From 2f21bf5cfda22a435aa325e0b065cbab92b492b5 Mon Sep 17 00:00:00 2001 From: Giordano Ricci Date: Thu, 5 Aug 2021 16:03:38 +0100 Subject: [PATCH] Chore: Reduce Elasticsearch data source plugin strict errors (#37399) --- .../BucketAggregationEditor.tsx | 7 +- .../DateHistogramSettingsEditor.tsx | 17 +- .../FiltersSettingsEditor/index.tsx | 9 +- .../FiltersSettingsEditor/state/actions.ts | 18 +- .../state/reducer.test.ts | 2 +- .../FiltersSettingsEditor/state/reducer.ts | 37 ++- .../FiltersSettingsEditor/state/types.ts | 22 -- .../SettingsEditor/TermsSettingsEditor.tsx | 22 +- .../SettingsEditor/index.tsx | 18 +- .../BucketAggregationsEditor/index.tsx | 3 +- .../BucketAggregationsEditor/state/actions.ts | 77 ++--- .../state/reducer.test.ts | 20 +- .../BucketAggregationsEditor/state/reducer.ts | 204 ++++++------- .../BucketAggregationsEditor/state/types.ts | 51 ---- .../BucketAggregationsEditor/utils.ts | 2 +- .../MetricAggregationsEditor/MetricEditor.tsx | 9 +- .../BucketScriptSettingsEditor/index.tsx | 10 +- .../state/actions.ts | 38 +-- .../state/reducer.test.ts | 4 +- .../state/reducer.ts | 81 ++--- .../BucketScriptSettingsEditor/state/types.ts | 34 --- .../MovingAverageSettingsEditor.tsx | 50 +++- .../SettingsEditor/SettingField.tsx | 5 +- .../TopMetricsSettingsEditor.tsx | 12 +- .../SettingsEditor/index.tsx | 18 +- .../MetricAggregationsEditor/index.tsx | 3 +- .../MetricAggregationsEditor/state/actions.ts | 115 ++----- .../state/reducer.test.ts | 18 +- .../MetricAggregationsEditor/state/reducer.ts | 281 +++++++++--------- .../MetricAggregationsEditor/state/types.ts | 89 ------ .../components/QueryEditor/state.ts | 77 ++--- .../hooks/useStatelessReducer.ts | 7 +- scripts/ci-check-strict.sh | 2 +- 33 files changed, 528 insertions(+), 834 deletions(-) delete mode 100644 public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/FiltersSettingsEditor/state/types.ts delete mode 100644 public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/state/types.ts delete mode 100644 public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/BucketScriptSettingsEditor/state/types.ts delete mode 100644 public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/state/types.ts diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/BucketAggregationEditor.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/BucketAggregationEditor.tsx index 439acd59e92..b1f069f5730 100644 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/BucketAggregationEditor.tsx +++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/BucketAggregationEditor.tsx @@ -7,7 +7,6 @@ import { segmentStyles } from '../styles'; import { BucketAggregation, BucketAggregationType, isBucketAggregationWithField } from './aggregations'; import { SettingsEditor } from './SettingsEditor'; import { changeBucketAggregationField, changeBucketAggregationType } from './state/actions'; -import { BucketAggregationAction } from './state/types'; import { bucketAggregationConfig } from './utils'; const bucketAggOptions: Array> = Object.entries(bucketAggregationConfig).map( @@ -27,7 +26,7 @@ interface QueryMetricEditorProps { } export const BucketAggregationEditor = ({ value }: QueryMetricEditorProps) => { - const dispatch = useDispatch(); + const dispatch = useDispatch(); const getFields = useFields(value.type); return ( @@ -36,7 +35,7 @@ export const BucketAggregationEditor = ({ value }: QueryMetricEditorProps) => { dispatch(changeBucketAggregationType(value.id, e.value!))} + onChange={(e) => dispatch(changeBucketAggregationType({ id: value.id, newType: e.value! }))} value={toOption(value)} /> @@ -44,7 +43,7 @@ export const BucketAggregationEditor = ({ value }: QueryMetricEditorProps) => { dispatch(changeBucketAggregationField(value.id, e.value))} + onChange={(e) => dispatch(changeBucketAggregationField({ id: value.id, newField: e.value }))} placeholder="Select Field" value={value.field} /> 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 901f3299b4d..f4eac46858f 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 @@ -46,7 +46,8 @@ interface Props { export const DateHistogramSettingsEditor = ({ bucketAgg }: Props) => { const dispatch = useDispatch(); - const handleIntervalChange = (v: string) => dispatch(changeBucketAggregationSetting(bucketAgg, 'interval', v)); + const handleIntervalChange = (newValue: string) => + dispatch(changeBucketAggregationSetting({ bucketAgg, settingName: 'interval', newValue })); return ( <> @@ -66,7 +67,11 @@ export const DateHistogramSettingsEditor = ({ bucketAgg }: Props) => { dispatch(changeBucketAggregationSetting(bucketAgg, 'min_doc_count', e.target.value!))} + onBlur={(e) => + dispatch( + changeBucketAggregationSetting({ bucketAgg, settingName: 'min_doc_count', newValue: e.target.value }) + ) + } defaultValue={ bucketAgg.settings?.min_doc_count || bucketAggregationConfig.date_histogram.defaultSettings?.min_doc_count } @@ -75,7 +80,9 @@ export const DateHistogramSettingsEditor = ({ bucketAgg }: Props) => { dispatch(changeBucketAggregationSetting(bucketAgg, 'trimEdges', e.target.value!))} + onBlur={(e) => + dispatch(changeBucketAggregationSetting({ bucketAgg, settingName: 'trimEdges', newValue: e.target.value })) + } defaultValue={ bucketAgg.settings?.trimEdges || bucketAggregationConfig.date_histogram.defaultSettings?.trimEdges } @@ -88,7 +95,9 @@ export const DateHistogramSettingsEditor = ({ bucketAgg }: Props) => { tooltip="Change the start value of each bucket by the specified positive (+) or negative offset (-) duration, such as 1h for an hour, or 1d for a day" > dispatch(changeBucketAggregationSetting(bucketAgg, 'offset', e.target.value!))} + onBlur={(e) => + dispatch(changeBucketAggregationSetting({ bucketAgg, settingName: 'offset', newValue: e.target.value })) + } defaultValue={bucketAgg.settings?.offset || bucketAggregationConfig.date_histogram.defaultSettings?.offset} /> diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/FiltersSettingsEditor/index.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/FiltersSettingsEditor/index.tsx index f8a84814d67..baa3d3ef692 100644 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/FiltersSettingsEditor/index.tsx +++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/FiltersSettingsEditor/index.tsx @@ -5,7 +5,6 @@ import { AddRemove } from '../../../../AddRemove'; import { useDispatch, useStatelessReducer } from '../../../../../hooks/useStatelessReducer'; import { Filters } from '../../aggregations'; import { changeBucketAggregationSetting } from '../../state/actions'; -import { BucketAggregationAction } from '../../state/types'; import { addFilter, changeFilter, removeFilter } from './state/actions'; import { reducer as filtersReducer } from './state/reducer'; @@ -14,10 +13,10 @@ interface Props { } export const FiltersSettingsEditor = ({ bucketAgg }: Props) => { - const upperStateDispatch = useDispatch>(); + const upperStateDispatch = useDispatch(); const dispatch = useStatelessReducer( - (newState) => upperStateDispatch(changeBucketAggregationSetting(bucketAgg, 'filters', newState)), + (newValue) => upperStateDispatch(changeBucketAggregationSetting({ bucketAgg, settingName: 'filters', newValue })), bucketAgg.settings?.filters, filtersReducer ); @@ -55,7 +54,7 @@ export const FiltersSettingsEditor = ({ bucketAgg }: Props) => { placeholder="Lucene Query" portalOrigin="elasticsearch" onBlur={() => {}} - onChange={(query) => dispatch(changeFilter(index, { ...filter, query }))} + onChange={(query) => dispatch(changeFilter({ index, filter: { ...filter, query } }))} query={filter.query} /> @@ -63,7 +62,7 @@ export const FiltersSettingsEditor = ({ bucketAgg }: Props) => { dispatch(changeFilter(index, { ...filter, label: e.target.value }))} + onBlur={(e) => dispatch(changeFilter({ index, filter: { ...filter, label: e.target.value } }))} defaultValue={filter.label} /> diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/FiltersSettingsEditor/state/actions.ts b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/FiltersSettingsEditor/state/actions.ts index 61da5fbc131..90f823e9149 100644 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/FiltersSettingsEditor/state/actions.ts +++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/FiltersSettingsEditor/state/actions.ts @@ -1,16 +1,6 @@ +import { createAction } from '@reduxjs/toolkit'; import { Filter } from '../../../aggregations'; -import { FilterAction, ADD_FILTER, REMOVE_FILTER, CHANGE_FILTER } from './types'; -export const addFilter = (): FilterAction => ({ - type: ADD_FILTER, -}); - -export const removeFilter = (index: number): FilterAction => ({ - type: REMOVE_FILTER, - payload: { index }, -}); - -export const changeFilter = (index: number, filter: Filter): FilterAction => ({ - type: CHANGE_FILTER, - payload: { index, filter }, -}); +export const addFilter = createAction('@bucketAggregations/filter/add'); +export const removeFilter = createAction('@bucketAggregations/filter/remove'); +export const changeFilter = createAction<{ index: number; filter: Filter }>('@bucketAggregations/filter/change'); diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/FiltersSettingsEditor/state/reducer.test.ts b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/FiltersSettingsEditor/state/reducer.test.ts index 4e63765bae1..ee947026028 100644 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/FiltersSettingsEditor/state/reducer.test.ts +++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/FiltersSettingsEditor/state/reducer.test.ts @@ -46,7 +46,7 @@ describe('Filters Bucket Aggregation Settings Reducer', () => { reducerTester() .givenReducer(reducer, [firstFilter, secondFilter]) - .whenActionIsDispatched(changeFilter(1, expectedSecondFilter)) + .whenActionIsDispatched(changeFilter({ index: 1, filter: expectedSecondFilter })) .thenStateShouldEqual([firstFilter, expectedSecondFilter]); }); }); diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/FiltersSettingsEditor/state/reducer.ts b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/FiltersSettingsEditor/state/reducer.ts index 5a4dcde2e40..dfe5c518c21 100644 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/FiltersSettingsEditor/state/reducer.ts +++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/FiltersSettingsEditor/state/reducer.ts @@ -1,21 +1,26 @@ +import { Action } from 'redux'; import { Filter } from '../../../aggregations'; import { defaultFilter } from '../utils'; -import { ADD_FILTER, CHANGE_FILTER, FilterAction, REMOVE_FILTER } from './types'; +import { addFilter, changeFilter, removeFilter } from './actions'; -export const reducer = (state: Filter[] = [], action: FilterAction) => { - switch (action.type) { - case ADD_FILTER: - return [...state, defaultFilter()]; - case REMOVE_FILTER: - return state.slice(0, action.payload.index).concat(state.slice(action.payload.index + 1)); - - case CHANGE_FILTER: - return state.map((filter, index) => { - if (index !== action.payload.index) { - return filter; - } - - return action.payload.filter; - }); +export const reducer = (state: Filter[] = [], action: Action) => { + if (addFilter.match(action)) { + return [...state, defaultFilter()]; } + + if (removeFilter.match(action)) { + return state.slice(0, action.payload).concat(state.slice(action.payload + 1)); + } + + if (changeFilter.match(action)) { + return state.map((filter, index) => { + if (index !== action.payload.index) { + return filter; + } + + return action.payload.filter; + }); + } + + return state; }; diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/FiltersSettingsEditor/state/types.ts b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/FiltersSettingsEditor/state/types.ts deleted file mode 100644 index b9f5ff3ebb2..00000000000 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/FiltersSettingsEditor/state/types.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Action } from '../../../../../../hooks/useStatelessReducer'; -import { Filter } from '../../../aggregations'; - -export const ADD_FILTER = '@bucketAggregations/filter/add'; -export const REMOVE_FILTER = '@bucketAggregations/filter/remove'; -export const CHANGE_FILTER = '@bucketAggregations/filter/change'; - -export type AddFilterAction = Action; - -export interface RemoveFilterAction extends Action { - payload: { - index: number; - }; -} - -export interface ChangeFilterAction extends Action { - payload: { - index: number; - filter: Filter; - }; -} -export type FilterAction = AddFilterAction | RemoveFilterAction | ChangeFilterAction; diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/TermsSettingsEditor.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/TermsSettingsEditor.tsx index 2db26891edb..dfc9b5fd1db 100644 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/TermsSettingsEditor.tsx +++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/TermsSettingsEditor.tsx @@ -23,7 +23,9 @@ export const TermsSettingsEditor = ({ bucketAgg }: Props) => { dispatch(changeBucketAggregationSetting(bucketAgg, 'min_doc_count', e.target.value!))} + onBlur={(e) => + dispatch( + changeBucketAggregationSetting({ bucketAgg, settingName: 'min_doc_count', newValue: e.target.value }) + ) + } defaultValue={ bucketAgg.settings?.min_doc_count || bucketAggregationConfig.terms.defaultSettings?.min_doc_count } @@ -55,7 +61,9 @@ export const TermsSettingsEditor = ({ bucketAgg }: Props) => { dispatch(changeBucketAggregationSetting(bucketAgg, 'missing', e.target.value!))} + onBlur={(e) => + dispatch(changeBucketAggregationSetting({ bucketAgg, settingName: 'missing', newValue: e.target.value })) + } defaultValue={bucketAgg.settings?.missing || bucketAggregationConfig.terms.defaultSettings?.missing} /> diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/index.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/index.tsx index 6d9c11101cd..1ee6f5399ed 100644 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/index.tsx +++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/index.tsx @@ -32,7 +32,11 @@ export const SettingsEditor = ({ bucketAgg }: Props) => { {bucketAgg.type === 'geohash_grid' && ( dispatch(changeBucketAggregationSetting(bucketAgg, 'precision', e.target.value!))} + onBlur={(e) => + dispatch( + changeBucketAggregationSetting({ bucketAgg, settingName: 'precision', newValue: e.target.value }) + ) + } defaultValue={ bucketAgg.settings?.precision || bucketAggregationConfig[bucketAgg.type].defaultSettings?.precision } @@ -44,7 +48,11 @@ export const SettingsEditor = ({ bucketAgg }: Props) => { <> dispatch(changeBucketAggregationSetting(bucketAgg, 'interval', e.target.value!))} + onBlur={(e) => + dispatch( + changeBucketAggregationSetting({ bucketAgg, settingName: 'interval', newValue: e.target.value }) + ) + } defaultValue={ bucketAgg.settings?.interval || bucketAggregationConfig[bucketAgg.type].defaultSettings?.interval } @@ -53,7 +61,11 @@ export const SettingsEditor = ({ bucketAgg }: Props) => { dispatch(changeBucketAggregationSetting(bucketAgg, 'min_doc_count', e.target.value!))} + onBlur={(e) => + dispatch( + changeBucketAggregationSetting({ bucketAgg, settingName: 'min_doc_count', newValue: e.target.value }) + ) + } defaultValue={ bucketAgg.settings?.min_doc_count || bucketAggregationConfig[bucketAgg.type].defaultSettings?.min_doc_count diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/index.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/index.tsx index 7370caeb5e1..428015f7071 100644 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/index.tsx +++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/index.tsx @@ -2,7 +2,6 @@ import React from 'react'; import { BucketAggregationEditor } from './BucketAggregationEditor'; import { useDispatch } from '../../../hooks/useStatelessReducer'; import { addBucketAggregation, removeBucketAggregation } from './state/actions'; -import { BucketAggregationAction } from './state/types'; import { BucketAggregation } from './aggregations'; import { useQuery } from '../ElasticsearchQueryContext'; import { QueryEditorRow } from '../QueryEditorRow'; @@ -13,7 +12,7 @@ interface Props { } export const BucketAggregationsEditor = ({ nextId }: Props) => { - const dispatch = useDispatch(); + const dispatch = useDispatch(); const { bucketAggs } = useQuery(); const totalBucketAggs = bucketAggs?.length || 0; diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/state/actions.ts b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/state/actions.ts index 31203eea890..124577ba350 100644 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/state/actions.ts +++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/state/actions.ts @@ -1,61 +1,18 @@ -import { SettingKeyOf } from '../../../types'; -import { BucketAggregation, BucketAggregationWithField } from '../aggregations'; -import { - ADD_BUCKET_AGG, - BucketAggregationAction, - REMOVE_BUCKET_AGG, - CHANGE_BUCKET_AGG_TYPE, - CHANGE_BUCKET_AGG_FIELD, - CHANGE_BUCKET_AGG_SETTING, - ChangeBucketAggregationSettingAction, -} from './types'; +import { createAction } from '@reduxjs/toolkit'; +import { BucketAggregation, BucketAggregationType, BucketAggregationWithField } from '../aggregations'; -export const addBucketAggregation = (id: string): BucketAggregationAction => ({ - type: ADD_BUCKET_AGG, - payload: { - id, - }, -}); - -export const removeBucketAggregation = (id: BucketAggregation['id']): BucketAggregationAction => ({ - type: REMOVE_BUCKET_AGG, - payload: { - id, - }, -}); - -export const changeBucketAggregationType = ( - id: BucketAggregation['id'], - newType: BucketAggregation['type'] -): BucketAggregationAction => ({ - type: CHANGE_BUCKET_AGG_TYPE, - payload: { - id, - newType, - }, -}); - -export const changeBucketAggregationField = ( - id: BucketAggregationWithField['id'], - newField: BucketAggregationWithField['field'] -): BucketAggregationAction => ({ - type: CHANGE_BUCKET_AGG_FIELD, - payload: { - id, - newField, - }, -}); - -export const changeBucketAggregationSetting = >( - bucketAgg: T, - settingName: K, - // This could be inferred from T, but it's causing some troubles - newValue: string | string[] | any -): ChangeBucketAggregationSettingAction => ({ - type: CHANGE_BUCKET_AGG_SETTING, - payload: { - bucketAgg, - settingName, - newValue, - }, -}); +export const addBucketAggregation = createAction('@bucketAggs/add'); +export const removeBucketAggregation = createAction('@bucketAggs/remove'); +export const changeBucketAggregationType = createAction<{ + id: BucketAggregation['id']; + newType: BucketAggregationType; +}>('@bucketAggs/change_type'); +export const changeBucketAggregationField = createAction<{ + id: BucketAggregation['id']; + newField: BucketAggregationWithField['field']; +}>('@bucketAggs/change_field'); +export const changeBucketAggregationSetting = createAction<{ + bucketAgg: BucketAggregation; + settingName: string; + newValue: any; +}>('@bucketAggs/change_setting'); 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 aea19cff4dc..b97ef8d913d 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 @@ -71,7 +71,9 @@ describe('Bucket Aggregations Reducer', () => { reducerTester() .givenReducer(createReducer('@timestamp'), [firstAggregation, secondAggregation]) - .whenActionIsDispatched(changeBucketAggregationType(secondAggregation.id, expectedSecondAggregation.type)) + .whenActionIsDispatched( + changeBucketAggregationType({ id: secondAggregation.id, newType: expectedSecondAggregation.type }) + ) .thenStateShouldEqual([firstAggregation, expectedSecondAggregation]); }); @@ -92,7 +94,9 @@ describe('Bucket Aggregations Reducer', () => { reducerTester() .givenReducer(createReducer('@timestamp'), [firstAggregation, secondAggregation]) - .whenActionIsDispatched(changeBucketAggregationField(secondAggregation.id, expectedSecondAggregation.field)) + .whenActionIsDispatched( + changeBucketAggregationField({ id: secondAggregation.id, newField: expectedSecondAggregation.field }) + ) .thenStateShouldEqual([firstAggregation, expectedSecondAggregation]); }); @@ -108,13 +112,13 @@ describe('Bucket Aggregations Reducer', () => { reducerTester() .givenReducer(createReducer('@timestamp'), initialState) // If the new metric aggregation is `isSingleMetric` we should remove all bucket aggregations. - .whenActionIsDispatched(changeMetricType('Some id', 'raw_data')) + .whenActionIsDispatched(changeMetricType({ id: 'Some id', type: 'raw_data' })) .thenStatePredicateShouldEqual((newState) => newState?.length === 0) // Switching back to another aggregation that is NOT `isSingleMetric` should bring back a bucket aggregation - .whenActionIsDispatched(changeMetricType('Some id', 'max')) + .whenActionIsDispatched(changeMetricType({ id: 'Some id', type: 'max' })) .thenStatePredicateShouldEqual((newState) => newState?.length === 1) // When none of the above is true state shouldn't change. - .whenActionIsDispatched(changeMetricType('Some id', 'min')) + .whenActionIsDispatched(changeMetricType({ id: 'Some id', type: 'min' })) .thenStatePredicateShouldEqual((newState) => newState?.length === 1); }); }); @@ -139,7 +143,11 @@ describe('Bucket Aggregations Reducer', () => { reducerTester() .givenReducer(createReducer('@timestamp'), [firstAggregation, secondAggregation]) .whenActionIsDispatched( - changeBucketAggregationSetting(firstAggregation, 'min_doc_count', expectedSettings.min_doc_count!) + changeBucketAggregationSetting({ + bucketAgg: firstAggregation, + settingName: 'min_doc_count', + newValue: expectedSettings.min_doc_count!, + }) ) .thenStateShouldEqual([{ ...firstAggregation, settings: expectedSettings }, secondAggregation]); }); 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 460f28f1918..78ae8ef26e1 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 @@ -1,114 +1,118 @@ import { defaultBucketAgg } from '../../../../query_def'; import { ElasticsearchQuery } from '../../../../types'; -import { ChangeMetricTypeAction, CHANGE_METRIC_TYPE } from '../../MetricAggregationsEditor/state/types'; import { metricAggregationConfig } from '../../MetricAggregationsEditor/utils'; import { BucketAggregation, Terms } from '../aggregations'; -import { INIT, InitAction } from '../../state'; -import { - ADD_BUCKET_AGG, - REMOVE_BUCKET_AGG, - CHANGE_BUCKET_AGG_TYPE, - CHANGE_BUCKET_AGG_FIELD, - CHANGE_BUCKET_AGG_SETTING, - BucketAggregationAction, -} from './types'; +import { initQuery } from '../../state'; import { bucketAggregationConfig } from '../utils'; import { removeEmpty } from '../../../../utils'; +import { Action } from '@reduxjs/toolkit'; +import { + addBucketAggregation, + changeBucketAggregationField, + changeBucketAggregationSetting, + changeBucketAggregationType, + removeBucketAggregation, +} from './actions'; +import { changeMetricType } from '../../MetricAggregationsEditor/state/actions'; export const createReducer = (defaultTimeField: string) => ( state: ElasticsearchQuery['bucketAggs'], - action: BucketAggregationAction | ChangeMetricTypeAction | InitAction + action: Action ): ElasticsearchQuery['bucketAggs'] => { - switch (action.type) { - case ADD_BUCKET_AGG: - const newAgg: Terms = { - id: action.payload.id, - type: 'terms', - settings: bucketAggregationConfig['terms'].defaultSettings, - }; + if (addBucketAggregation.match(action)) { + const newAgg: Terms = { + id: action.payload, + type: 'terms', + settings: bucketAggregationConfig['terms'].defaultSettings, + }; - // If the last bucket aggregation is a `date_histogram` we add the new one before it. - const lastAgg = state![state!.length - 1]; - if (lastAgg?.type === 'date_histogram') { - return [...state!.slice(0, state!.length - 1), newAgg, lastAgg]; - } + // If the last bucket aggregation is a `date_histogram` we add the new one before it. + const lastAgg = state![state!.length - 1]; + if (lastAgg?.type === 'date_histogram') { + return [...state!.slice(0, state!.length - 1), newAgg, lastAgg]; + } - return [...state!, newAgg]; - - case REMOVE_BUCKET_AGG: - return state!.filter((bucketAgg) => bucketAgg.id !== action.payload.id); - - case CHANGE_BUCKET_AGG_TYPE: - return state!.map((bucketAgg) => { - if (bucketAgg.id !== action.payload.id) { - return bucketAgg; - } - - /* - TODO: The previous version of the query editor was keeping some of the old bucket aggregation's configurations - in the new selected one (such as field or some settings). - It the future would be nice to have the same behavior but it's hard without a proper definition, - as Elasticsearch will error sometimes if some settings are not compatible. - */ - return { - id: bucketAgg.id, - type: action.payload.newType, - settings: bucketAggregationConfig[action.payload.newType].defaultSettings, - } as BucketAggregation; - }); - - case CHANGE_BUCKET_AGG_FIELD: - return state!.map((bucketAgg) => { - if (bucketAgg.id !== action.payload.id) { - return bucketAgg; - } - - return { - ...bucketAgg, - field: action.payload.newField, - }; - }); - - case CHANGE_METRIC_TYPE: - // If we are switching to a metric which requires the absence of bucket aggregations - // we remove all of them. - if (metricAggregationConfig[action.payload.type].isSingleMetric) { - return []; - } else if (state!.length === 0) { - // Else, if there are no bucket aggregations we restore a default one. - // This happens when switching from a metric that requires the absence of bucket aggregations to - // one that requires it. - return [{ ...defaultBucketAgg('2'), field: defaultTimeField }]; - } - return state; - - case CHANGE_BUCKET_AGG_SETTING: - return state!.map((bucketAgg) => { - if (bucketAgg.id !== action.payload.bucketAgg.id) { - return bucketAgg; - } - - const newSettings = removeEmpty({ - ...bucketAgg.settings, - [action.payload.settingName]: action.payload.newValue, - }); - - return { - ...bucketAgg, - settings: { - ...newSettings, - }, - }; - }); - - case INIT: - if (state?.length || 0 > 0) { - return state; - } - - return [{ ...defaultBucketAgg('2'), field: defaultTimeField }]; - - default: - return state; + return [...state!, newAgg]; } + + if (removeBucketAggregation.match(action)) { + return state!.filter((bucketAgg) => bucketAgg.id !== action.payload); + } + + if (changeBucketAggregationType.match(action)) { + return state!.map((bucketAgg) => { + if (bucketAgg.id !== action.payload.id) { + return bucketAgg; + } + + /* + TODO: The previous version of the query editor was keeping some of the old bucket aggregation's configurations + in the new selected one (such as field or some settings). + It the future would be nice to have the same behavior but it's hard without a proper definition, + as Elasticsearch will error sometimes if some settings are not compatible. + */ + return { + id: bucketAgg.id, + type: action.payload.newType, + settings: bucketAggregationConfig[action.payload.newType].defaultSettings, + } as BucketAggregation; + }); + } + + if (changeBucketAggregationField.match(action)) { + return state!.map((bucketAgg) => { + if (bucketAgg.id !== action.payload.id) { + return bucketAgg; + } + + return { + ...bucketAgg, + field: action.payload.newField, + }; + }); + } + + if (changeMetricType.match(action)) { + // If we are switching to a metric which requires the absence of bucket aggregations + // we remove all of them. + if (metricAggregationConfig[action.payload.type].isSingleMetric) { + return []; + } else if (state!.length === 0) { + // Else, if there are no bucket aggregations we restore a default one. + // This happens when switching from a metric that requires the absence of bucket aggregations to + // one that requires it. + return [{ ...defaultBucketAgg('2'), field: defaultTimeField }]; + } + return state; + } + + if (changeBucketAggregationSetting.match(action)) { + return state!.map((bucketAgg) => { + if (bucketAgg.id !== action.payload.bucketAgg.id) { + return bucketAgg; + } + + const newSettings = removeEmpty({ + ...bucketAgg.settings, + [action.payload.settingName]: action.payload.newValue, + }); + + return { + ...bucketAgg, + settings: { + ...newSettings, + }, + }; + }); + } + + if (initQuery.match(action)) { + if (state?.length || 0 > 0) { + return state; + } + + return [{ ...defaultBucketAgg('2'), field: defaultTimeField }]; + } + + return state; }; diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/state/types.ts b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/state/types.ts deleted file mode 100644 index a0b0f6e9510..00000000000 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/state/types.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Action } from '../../../../hooks/useStatelessReducer'; -import { SettingKeyOf } from '../../../types'; -import { BucketAggregation, BucketAggregationWithField } from '../aggregations'; - -export const ADD_BUCKET_AGG = '@bucketAggs/add'; -export const REMOVE_BUCKET_AGG = '@bucketAggs/remove'; -export const CHANGE_BUCKET_AGG_TYPE = '@bucketAggs/change_type'; -export const CHANGE_BUCKET_AGG_FIELD = '@bucketAggs/change_field'; -export const CHANGE_BUCKET_AGG_SETTING = '@bucketAggs/change_setting'; - -export interface AddBucketAggregationAction extends Action { - payload: { - id: BucketAggregation['id']; - }; -} - -export interface RemoveBucketAggregationAction extends Action { - payload: { - id: BucketAggregation['id']; - }; -} - -export interface ChangeBucketAggregationTypeAction extends Action { - payload: { - id: BucketAggregation['id']; - newType: BucketAggregation['type']; - }; -} - -export interface ChangeBucketAggregationFieldAction extends Action { - payload: { - id: BucketAggregation['id']; - newField: BucketAggregationWithField['field']; - }; -} - -export interface ChangeBucketAggregationSettingAction - extends Action { - payload: { - bucketAgg: T; - settingName: SettingKeyOf; - newValue: unknown; - }; -} - -export type BucketAggregationAction = - | AddBucketAggregationAction - | RemoveBucketAggregationAction - | ChangeBucketAggregationTypeAction - | ChangeBucketAggregationFieldAction - | ChangeBucketAggregationSettingAction; diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/utils.ts b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/utils.ts index a725c59e0ec..86665d51838 100644 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/utils.ts +++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/utils.ts @@ -79,7 +79,7 @@ export const orderByOptions = [ /** * This returns the valid options for each of the enabled extended stat */ -function createOrderByOptionsForExtendedStats(metric: ExtendedStats): OrderByOption[] { +function createOrderByOptionsForExtendedStats(metric: ExtendedStats): SelectableValue { if (!metric.meta) { return []; } diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/MetricEditor.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/MetricEditor.tsx index edda9223a62..2c4d5619b68 100644 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/MetricEditor.tsx +++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/MetricEditor.tsx @@ -6,7 +6,6 @@ import { useDatasource, useQuery } from '../ElasticsearchQueryContext'; import { useDispatch } from '../../../hooks/useStatelessReducer'; import { getStyles } from './styles'; import { SettingsEditor } from './SettingsEditor'; -import { MetricAggregationAction } from './state/types'; import { metricAggregationConfig } from './utils'; import { changeMetricField, changeMetricType } from './state/actions'; import { MetricPicker } from '../../MetricPicker'; @@ -65,7 +64,7 @@ export const MetricEditor = ({ value }: Props) => { const styles = getStyles(useTheme2(), !!value.hide); const datasource = useDatasource(); const query = useQuery(); - const dispatch = useDispatch(); + const dispatch = useDispatch(); const getFields = useFields(value.type); const loadOptions = useCallback(async () => { @@ -90,7 +89,7 @@ export const MetricEditor = ({ value }: Props) => { dispatch(changeMetricType(value.id, e.value!))} + onChange={(e) => dispatch(changeMetricType({ id: value.id, type: e.value! }))} value={toOption(value)} /> @@ -98,7 +97,7 @@ export const MetricEditor = ({ value }: Props) => { dispatch(changeMetricField(value.id, e.value!))} + onChange={(e) => dispatch(changeMetricField({ id: value.id, field: e.value! }))} placeholder="Select Field" value={value.field} /> @@ -107,7 +106,7 @@ export const MetricEditor = ({ value }: Props) => { {isPipelineAggregation(value) && !isPipelineAggregationWithMultipleBucketPaths(value) && ( dispatch(changeMetricField(value.id, e.value?.id!))} + onChange={(e) => dispatch(changeMetricField({ id: value.id, field: e.value?.id! }))} options={previousMetrics} value={value.field} /> diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/BucketScriptSettingsEditor/index.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/BucketScriptSettingsEditor/index.tsx index ef93c08c6fd..78a9715a7c5 100644 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/BucketScriptSettingsEditor/index.tsx +++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/BucketScriptSettingsEditor/index.tsx @@ -1,6 +1,5 @@ import React, { Fragment, useEffect } from 'react'; import { Input, InlineLabel } from '@grafana/ui'; -import { MetricAggregationAction } from '../../state/types'; import { changeMetricAttribute } from '../../state/actions'; import { css } from '@emotion/css'; import { AddRemove } from '../../../../AddRemove'; @@ -23,10 +22,11 @@ interface Props { } export const BucketScriptSettingsEditor = ({ value, previousMetrics }: Props) => { - const upperStateDispatch = useDispatch>(); + const upperStateDispatch = useDispatch(); const dispatch = useStatelessReducer( - (newState) => upperStateDispatch(changeMetricAttribute(value, 'pipelineVariables', newState)), + (newValue) => + upperStateDispatch(changeMetricAttribute({ metric: value, attribute: 'pipelineVariables', newValue })), value.pipelineVariables, reducer ); @@ -74,10 +74,10 @@ export const BucketScriptSettingsEditor = ({ value, previousMetrics }: Props) => dispatch(renamePipelineVariable(e.target.value, index))} + onBlur={(e) => dispatch(renamePipelineVariable({ newName: e.target.value, index }))} /> dispatch(changePipelineVariableMetric(e.value!.id, index))} + onChange={(e) => dispatch(changePipelineVariableMetric({ newMetric: e.value!.id, index }))} options={previousMetrics} value={pipelineVar.pipelineAgg} /> diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/BucketScriptSettingsEditor/state/actions.ts b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/BucketScriptSettingsEditor/state/actions.ts index 67d32db96ca..368362d172e 100644 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/BucketScriptSettingsEditor/state/actions.ts +++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/BucketScriptSettingsEditor/state/actions.ts @@ -1,34 +1,10 @@ -import { - ADD_PIPELINE_VARIABLE, - REMOVE_PIPELINE_VARIABLE, - PipelineVariablesAction, - RENAME_PIPELINE_VARIABLE, - CHANGE_PIPELINE_VARIABLE_METRIC, -} from './types'; +import { createAction } from '@reduxjs/toolkit'; -export const addPipelineVariable = (): PipelineVariablesAction => ({ - type: ADD_PIPELINE_VARIABLE, -}); +export const addPipelineVariable = createAction('@pipelineVariables/add'); +export const removePipelineVariable = createAction('@pipelineVariables/remove'); -export const removePipelineVariable = (index: number): PipelineVariablesAction => ({ - type: REMOVE_PIPELINE_VARIABLE, - payload: { - index, - }, -}); +export const renamePipelineVariable = createAction<{ index: number; newName: string }>('@pipelineVariables/rename'); -export const renamePipelineVariable = (newName: string, index: number): PipelineVariablesAction => ({ - type: RENAME_PIPELINE_VARIABLE, - payload: { - index, - newName, - }, -}); - -export const changePipelineVariableMetric = (newMetric: string, index: number): PipelineVariablesAction => ({ - type: CHANGE_PIPELINE_VARIABLE_METRIC, - payload: { - index, - newMetric, - }, -}); +export const changePipelineVariableMetric = createAction<{ index: number; newMetric: string }>( + '@pipelineVariables/change_metric' +); diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/BucketScriptSettingsEditor/state/reducer.test.ts b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/BucketScriptSettingsEditor/state/reducer.test.ts index a28828b2fa4..df26707ce18 100644 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/BucketScriptSettingsEditor/state/reducer.test.ts +++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/BucketScriptSettingsEditor/state/reducer.test.ts @@ -72,7 +72,7 @@ describe('BucketScript Settings Reducer', () => { reducerTester() .givenReducer(reducer, [firstVar, secondVar]) - .whenActionIsDispatched(renamePipelineVariable(expectedSecondVar.name, 1)) + .whenActionIsDispatched(renamePipelineVariable({ newName: expectedSecondVar.name, index: 1 })) .thenStateShouldEqual([firstVar, expectedSecondVar]); }); @@ -94,7 +94,7 @@ describe('BucketScript Settings Reducer', () => { reducerTester() .givenReducer(reducer, [firstVar, secondVar]) - .whenActionIsDispatched(changePipelineVariableMetric(expectedSecondVar.pipelineAgg, 1)) + .whenActionIsDispatched(changePipelineVariableMetric({ newMetric: expectedSecondVar.pipelineAgg, index: 1 })) .thenStateShouldEqual([firstVar, expectedSecondVar]); }); diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/BucketScriptSettingsEditor/state/reducer.ts b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/BucketScriptSettingsEditor/state/reducer.ts index 6b8b5b7c1a4..563189fe426 100644 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/BucketScriptSettingsEditor/state/reducer.ts +++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/BucketScriptSettingsEditor/state/reducer.ts @@ -1,46 +1,47 @@ +import { Action } from '@reduxjs/toolkit'; import { PipelineVariable } from '../../../aggregations'; import { defaultPipelineVariable, generatePipelineVariableName } from '../utils'; import { - PipelineVariablesAction, - REMOVE_PIPELINE_VARIABLE, - ADD_PIPELINE_VARIABLE, - RENAME_PIPELINE_VARIABLE, - CHANGE_PIPELINE_VARIABLE_METRIC, -} from './types'; + addPipelineVariable, + changePipelineVariableMetric, + removePipelineVariable, + renamePipelineVariable, +} from './actions'; -export const reducer = (state: PipelineVariable[] = [], action: PipelineVariablesAction) => { - switch (action.type) { - case ADD_PIPELINE_VARIABLE: - return [...state, defaultPipelineVariable(generatePipelineVariableName(state))]; - - case REMOVE_PIPELINE_VARIABLE: - return state.slice(0, action.payload.index).concat(state.slice(action.payload.index + 1)); - - case RENAME_PIPELINE_VARIABLE: - return state.map((pipelineVariable, index) => { - if (index !== action.payload.index) { - return pipelineVariable; - } - - return { - ...pipelineVariable, - name: action.payload.newName, - }; - }); - - case CHANGE_PIPELINE_VARIABLE_METRIC: - return state.map((pipelineVariable, index) => { - if (index !== action.payload.index) { - return pipelineVariable; - } - - return { - ...pipelineVariable, - pipelineAgg: action.payload.newMetric, - }; - }); - - default: - return state; +export const reducer = (state: PipelineVariable[] = [], action: Action) => { + if (addPipelineVariable.match(action)) { + return [...state, defaultPipelineVariable(generatePipelineVariableName(state))]; } + + if (removePipelineVariable.match(action)) { + return state.slice(0, action.payload).concat(state.slice(action.payload + 1)); + } + + if (renamePipelineVariable.match(action)) { + return state.map((pipelineVariable, index) => { + if (index !== action.payload.index) { + return pipelineVariable; + } + + return { + ...pipelineVariable, + name: action.payload.newName, + }; + }); + } + + if (changePipelineVariableMetric.match(action)) { + return state.map((pipelineVariable, index) => { + if (index !== action.payload.index) { + return pipelineVariable; + } + + return { + ...pipelineVariable, + pipelineAgg: action.payload.newMetric, + }; + }); + } + + return state; }; diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/BucketScriptSettingsEditor/state/types.ts b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/BucketScriptSettingsEditor/state/types.ts deleted file mode 100644 index 7807a550b30..00000000000 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/BucketScriptSettingsEditor/state/types.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { Action } from '../../../../../../hooks/useStatelessReducer'; - -export const ADD_PIPELINE_VARIABLE = '@pipelineVariables/add'; -export const REMOVE_PIPELINE_VARIABLE = '@pipelineVariables/remove'; -export const RENAME_PIPELINE_VARIABLE = '@pipelineVariables/rename'; -export const CHANGE_PIPELINE_VARIABLE_METRIC = '@pipelineVariables/change_metric'; - -export type AddPipelineVariableAction = Action; - -export interface RemovePipelineVariableAction extends Action { - payload: { - index: number; - }; -} - -export interface RenamePipelineVariableAction extends Action { - payload: { - index: number; - newName: string; - }; -} - -export interface ChangePipelineVariableMetricAction extends Action { - payload: { - index: number; - newMetric: string; - }; -} - -export type PipelineVariablesAction = - | AddPipelineVariableAction - | RemovePipelineVariableAction - | RenamePipelineVariableAction - | ChangePipelineVariableMetricAction; diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/MovingAverageSettingsEditor.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/MovingAverageSettingsEditor.tsx index 68a9251d475..d47bf7b837e 100644 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/MovingAverageSettingsEditor.tsx +++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/MovingAverageSettingsEditor.tsx @@ -21,7 +21,7 @@ export const MovingAverageSettingsEditor = ({ metric }: Props) => { dispatch( - changeMetricSetting(metric, 'settings', { - ...metric.settings?.settings, - alpha: e.target.value, + changeMetricSetting({ + metric, + settingName: 'settings', + newValue: { + ...metric.settings?.settings, + alpha: e.target.value, + }, }) ) } @@ -52,9 +56,13 @@ export const MovingAverageSettingsEditor = ({ metric }: Props) => { dispatch( - changeMetricSetting(metric, 'settings', { - ...metric.settings?.settings, - beta: e.target.value, + changeMetricSetting({ + metric, + settingName: 'settings', + newValue: { + ...metric.settings?.settings, + beta: e.target.value, + }, }) ) } @@ -69,9 +77,13 @@ export const MovingAverageSettingsEditor = ({ metric }: Props) => { dispatch( - changeMetricSetting(metric, 'settings', { - ...metric.settings?.settings, - gamma: e.target.value, + changeMetricSetting({ + metric, + settingName: 'settings', + newValue: { + ...metric.settings?.settings, + gamma: e.target.value, + }, }) ) } @@ -82,9 +94,13 @@ export const MovingAverageSettingsEditor = ({ metric }: Props) => { dispatch( - changeMetricSetting(metric, 'settings', { - ...metric.settings?.settings, - period: e.target.value!, + changeMetricSetting({ + metric, + settingName: 'settings', + newValue: { + ...metric.settings?.settings, + period: e.target.value!, + }, }) ) } @@ -96,7 +112,11 @@ export const MovingAverageSettingsEditor = ({ metric }: Props) => { ) => dispatch( - changeMetricSetting(metric, 'settings', { ...metric.settings?.settings, pad: e.target.checked }) + changeMetricSetting({ + metric, + settingName: 'settings', + newValue: { ...metric.settings?.settings, pad: e.target.checked }, + }) ) } checked={!!metric.settings?.settings?.pad} @@ -109,7 +129,7 @@ export const MovingAverageSettingsEditor = ({ metric }: Props) => { ) => - dispatch(changeMetricSetting(metric, 'minimize', e.target.checked)) + dispatch(changeMetricSetting({ metric, settingName: 'minimize', newValue: e.target.checked })) } checked={!!metric.settings?.minimize} /> diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/SettingField.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/SettingField.tsx index 01a9370ccaa..e25ff580464 100644 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/SettingField.tsx +++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/SettingField.tsx @@ -2,7 +2,6 @@ import React, { ComponentProps, useState } from 'react'; import { InlineField, Input } from '@grafana/ui'; import { useDispatch } from '../../../../hooks/useStatelessReducer'; import { changeMetricSetting } from '../state/actions'; -import { ChangeMetricSettingAction } from '../state/types'; import { SettingKeyOf } from '../../../types'; import { MetricAggregationWithInlineScript, MetricAggregationWithSettings } from '../aggregations'; import { uniqueId } from 'lodash'; @@ -23,7 +22,7 @@ export function SettingField) { - const dispatch = useDispatch>(); + const dispatch = useDispatch(); const [id] = useState(uniqueId(`es-field-id-`)); const settings = metric.settings; @@ -38,7 +37,7 @@ export function SettingField dispatch(changeMetricSetting(metric, settingName, e.target.value as any))} + onBlur={(e) => dispatch(changeMetricSetting({ metric, settingName, newValue: e.target.value }))} defaultValue={defaultValue} /> diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/TopMetricsSettingsEditor.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/TopMetricsSettingsEditor.tsx index 9b4db4d857d..f8f5c5ba63d 100644 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/TopMetricsSettingsEditor.tsx +++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/TopMetricsSettingsEditor.tsx @@ -26,11 +26,11 @@ export const TopMetricsSettingsEditor: FunctionComponent = ({ metric }) = menuShouldPortal onChange={(e) => dispatch( - changeMetricSetting( + changeMetricSetting({ metric, - 'metrics', - e.map((v) => v.value!) - ) + settingName: 'metrics', + newValue: e.map((v) => v.value!), + }) ) } loadOptions={getMetricsOptions} @@ -42,7 +42,7 @@ export const TopMetricsSettingsEditor: FunctionComponent = ({ metric }) = dispatch(changeMetricSetting(metric, 'size', e.target.value))} + onBlur={(e) => dispatch(changeMetricSetting({ metric, settingName: 'size', newValue: e.target.value }))} defaultValue={metric.settings?.size ?? metricAggregationConfig['raw_data'].defaults.settings?.size} /> @@ -96,7 +96,7 @@ export const SettingsEditor = ({ metric, previousMetrics }: Props) => { dispatch(changeMetricMeta(metric, stat.value, checked))} + onChange={(newValue) => dispatch(changeMetricMeta({ metric, meta: stat.value, newValue }))} value={ metric.meta?.[stat.value] !== undefined ? !!metric.meta?.[stat.value] @@ -112,7 +112,15 @@ export const SettingsEditor = ({ metric, previousMetrics }: Props) => { {metric.type === 'percentiles' && ( dispatch(changeMetricSetting(metric, 'percents', e.target.value.split(',').filter(Boolean)))} + onBlur={(e) => + dispatch( + changeMetricSetting({ + metric, + settingName: 'percents', + newValue: e.target.value.split(',').filter(Boolean), + }) + ) + } defaultValue={ metric.settings?.percents || metricAggregationConfig['percentiles'].defaults.settings?.percents } @@ -127,7 +135,7 @@ export const SettingsEditor = ({ metric, previousMetrics }: Props) => { dispatch(changeMetricSetting(metric, 'mode', e.value))} + onChange={(e) => dispatch(changeMetricSetting({ metric, settingName: 'mode', newValue: e.value }))} options={rateAggModeOptions} value={metric.settings?.unit} /> diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/index.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/index.tsx index 2471f534537..f00699af7f5 100644 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/index.tsx +++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/index.tsx @@ -1,7 +1,6 @@ import React from 'react'; import { MetricEditor } from './MetricEditor'; import { useDispatch } from '../../../hooks/useStatelessReducer'; -import { MetricAggregationAction } from './state/types'; import { metricAggregationConfig } from './utils'; import { addMetric, removeMetric, toggleMetricVisibility } from './state/actions'; import { MetricAggregation } from './aggregations'; @@ -14,7 +13,7 @@ interface Props { } export const MetricAggregationsEditor = ({ nextId }: Props) => { - const dispatch = useDispatch(); + const dispatch = useDispatch(); const { metrics } = useQuery(); const totalMetrics = metrics?.length || 0; diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/state/actions.ts b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/state/actions.ts index 63a09ec6a09..fba44d42f4e 100644 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/state/actions.ts +++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/state/actions.ts @@ -1,96 +1,23 @@ -import { SettingKeyOf } from '../../../types'; +import { createAction } from '@reduxjs/toolkit'; import { MetricAggregation, MetricAggregationWithMeta, MetricAggregationWithSettings } from '../aggregations'; -import { - ADD_METRIC, - CHANGE_METRIC_FIELD, - CHANGE_METRIC_TYPE, - REMOVE_METRIC, - TOGGLE_METRIC_VISIBILITY, - CHANGE_METRIC_SETTING, - CHANGE_METRIC_META, - CHANGE_METRIC_ATTRIBUTE, - MetricAggregationAction, - ChangeMetricAttributeAction, - ChangeMetricSettingAction, - ChangeMetricMetaAction, -} from './types'; -export const addMetric = (id: MetricAggregation['id']): MetricAggregationAction => ({ - type: ADD_METRIC, - payload: { - id, - }, -}); - -export const removeMetric = (id: MetricAggregation['id']): MetricAggregationAction => ({ - type: REMOVE_METRIC, - payload: { - id, - }, -}); - -export const changeMetricType = ( - id: MetricAggregation['id'], - type: MetricAggregation['type'] -): MetricAggregationAction => ({ - type: CHANGE_METRIC_TYPE, - payload: { - id, - type, - }, -}); - -export const changeMetricField = (id: MetricAggregation['id'], field: string): MetricAggregationAction => ({ - type: CHANGE_METRIC_FIELD, - payload: { - id, - field, - }, -}); - -export const toggleMetricVisibility = (id: MetricAggregation['id']): MetricAggregationAction => ({ - type: TOGGLE_METRIC_VISIBILITY, - payload: { - id, - }, -}); - -export const changeMetricAttribute = >( - metric: T, - attribute: K, - newValue: T[K] -): ChangeMetricAttributeAction => ({ - type: CHANGE_METRIC_ATTRIBUTE, - payload: { - metric, - attribute, - newValue, - }, -}); - -export const changeMetricSetting = >( - metric: T, - settingName: K, - // Maybe this could have been NonNullable[K], but it doesn't seem to work really well - newValue: NonNullable[K] -): ChangeMetricSettingAction => ({ - type: CHANGE_METRIC_SETTING, - payload: { - metric, - settingName, - newValue, - }, -}); - -export const changeMetricMeta = ( - metric: T, - meta: Extract['meta'], string>, - newValue: string | number | boolean -): ChangeMetricMetaAction => ({ - type: CHANGE_METRIC_META, - payload: { - metric, - meta, - newValue, - }, -}); +export const addMetric = createAction('@metrics/add'); +export const removeMetric = createAction('@metrics/remove'); +export const toggleMetricVisibility = createAction('@metrics/toggle_visibility'); +export const changeMetricField = createAction<{ id: MetricAggregation['id']; field: string }>('@metrics/change_field'); +export const changeMetricType = createAction<{ id: MetricAggregation['id']; type: MetricAggregation['type'] }>( + '@metrics/change_type' +); +export const changeMetricAttribute = createAction<{ metric: MetricAggregation; attribute: string; newValue: any }>( + '@metrics/change_attr' +); +export const changeMetricSetting = createAction<{ + metric: MetricAggregationWithSettings; + settingName: string; + newValue: any; +}>('@metrics/change_setting'); +export const changeMetricMeta = createAction<{ + metric: MetricAggregationWithMeta; + meta: string; + newValue: any; +}>('@metrics/change_meta'); 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 fb763e05ff8..e9ee62bfec2 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 @@ -77,7 +77,7 @@ describe('Metric Aggregations Reducer', () => { reducerTester() .givenReducer(reducer, [firstAggregation, secondAggregation]) - .whenActionIsDispatched(changeMetricType(secondAggregation.id, expectedSecondAggregation.type)) + .whenActionIsDispatched(changeMetricType({ id: secondAggregation.id, type: expectedSecondAggregation.type })) .thenStateShouldEqual([firstAggregation, { ...secondAggregation, type: expectedSecondAggregation.type }]); }); @@ -99,7 +99,7 @@ describe('Metric Aggregations Reducer', () => { reducerTester() .givenReducer(reducer, [firstAggregation, secondAggregation]) - .whenActionIsDispatched(changeMetricType(secondAggregation.id, expectedAggregation.type)) + .whenActionIsDispatched(changeMetricType({ id: secondAggregation.id, type: expectedAggregation.type })) .thenStateShouldEqual([expectedAggregation]); }); }); @@ -128,10 +128,10 @@ describe('Metric Aggregations Reducer', () => { reducerTester() .givenReducer(reducer, [firstAggregation, secondAggregation]) // When changing a a pipelineAggregation field we set both pipelineAgg and field - .whenActionIsDispatched(changeMetricField(secondAggregation.id, expectedSecondAggregation.field)) + .whenActionIsDispatched(changeMetricField({ id: secondAggregation.id, field: expectedSecondAggregation.field })) .thenStateShouldEqual([firstAggregation, expectedSecondAggregation]) // otherwhise only field - .whenActionIsDispatched(changeMetricField(firstAggregation.id, expectedFirstAggregation.field)) + .whenActionIsDispatched(changeMetricField({ id: firstAggregation.id, field: expectedFirstAggregation.field })) .thenStateShouldEqual([expectedFirstAggregation, expectedSecondAggregation]); }); @@ -173,7 +173,9 @@ describe('Metric Aggregations Reducer', () => { reducerTester() .givenReducer(reducer, [firstAggregation, secondAggregation]) - .whenActionIsDispatched(changeMetricSetting(firstAggregation, 'unit', expectedSettings.unit!)) + .whenActionIsDispatched( + changeMetricSetting({ metric: firstAggregation, settingName: 'unit', newValue: expectedSettings.unit! }) + ) .thenStateShouldEqual([{ ...firstAggregation, settings: expectedSettings }, secondAggregation]); }); @@ -196,7 +198,7 @@ describe('Metric Aggregations Reducer', () => { reducerTester() .givenReducer(reducer, [firstAggregation, secondAggregation]) - .whenActionIsDispatched(changeMetricMeta(firstAggregation, 'avg', expectedMeta.avg!)) + .whenActionIsDispatched(changeMetricMeta({ metric: firstAggregation, meta: 'avg', newValue: expectedMeta.avg! })) .thenStateShouldEqual([{ ...firstAggregation, meta: expectedMeta }, secondAggregation]); }); @@ -214,7 +216,9 @@ describe('Metric Aggregations Reducer', () => { reducerTester() .givenReducer(reducer, [firstAggregation, secondAggregation]) - .whenActionIsDispatched(changeMetricAttribute(firstAggregation, 'hide', expectedHide)) + .whenActionIsDispatched( + changeMetricAttribute({ metric: firstAggregation, attribute: 'hide', newValue: expectedHide }) + ) .thenStateShouldEqual([{ ...firstAggregation, hide: expectedHide }, secondAggregation]); }); 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 7bed9ec7323..c1919640f9a 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 @@ -1,7 +1,8 @@ +import { Action } from '@reduxjs/toolkit'; import { defaultMetricAgg } from '../../../../query_def'; import { ElasticsearchQuery } from '../../../../types'; import { removeEmpty } from '../../../../utils'; -import { INIT, InitAction } from '../../state'; +import { initQuery } from '../../state'; import { isMetricAggregationWithMeta, isMetricAggregationWithSettings, @@ -10,156 +11,156 @@ import { } from '../aggregations'; import { getChildren, metricAggregationConfig } from '../utils'; import { - ADD_METRIC, - CHANGE_METRIC_TYPE, - REMOVE_METRIC, - TOGGLE_METRIC_VISIBILITY, - MetricAggregationAction, - CHANGE_METRIC_FIELD, - CHANGE_METRIC_SETTING, - CHANGE_METRIC_META, - CHANGE_METRIC_ATTRIBUTE, -} from './types'; + addMetric, + changeMetricAttribute, + changeMetricField, + changeMetricMeta, + changeMetricSetting, + changeMetricType, + removeMetric, + toggleMetricVisibility, +} from './actions'; -export const reducer = ( - state: ElasticsearchQuery['metrics'], - action: MetricAggregationAction | InitAction -): ElasticsearchQuery['metrics'] => { - switch (action.type) { - case ADD_METRIC: - return [...state!, defaultMetricAgg(action.payload.id)]; +export const reducer = (state: ElasticsearchQuery['metrics'], action: Action): ElasticsearchQuery['metrics'] => { + if (addMetric.match(action)) { + return [...state!, defaultMetricAgg(action.payload)]; + } - case REMOVE_METRIC: - const metricToRemove = state!.find((m) => m.id === action.payload.id)!; - const metricsToRemove = [metricToRemove, ...getChildren(metricToRemove, state!)]; - const resultingMetrics = state!.filter( - (metric) => !metricsToRemove.some((toRemove) => toRemove.id === metric.id) - ); - if (resultingMetrics.length === 0) { - return [defaultMetricAgg('1')]; + if (removeMetric.match(action)) { + const metricToRemove = state!.find((m) => m.id === action.payload)!; + const metricsToRemove = [metricToRemove, ...getChildren(metricToRemove, state!)]; + const resultingMetrics = state!.filter((metric) => !metricsToRemove.some((toRemove) => toRemove.id === metric.id)); + if (resultingMetrics.length === 0) { + return [defaultMetricAgg('1')]; + } + return resultingMetrics; + } + + if (changeMetricType.match(action)) { + return state! + .filter((metric) => + // When the new metric type is `isSingleMetric` we remove all other metrics from the query + // leaving only the current one. + !!metricAggregationConfig[action.payload.type].isSingleMetric ? metric.id === action.payload.id : true + ) + .map((metric) => { + if (metric.id !== action.payload.id) { + return metric; + } + + /* + TODO: The previous version of the query editor was keeping some of the old metric's configurations + in the new selected one (such as field or some settings). + It the future would be nice to have the same behavior but it's hard without a proper definition, + as Elasticsearch will error sometimes if some settings are not compatible. + */ + return { + id: metric.id, + type: action.payload.type, + ...metricAggregationConfig[action.payload.type].defaults, + } as MetricAggregation; + }); + } + + if (changeMetricField.match(action)) { + return state!.map((metric) => { + if (metric.id !== action.payload.id) { + return metric; } - return resultingMetrics; - case CHANGE_METRIC_TYPE: - return state! - .filter((metric) => - // When the new metric type is `isSingleMetric` we remove all other metrics from the query - // leaving only the current one. - !!metricAggregationConfig[action.payload.type].isSingleMetric ? metric.id === action.payload.id : true - ) - .map((metric) => { - if (metric.id !== action.payload.id) { - return metric; - } + const newMetric = { + ...metric, + field: action.payload.field, + }; - /* - TODO: The previous version of the query editor was keeping some of the old metric's configurations - in the new selected one (such as field or some settings). - It the future would be nice to have the same behavior but it's hard without a proper definition, - as Elasticsearch will error sometimes if some settings are not compatible. - */ - return { - id: metric.id, - type: action.payload.type, - ...metricAggregationConfig[action.payload.type].defaults, - } as MetricAggregation; + if (isPipelineAggregation(metric)) { + return { ...newMetric, pipelineAgg: action.payload.field }; + } + + return newMetric; + }); + } + + if (toggleMetricVisibility.match(action)) { + return state!.map((metric) => { + if (metric.id !== action.payload) { + return metric; + } + + return { + ...metric, + hide: !metric.hide, + }; + }); + } + + if (changeMetricSetting.match(action)) { + return state!.map((metric) => { + if (metric.id !== action.payload.metric.id) { + return metric; + } + + // TODO: Here, instead of this if statement, we should assert that metric is MetricAggregationWithSettings + if (isMetricAggregationWithSettings(metric)) { + const newSettings = removeEmpty({ + ...metric.settings, + [action.payload.settingName]: action.payload.newValue, }); - case CHANGE_METRIC_FIELD: - return state!.map((metric) => { - if (metric.id !== action.payload.id) { - return metric; - } - - const newMetric = { - ...metric, - field: action.payload.field, - }; - - if (isPipelineAggregation(metric)) { - return { ...newMetric, pipelineAgg: action.payload.field }; - } - - return newMetric; - }); - - case TOGGLE_METRIC_VISIBILITY: - return state!.map((metric) => { - if (metric.id !== action.payload.id) { - return metric; - } - return { ...metric, - hide: !metric.hide, + settings: { + ...newSettings, + }, }; - }); - - case CHANGE_METRIC_SETTING: - return state!.map((metric) => { - if (metric.id !== action.payload.metric.id) { - return metric; - } - - // TODO: Here, instead of this if statement, we should assert that metric is MetricAggregationWithSettings - if (isMetricAggregationWithSettings(metric)) { - const newSettings = removeEmpty({ - ...metric.settings, - [action.payload.settingName]: action.payload.newValue, - }); - - return { - ...metric, - settings: { - ...newSettings, - }, - }; - } - - // This should never happen. - return metric; - }); - - case CHANGE_METRIC_META: - return state!.map((metric) => { - if (metric.id !== action.payload.metric.id) { - return metric; - } - - // TODO: Here, instead of this if statement, we should assert that metric is MetricAggregationWithMeta - if (isMetricAggregationWithMeta(metric)) { - return { - ...metric, - meta: { - ...metric.meta, - [action.payload.meta]: action.payload.newValue, - }, - }; - } - - // This should never happen. - return metric; - }); - - case CHANGE_METRIC_ATTRIBUTE: - return state!.map((metric) => { - if (metric.id !== action.payload.metric.id) { - return metric; - } - - return { - ...metric, - [action.payload.attribute]: action.payload.newValue, - }; - }); - - case INIT: - if (state?.length || 0 > 0) { - return state; } - return [defaultMetricAgg('1')]; - default: - return state; + // This should never happen. + return metric; + }); } + + if (changeMetricMeta.match(action)) { + return state!.map((metric) => { + if (metric.id !== action.payload.metric.id) { + return metric; + } + + // TODO: Here, instead of this if statement, we should assert that metric is MetricAggregationWithMeta + if (isMetricAggregationWithMeta(metric)) { + return { + ...metric, + meta: { + ...metric.meta, + [action.payload.meta]: action.payload.newValue, + }, + }; + } + + // This should never happen. + return metric; + }); + } + + if (changeMetricAttribute.match(action)) { + return state!.map((metric) => { + if (metric.id !== action.payload.metric.id) { + return metric; + } + + return { + ...metric, + [action.payload.attribute]: action.payload.newValue, + }; + }); + } + + if (initQuery.match(action)) { + if (state?.length || 0 > 0) { + return state; + } + return [defaultMetricAgg('1')]; + } + + return state; }; diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/state/types.ts b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/state/types.ts deleted file mode 100644 index 4c1a6f9a3d7..00000000000 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/state/types.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { Action } from '../../../../hooks/useStatelessReducer'; -import { SettingKeyOf } from '../../../types'; -import { - MetricAggregation, - MetricAggregationWithMeta, - MetricAggregationWithSettings, - MetricAggregationWithField, -} from '../aggregations'; - -export const ADD_METRIC = '@metrics/add'; -export const REMOVE_METRIC = '@metrics/remove'; -export const CHANGE_METRIC_TYPE = '@metrics/change_type'; -export const CHANGE_METRIC_FIELD = '@metrics/change_field'; -export const CHANGE_METRIC_SETTING = '@metrics/change_setting'; -export const CHANGE_METRIC_META = '@metrics/change_meta'; -export const CHANGE_METRIC_ATTRIBUTE = '@metrics/change_attr'; -export const TOGGLE_METRIC_VISIBILITY = '@metrics/toggle_visibility'; - -export interface AddMetricAction extends Action { - payload: { - id: MetricAggregation['id']; - }; -} - -export interface RemoveMetricAction extends Action { - payload: { - id: MetricAggregation['id']; - }; -} - -export interface ChangeMetricTypeAction extends Action { - payload: { - id: MetricAggregation['id']; - type: MetricAggregation['type']; - }; -} - -export interface ChangeMetricFieldAction extends Action { - payload: { - id: MetricAggregation['id']; - field: MetricAggregationWithField['field']; - }; -} -export interface ToggleMetricVisibilityAction extends Action { - payload: { - id: MetricAggregation['id']; - }; -} - -export interface ChangeMetricSettingAction - extends Action { - payload: { - metric: T; - settingName: SettingKeyOf; - newValue: unknown; - }; -} - -export interface ChangeMetricMetaAction extends Action { - payload: { - metric: T; - meta: Extract['meta'], string>; - newValue: string | number | boolean; - }; -} - -export interface ChangeMetricAttributeAction< - T extends MetricAggregation, - K extends Extract = Extract -> extends Action { - payload: { - metric: T; - attribute: K; - newValue: T[K]; - }; -} - -type CommonActions = - | AddMetricAction - | RemoveMetricAction - | ChangeMetricTypeAction - | ChangeMetricFieldAction - | ToggleMetricVisibilityAction; - -export type MetricAggregationAction = - | (T extends MetricAggregationWithSettings ? ChangeMetricSettingAction : never) - | (T extends MetricAggregationWithMeta ? ChangeMetricMetaAction : never) - | ChangeMetricAttributeAction - | CommonActions; diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/state.ts b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/state.ts index a655d764009..8601a3b0180 100644 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/state.ts +++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/state.ts @@ -1,69 +1,36 @@ -import { Action } from '../../hooks/useStatelessReducer'; +import { Action, createAction } from '@reduxjs/toolkit'; import { ElasticsearchQuery } from '../../types'; -export const INIT = 'init'; -const CHANGE_QUERY = 'change_query'; -const CHANGE_ALIAS_PATTERN = 'change_alias_pattern'; - -export interface InitAction extends Action {} - -interface ChangeQueryAction extends Action { - payload: { - query: string; - }; -} - -interface ChangeAliasPatternAction extends Action { - payload: { - aliasPattern: string; - }; -} - /** * When the `initQuery` Action is dispatched, the query gets populated with default values where values are not present. * This means it won't override any existing value in place, but just ensure the query is in a "runnable" state. */ -export const initQuery = (): InitAction => ({ type: INIT }); +export const initQuery = createAction('init'); -export const changeQuery = (query: string): ChangeQueryAction => ({ - type: CHANGE_QUERY, - payload: { - query, - }, -}); +export const changeQuery = createAction('change_query'); -export const changeAliasPattern = (aliasPattern: string): ChangeAliasPatternAction => ({ - type: CHANGE_ALIAS_PATTERN, - payload: { - aliasPattern, - }, -}); +export const changeAliasPattern = createAction('change_alias_pattern'); -export const queryReducer = (prevQuery: ElasticsearchQuery['query'], action: ChangeQueryAction | InitAction) => { - switch (action.type) { - case CHANGE_QUERY: - return action.payload.query; - - case INIT: - return prevQuery || ''; - - default: - return prevQuery; +export const queryReducer = (prevQuery: ElasticsearchQuery['query'], action: Action) => { + if (changeQuery.match(action)) { + return action.payload; } + + if (initQuery.match(action)) { + return prevQuery || ''; + } + + return prevQuery; }; -export const aliasPatternReducer = ( - prevAliasPattern: ElasticsearchQuery['alias'], - action: ChangeAliasPatternAction | InitAction -) => { - switch (action.type) { - case CHANGE_ALIAS_PATTERN: - return action.payload.aliasPattern; - - case INIT: - return prevAliasPattern || ''; - - default: - return prevAliasPattern; +export const aliasPatternReducer = (prevAliasPattern: ElasticsearchQuery['alias'], action: Action) => { + if (changeAliasPattern.match(action)) { + return action.payload; } + + if (initQuery.match(action)) { + return prevAliasPattern || ''; + } + + return prevAliasPattern; }; diff --git a/public/app/plugins/datasource/elasticsearch/hooks/useStatelessReducer.ts b/public/app/plugins/datasource/elasticsearch/hooks/useStatelessReducer.ts index 8a38cc3ce7c..3fed5c367b1 100644 --- a/public/app/plugins/datasource/elasticsearch/hooks/useStatelessReducer.ts +++ b/public/app/plugins/datasource/elasticsearch/hooks/useStatelessReducer.ts @@ -1,10 +1,7 @@ import { createContext, useCallback, useContext } from 'react'; +import { Action } from '@reduxjs/toolkit'; -export interface Action { - type: T; -} - -export type Reducer = (state: S, action: A) => S; +export type Reducer = (state: S, action: A) => S; export const combineReducers = (reducers: { [P in keyof S]: Reducer }) => ( state: S, diff --git a/scripts/ci-check-strict.sh b/scripts/ci-check-strict.sh index 0330698baeb..f18ffc6d8d1 100755 --- a/scripts/ci-check-strict.sh +++ b/scripts/ci-check-strict.sh @@ -3,7 +3,7 @@ set -e echo -e "Collecting code stats (typescript errors & more)" -ERROR_COUNT_LIMIT=73 +ERROR_COUNT_LIMIT=61 ERROR_COUNT="$(./node_modules/.bin/tsc --project tsconfig.json --noEmit --strict true | grep -oP 'Found \K(\d+)')" if [ "$ERROR_COUNT" -gt $ERROR_COUNT_LIMIT ]; then