Alerting: Move logic for simple mode in QueryAndExpressionsStep to a separate hook (#94709)

* Move logic for simple mode in QueryAndExpressionsStep to a separate hook and add tests

* remove unnecessary jest.clearAllMocks
This commit is contained in:
Sonia Aguilar
2024-10-24 16:26:46 +02:00
committed by GitHub
parent 5fb1c7f512
commit f5bd197cdb
5 changed files with 200 additions and 54 deletions
@@ -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<SimpleCondition>(
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(() => {
@@ -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<AlertDataQuery | ExpressionQuery> = {
refId: SIMPLE_CONDITION_QUERY_ID,
datasourceUid: 'abc123',
queryType: '',
model: { refId: SIMPLE_CONDITION_QUERY_ID },
};
const reduceExpression: AlertQuery<ExpressionQuery> = {
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<ExpressionQuery> = {
refId: SIMPLE_CONDITION_THRESHOLD_ID,
queryType: 'expression',
datasourceUid: '__expr__',
model: {
type: ExpressionQueryType.threshold,
refId: SIMPLE_CONDITION_THRESHOLD_ID,
},
};
const expressionQueries: Array<AlertQuery<ExpressionQuery>> = [reduceExpression, thresholdExpression];
@@ -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);
});
});
@@ -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<AlertQuery<AlertDataQuery>>,
expressionQueries: Array<AlertQuery<ExpressionQuery>>
) {
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<AlertQuery<ExpressionQuery | AlertDataQuery>>,
expressionQueries: Array<AlertQuery<ExpressionQuery>>
) {
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<AlertQuery<ExpressionQuery | AlertDataQuery>>,
expressionQueries: Array<AlertQuery<ExpressionQuery>>
) => {
const isAdvancedMode = determineAdvancedMode(
editorSettings,
isGrafanaAlertingType,
isNewFromQueryParams,
dataQueries,
expressionQueries
);
const [simpleCondition, setSimpleCondition] = useState<SimpleCondition>(
initializeSimpleCondition(isGrafanaAlertingType, dataQueries, expressionQueries)
);
useEffect(() => {
if (!isAdvancedMode && isGrafanaAlertingType) {
setSimpleCondition(getSimpleConditionFromExpressions(expressionQueries));
}
}, [isAdvancedMode, expressionQueries, isGrafanaAlertingType]);
return { isAdvancedMode, simpleCondition, setSimpleCondition };
};
@@ -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<AlertDataQuery | ExpressionQuery> = {
refId: SIMPLE_CONDITION_QUERY_ID,
datasourceUid: 'abc123',
queryType: '',
model: { refId: SIMPLE_CONDITION_QUERY_ID },
};
export const reduceExpression: AlertQuery<ExpressionQuery> = {
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<ExpressionQuery> = {
refId: SIMPLE_CONDITION_THRESHOLD_ID,
queryType: 'expression',
datasourceUid: '__expr__',
model: {
type: ExpressionQueryType.threshold,
refId: SIMPLE_CONDITION_THRESHOLD_ID,
},
};