diff --git a/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/QueryAndExpressionsStep.tsx b/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/QueryAndExpressionsStep.tsx index 7073b257626..1e66bba204d 100644 --- a/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/QueryAndExpressionsStep.tsx +++ b/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/QueryAndExpressionsStep.tsx @@ -3,7 +3,7 @@ import { cloneDeep } from 'lodash'; import { useCallback, useEffect, useMemo, useReducer, useState } from 'react'; import { Controller, useFormContext } from 'react-hook-form'; -import { getDefaultRelativeTimeRange, GrafanaTheme2, ReducerID } from '@grafana/data'; +import { getDefaultRelativeTimeRange, GrafanaTheme2 } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; import { config, getDataSourceSrv } from '@grafana/runtime'; import { @@ -21,7 +21,6 @@ import { } from '@grafana/ui'; import { Text } from '@grafana/ui/src/components/Text/Text'; import { t, Trans } from 'app/core/internationalization'; -import { EvalFunction } from 'app/features/alerting/state/alertDef'; import { isExpressionQuery } from 'app/features/expressions/guards'; import { ExpressionDatasourceUID, @@ -60,7 +59,6 @@ import { SIMPLE_CONDITION_QUERY_ID, SIMPLE_CONDITION_REDUCER_ID, SIMPLE_CONDITION_THRESHOLD_ID, - SimpleCondition, SimpleConditionEditor, } from './SimpleCondition'; import { SmartAlertTypeDetector } from './SmartAlertTypeDetector'; @@ -82,6 +80,7 @@ import { updateExpressionTimeRange, updateExpressionType, } from './reducer'; +import { useAdvancedMode } from './useAdvancedMode'; import { useAlertQueryRunner } from './useAlertQueryRunner'; export function areQueriesTransformableToSimpleCondition( @@ -168,25 +167,14 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange }: P const isGrafanaAlertingType = isGrafanaAlertingRuleByType(type); const isRecordingRuleType = isCloudRecordingRuleByType(type); const isCloudAlertRuleType = isCloudAlertingRuleByType(type); - const queryParamsAreTransformable = areQueriesTransformableToSimpleCondition(dataQueries, expressionQueries); - - const isAdvancedMode = - Boolean(editorSettings?.simplifiedQueryEditor) === false || - !isGrafanaAlertingType || - (isNewFromQueryParams && !queryParamsAreTransformable); - const [showResetModeModal, setShowResetModal] = useState(false); - const [simpleCondition, setSimpleCondition] = useState( - isGrafanaAlertingType && areQueriesTransformableToSimpleCondition(dataQueries, expressionQueries) - ? getSimpleConditionFromExpressions(expressionQueries) - : { - whenField: ReducerID.last, - evaluator: { - params: [0], - type: EvalFunction.IsAbove, - }, - } + const { isAdvancedMode, simpleCondition, setSimpleCondition } = useAdvancedMode( + editorSettings, + isGrafanaAlertingType, + isNewFromQueryParams, + dataQueries, + expressionQueries ); // If we switch to simple mode we need to update the simple condition with the data in the queries reducer @@ -194,7 +182,7 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange }: P if (!isAdvancedMode && isGrafanaAlertingType) { setSimpleCondition(getSimpleConditionFromExpressions(expressionQueries)); } - }, [isAdvancedMode, expressionQueries, isGrafanaAlertingType]); + }, [isAdvancedMode, expressionQueries, isGrafanaAlertingType, setSimpleCondition]); const dispatchReduxAction = useDispatch(); useEffect(() => { diff --git a/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/__snapshots__/areQueriesTransformableToSimpleCondition.test.ts b/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/__snapshots__/areQueriesTransformableToSimpleCondition.test.ts index 0357d99f4d1..363c88c6eab 100644 --- a/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/__snapshots__/areQueriesTransformableToSimpleCondition.test.ts +++ b/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/__snapshots__/areQueriesTransformableToSimpleCondition.test.ts @@ -3,42 +3,11 @@ import { produce } from 'immer'; import { EvalFunction } from 'app/features/alerting/state/alertDef'; -import { ExpressionQuery, ExpressionQueryType, ReducerMode } from 'app/features/expressions/types'; +import { dataQuery, reduceExpression, thresholdExpression } from 'app/features/alerting/unified/mocks'; +import { ExpressionQuery, ReducerMode } from 'app/features/expressions/types'; import { AlertDataQuery, AlertQuery } from 'app/types/unified-alerting-dto'; import { areQueriesTransformableToSimpleCondition } from '../QueryAndExpressionsStep'; -import { - SIMPLE_CONDITION_QUERY_ID, - SIMPLE_CONDITION_REDUCER_ID, - SIMPLE_CONDITION_THRESHOLD_ID, -} from '../SimpleCondition'; - -const dataQuery: AlertQuery = { - refId: SIMPLE_CONDITION_QUERY_ID, - datasourceUid: 'abc123', - queryType: '', - model: { refId: SIMPLE_CONDITION_QUERY_ID }, -}; - -const reduceExpression: AlertQuery = { - refId: SIMPLE_CONDITION_REDUCER_ID, - queryType: 'expression', - datasourceUid: '__expr__', - model: { - type: ExpressionQueryType.reduce, - refId: SIMPLE_CONDITION_REDUCER_ID, - settings: { mode: ReducerMode.Strict }, - }, -}; -const thresholdExpression: AlertQuery = { - refId: SIMPLE_CONDITION_THRESHOLD_ID, - queryType: 'expression', - datasourceUid: '__expr__', - model: { - type: ExpressionQueryType.threshold, - refId: SIMPLE_CONDITION_THRESHOLD_ID, - }, -}; const expressionQueries: Array> = [reduceExpression, thresholdExpression]; diff --git a/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/determineAdvancedMode.test.ts b/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/determineAdvancedMode.test.ts new file mode 100644 index 00000000000..ad598680709 --- /dev/null +++ b/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/determineAdvancedMode.test.ts @@ -0,0 +1,78 @@ +import { produce } from 'immer'; + +import { dataQuery, reduceExpression, thresholdExpression } from '../../../mocks'; + +import { determineAdvancedMode } from './useAdvancedMode'; + +const dataQueries = [dataQuery]; +const expressionQueries = [reduceExpression, thresholdExpression]; + +describe('determineAdvancedMode', () => { + it('should return true if simplifiedQueryEditor is false', () => { + const editorSettings = { simplifiedQueryEditor: false }; + const isGrafanaAlertingType = true; + const isNewFromQueryParams = false; + + const result = determineAdvancedMode( + editorSettings, + isGrafanaAlertingType, + isNewFromQueryParams, + dataQueries, + expressionQueries + ); + + expect(result).toBe(true); + }); + + it('should return true if isGrafanaAlertingType is false', () => { + const editorSettings = { simplifiedQueryEditor: true }; + const isGrafanaAlertingType = false; + const isNewFromQueryParams = false; + + const result = determineAdvancedMode( + editorSettings, + isGrafanaAlertingType, + isNewFromQueryParams, + dataQueries, + expressionQueries + ); + + expect(result).toBe(true); + }); + + it('should return true if isNewFromQueryParams is true and queries are not transformable', () => { + const editorSettings = { simplifiedQueryEditor: true }; + const isGrafanaAlertingType = true; + const isNewFromQueryParams = true; + + const newQuery = produce(dataQuery, (draft) => { + draft.refId = 'whatever'; + }); + + const result = determineAdvancedMode( + editorSettings, + isGrafanaAlertingType, + isNewFromQueryParams, + [newQuery], + expressionQueries + ); + + expect(result).toBe(true); + }); + + it('should return false if all conditions are false', () => { + const editorSettings = { simplifiedQueryEditor: true }; + const isGrafanaAlertingType = true; + const isNewFromQueryParams = false; + + const result = determineAdvancedMode( + editorSettings, + isGrafanaAlertingType, + isNewFromQueryParams, + dataQueries, + expressionQueries + ); + + expect(result).toBe(false); + }); +}); diff --git a/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/useAdvancedMode.ts b/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/useAdvancedMode.ts new file mode 100644 index 00000000000..3fbf4f91874 --- /dev/null +++ b/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/useAdvancedMode.ts @@ -0,0 +1,75 @@ +import { useEffect, useState } from 'react'; + +import { ReducerID } from '@grafana/data'; +import { EvalFunction } from 'app/features/alerting/state/alertDef'; +import { ExpressionQuery } from 'app/features/expressions/types'; +import { AlertDataQuery, AlertQuery } from 'app/types/unified-alerting-dto'; + +import { SimplifiedEditor } from '../../../types/rule-form'; + +import { areQueriesTransformableToSimpleCondition } from './QueryAndExpressionsStep'; +import { getSimpleConditionFromExpressions, SimpleCondition } from './SimpleCondition'; + +function initializeSimpleCondition( + isGrafanaAlertingType: boolean, + dataQueries: Array>, + expressionQueries: Array> +) { + if (isGrafanaAlertingType && areQueriesTransformableToSimpleCondition(dataQueries, expressionQueries)) { + return getSimpleConditionFromExpressions(expressionQueries); + } else { + return { + whenField: ReducerID.last, + evaluator: { + params: [0], + type: EvalFunction.IsAbove, + }, + }; + } +} +export function determineAdvancedMode( + editorSettings: SimplifiedEditor | undefined, + isGrafanaAlertingType: boolean, + isNewFromQueryParams: boolean, + dataQueries: Array>, + expressionQueries: Array> +) { + const queryParamsAreTransformable = areQueriesTransformableToSimpleCondition(dataQueries, expressionQueries); + return ( + Boolean(editorSettings?.simplifiedQueryEditor) === false || + !isGrafanaAlertingType || + (isNewFromQueryParams && !queryParamsAreTransformable) + ); +} + +/* + This hook is used mantain the state of the advanced mode, and the simple condition, + depending on the editor settings, the alert type, and the queries. + */ +export const useAdvancedMode = ( + editorSettings: SimplifiedEditor | undefined, + isGrafanaAlertingType: boolean, + isNewFromQueryParams: boolean, + dataQueries: Array>, + expressionQueries: Array> +) => { + const isAdvancedMode = determineAdvancedMode( + editorSettings, + isGrafanaAlertingType, + isNewFromQueryParams, + dataQueries, + expressionQueries + ); + + const [simpleCondition, setSimpleCondition] = useState( + initializeSimpleCondition(isGrafanaAlertingType, dataQueries, expressionQueries) + ); + + useEffect(() => { + if (!isAdvancedMode && isGrafanaAlertingType) { + setSimpleCondition(getSimpleConditionFromExpressions(expressionQueries)); + } + }, [isAdvancedMode, expressionQueries, isGrafanaAlertingType]); + + return { isAdvancedMode, simpleCondition, setSimpleCondition }; +}; diff --git a/public/app/features/alerting/unified/mocks.ts b/public/app/features/alerting/unified/mocks.ts index 4c5dfdd11e9..0564b60507a 100644 --- a/public/app/features/alerting/unified/mocks.ts +++ b/public/app/features/alerting/unified/mocks.ts @@ -12,6 +12,7 @@ import { DataSourceRef, PluginExtensionLink, PluginExtensionTypes, + ReducerID, ScopedVars, TestDataSourceResponse, } from '@grafana/data'; @@ -19,6 +20,7 @@ import { DataSourceSrv, GetDataSourceListFilters, config } from '@grafana/runtim import { defaultDashboard } from '@grafana/schema'; import { contextSrv } from 'app/core/services/context_srv'; import { MOCK_GRAFANA_ALERT_RULE_TITLE } from 'app/features/alerting/unified/mocks/server/handlers/grafanaRuler'; +import { ExpressionQuery, ExpressionQueryType, ReducerMode } from 'app/features/expressions/types'; import { DatasourceSrv } from 'app/features/plugins/datasource_srv'; import { AlertManagerCortexConfig, @@ -45,6 +47,7 @@ import { RuleWithLocation, } from 'app/types/unified-alerting'; import { + AlertDataQuery, AlertQuery, GrafanaAlertState, GrafanaAlertStateDecision, @@ -61,6 +64,11 @@ import { import { DashboardSearchItem, DashboardSearchItemType } from '../../search/types'; +import { + SIMPLE_CONDITION_QUERY_ID, + SIMPLE_CONDITION_REDUCER_ID, + SIMPLE_CONDITION_THRESHOLD_ID, +} from './components/rule-editor/query-and-alert-condition/SimpleCondition'; import { parsePromQLStyleMatcherLooseSafe } from './utils/matchers'; let nextDataSourceId = 1; @@ -845,3 +853,31 @@ export function mockDashboardDto( meta: { ...meta }, }; } + +export const dataQuery: AlertQuery = { + refId: SIMPLE_CONDITION_QUERY_ID, + datasourceUid: 'abc123', + queryType: '', + model: { refId: SIMPLE_CONDITION_QUERY_ID }, +}; + +export const reduceExpression: AlertQuery = { + refId: SIMPLE_CONDITION_REDUCER_ID, + queryType: 'expression', + datasourceUid: '__expr__', + model: { + type: ExpressionQueryType.reduce, + refId: SIMPLE_CONDITION_REDUCER_ID, + settings: { mode: ReducerMode.Strict }, + reducer: ReducerID.last, + }, +}; +export const thresholdExpression: AlertQuery = { + refId: SIMPLE_CONDITION_THRESHOLD_ID, + queryType: 'expression', + datasourceUid: '__expr__', + model: { + type: ExpressionQueryType.threshold, + refId: SIMPLE_CONDITION_THRESHOLD_ID, + }, +};