Alerting: Fix simplified query step (#97046)

* Fix simplified query step

* remove is advancedMode and use editorSettings.simplifiedQueryEditor

* remove unnecessary Boolean conversion

* fix when feature toggle is disabled

* fix test

* simplify code

* fix when not ff is not enabled
This commit is contained in:
Sonia Aguilar 2024-11-27 15:13:27 +01:00 committed by GitHub
parent 3f83322fa9
commit a0de712bca
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 77 additions and 111 deletions

View File

@ -14,6 +14,7 @@ import {
RelativeTimeRange, RelativeTimeRange,
ThresholdsConfig, ThresholdsConfig,
} from '@grafana/data'; } from '@grafana/data';
import { config } from '@grafana/runtime';
import { DataQuery } from '@grafana/schema'; import { DataQuery } from '@grafana/schema';
import { GraphThresholdsStyleMode, Icon, InlineField, Input, Stack, Tooltip, useStyles2 } from '@grafana/ui'; import { GraphThresholdsStyleMode, Icon, InlineField, Input, Stack, Tooltip, useStyles2 } from '@grafana/ui';
import { logInfo } from 'app/features/alerting/unified/Analytics'; import { logInfo } from 'app/features/alerting/unified/Analytics';
@ -81,7 +82,8 @@ export const QueryWrapper = ({
const defaults = dsInstance?.getDefaultQuery ? dsInstance.getDefaultQuery(CoreApp.UnifiedAlerting) : {}; const defaults = dsInstance?.getDefaultQuery ? dsInstance.getDefaultQuery(CoreApp.UnifiedAlerting) : {};
const { getValues } = useFormContext<RuleFormValues>(); const { getValues } = useFormContext<RuleFormValues>();
const isAdvancedMode = getValues('editorSettings.simplifiedQueryEditor') !== true; const isSwitchModeEnabled = config.featureToggles.alertingQueryAndExpressionsStepMode ?? false;
const isAdvancedMode = isSwitchModeEnabled ? getValues('editorSettings.simplifiedQueryEditor') !== true : true;
const queryWithDefaults = { const queryWithDefaults = {
...defaults, ...defaults,

View File

@ -67,7 +67,11 @@ import { GrafanaFolderAndLabelsStep } from '../GrafanaFolderAndLabelsStep';
import { NotificationsStep } from '../NotificationsStep'; import { NotificationsStep } from '../NotificationsStep';
import { RecordingRulesNameSpaceAndGroupStep } from '../RecordingRulesNameSpaceAndGroupStep'; import { RecordingRulesNameSpaceAndGroupStep } from '../RecordingRulesNameSpaceAndGroupStep';
import { RuleInspector } from '../RuleInspector'; import { RuleInspector } from '../RuleInspector';
import { QueryAndExpressionsStep } from '../query-and-alert-condition/QueryAndExpressionsStep'; import {
areQueriesTransformableToSimpleCondition,
isExpressionQueryInAlert,
QueryAndExpressionsStep,
} from '../query-and-alert-condition/QueryAndExpressionsStep';
import { translateRouteParamToRuleType } from '../util'; import { translateRouteParamToRuleType } from '../util';
type Props = { type Props = {
@ -386,15 +390,17 @@ function formValuesFromQueryParams(ruleDefinition: string, type: RuleFormType):
}; };
} }
return setInstantOrRange( return setQueryEditorSettings(
ignoreHiddenQueries({ setInstantOrRange(
...getDefaultFormValues(), ignoreHiddenQueries({
...ruleFromQueryParams, ...getDefaultFormValues(),
annotations: normalizeDefaultAnnotations(ruleFromQueryParams.annotations ?? []), ...ruleFromQueryParams,
queries: ruleFromQueryParams.queries ?? getDefaultQueries(), annotations: normalizeDefaultAnnotations(ruleFromQueryParams.annotations ?? []),
type: type || RuleFormType.grafana, queries: ruleFromQueryParams.queries ?? getDefaultQueries(),
evaluateEvery: DEFAULT_GROUP_EVALUATION_INTERVAL, type: type || RuleFormType.grafana,
}) evaluateEvery: DEFAULT_GROUP_EVALUATION_INTERVAL,
})
)
); );
} }
@ -405,6 +411,35 @@ function formValuesFromPrefill(rule: Partial<RuleFormValues>): RuleFormValues {
}); });
} }
function setQueryEditorSettings(values: RuleFormValues): RuleFormValues {
const isQuerySwitchModeEnabled = config.featureToggles.alertingQueryAndExpressionsStepMode ?? false;
if (!isQuerySwitchModeEnabled) {
return {
...values,
editorSettings: {
simplifiedQueryEditor: false,
simplifiedNotificationEditor: true, // actually it doesn't matter in this case
},
};
}
// data queries only
const dataQueries = values.queries.filter((query) => !isExpressionQuery(query.model));
// expression queries only
const expressionQueries = values.queries.filter((query) => isExpressionQueryInAlert(query));
const queryParamsAreTransformable = areQueriesTransformableToSimpleCondition(dataQueries, expressionQueries);
return {
...values,
editorSettings: {
simplifiedQueryEditor: queryParamsAreTransformable,
simplifiedNotificationEditor: true,
},
};
}
function setInstantOrRange(values: RuleFormValues): RuleFormValues { function setInstantOrRange(values: RuleFormValues): RuleFormValues {
return { return {
...values, ...values,

View File

@ -32,7 +32,6 @@ import {
import { AlertDataQuery, AlertQuery } from 'app/types/unified-alerting-dto'; import { AlertDataQuery, AlertQuery } from 'app/types/unified-alerting-dto';
import { useRulesSourcesWithRuler } from '../../../hooks/useRuleSourcesWithRuler'; import { useRulesSourcesWithRuler } from '../../../hooks/useRuleSourcesWithRuler';
import { useURLSearchParams } from '../../../hooks/useURLSearchParams';
import { RuleFormType, RuleFormValues } from '../../../types/rule-form'; import { RuleFormType, RuleFormValues } from '../../../types/rule-form';
import { getDefaultOrFirstCompatibleDataSource } from '../../../utils/datasource'; import { getDefaultOrFirstCompatibleDataSource } from '../../../utils/datasource';
import { isPromOrLokiQuery, PromOrLokiQuery } from '../../../utils/rule-form'; import { isPromOrLokiQuery, PromOrLokiQuery } from '../../../utils/rule-form';
@ -134,9 +133,7 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange }: P
} = useFormContext<RuleFormValues>(); } = useFormContext<RuleFormValues>();
const { queryPreviewData, runQueries, cancelQueries, isPreviewLoading, clearPreviewData } = useAlertQueryRunner(); const { queryPreviewData, runQueries, cancelQueries, isPreviewLoading, clearPreviewData } = useAlertQueryRunner();
const [queryParams] = useURLSearchParams();
const isSwitchModeEnabled = config.featureToggles.alertingQueryAndExpressionsStepMode ?? false; const isSwitchModeEnabled = config.featureToggles.alertingQueryAndExpressionsStepMode ?? false;
const isNewFromQueryParams = queryParams.has('defaults') && !editingExistingRule;
const initialState = { const initialState = {
queries: getValues('queries'), queries: getValues('queries'),
@ -167,20 +164,23 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange }: P
const isCloudAlertRuleType = isCloudAlertingRuleByType(type); const isCloudAlertRuleType = isCloudAlertingRuleByType(type);
const [showResetModeModal, setShowResetModal] = useState(false); const [showResetModeModal, setShowResetModal] = useState(false);
const { isAdvancedMode, simpleCondition, setSimpleCondition } = useAdvancedMode( const simplifiedQueryInForm = editorSettings?.simplifiedQueryEditor;
editorSettings,
const { simpleCondition, setSimpleCondition } = useAdvancedMode(
simplifiedQueryInForm,
isGrafanaAlertingType, isGrafanaAlertingType,
isNewFromQueryParams,
dataQueries, dataQueries,
expressionQueries expressionQueries
); );
const simplifiedQueryStep = isSwitchModeEnabled ? getValues('editorSettings.simplifiedQueryEditor') : false;
// If we switch to simple mode we need to update the simple condition with the data in the queries reducer // If we switch to simple mode we need to update the simple condition with the data in the queries reducer
useEffect(() => { useEffect(() => {
if (!isAdvancedMode && isGrafanaAlertingType) { if (simplifiedQueryStep && isGrafanaAlertingType) {
setSimpleCondition(getSimpleConditionFromExpressions(expressionQueries)); setSimpleCondition(getSimpleConditionFromExpressions(expressionQueries));
} }
}, [isAdvancedMode, expressionQueries, isGrafanaAlertingType, setSimpleCondition]); }, [simplifiedQueryStep, expressionQueries, isGrafanaAlertingType, setSimpleCondition]);
const { rulesSourcesWithRuler } = useRulesSourcesWithRuler(); const { rulesSourcesWithRuler } = useRulesSourcesWithRuler();
@ -192,14 +192,14 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange }: P
return; return;
} }
// we need to be sure the condition is set once we switch to simple mode // we need to be sure the condition is set once we switch to simple mode
if (!isAdvancedMode) { if (simplifiedQueryStep) {
setValue('condition', SimpleConditionIdentifier.thresholdId); setValue('condition', SimpleConditionIdentifier.thresholdId);
runQueries(getValues('queries'), SimpleConditionIdentifier.thresholdId); runQueries(getValues('queries'), SimpleConditionIdentifier.thresholdId);
} else { } else {
runQueries(getValues('queries'), condition || (getValues('condition') ?? '')); runQueries(getValues('queries'), condition || (getValues('condition') ?? ''));
} }
}, },
[isCloudAlertRuleType, runQueries, getValues, isAdvancedMode, setValue] [isCloudAlertRuleType, runQueries, getValues, simplifiedQueryStep, setValue]
); );
// whenever we update the queries we have to update the form too // whenever we update the queries we have to update the form too
@ -472,13 +472,12 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange }: P
if (!type) { if (!type) {
return null; return null;
} }
const switchMode = const switchMode =
isGrafanaAlertingType && isSwitchModeEnabled isGrafanaAlertingType && isSwitchModeEnabled
? { ? {
isAdvancedMode, isAdvancedMode: !simplifiedQueryStep,
setAdvancedMode: (isAdvanced: boolean) => { setAdvancedMode: (isAdvanced: boolean) => {
if (!isAdvanced) { if (!getValues('editorSettings.simplifiedQueryEditor')) {
if (!areQueriesTransformableToSimpleCondition(dataQueries, expressionQueries)) { if (!areQueriesTransformableToSimpleCondition(dataQueries, expressionQueries)) {
setShowResetModal(true); setShowResetModal(true);
return; return;
@ -573,7 +572,7 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange }: P
condition={condition} condition={condition}
onSetCondition={handleSetCondition} onSetCondition={handleSetCondition}
/> />
{isAdvancedMode && ( {!simplifiedQueryStep && (
<Tooltip content={'You appear to have no compatible data sources'} show={noCompatibleDataSources}> <Tooltip content={'You appear to have no compatible data sources'} show={noCompatibleDataSources}>
<Button <Button
type="button" type="button"
@ -590,7 +589,7 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange }: P
</Tooltip> </Tooltip>
)} )}
{/* We only show Switch for Grafana managed alerts */} {/* We only show Switch for Grafana managed alerts */}
{isGrafanaAlertingType && isAdvancedMode && ( {isGrafanaAlertingType && !simplifiedQueryStep && (
<SmartAlertTypeDetector <SmartAlertTypeDetector
editingExistingRule={editingExistingRule} editingExistingRule={editingExistingRule}
rulesSourcesWithRuler={rulesSourcesWithRuler} rulesSourcesWithRuler={rulesSourcesWithRuler}
@ -599,7 +598,7 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange }: P
/> />
)} )}
{/* Expression Queries */} {/* Expression Queries */}
{isAdvancedMode && ( {!simplifiedQueryStep && (
<> <>
<Stack direction="column" gap={0}> <Stack direction="column" gap={0}>
<Text element="h5">Expressions</Text> <Text element="h5">Expressions</Text>
@ -628,7 +627,7 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange }: P
)} )}
{/* action buttons */} {/* action buttons */}
<Stack direction="column"> <Stack direction="column">
{!isAdvancedMode && ( {simplifiedQueryStep && (
<SimpleConditionEditor <SimpleConditionEditor
simpleCondition={simpleCondition} simpleCondition={simpleCondition}
onChange={setSimpleCondition} onChange={setSimpleCondition}
@ -638,7 +637,7 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange }: P
/> />
)} )}
<Stack direction="row"> <Stack direction="row">
{isAdvancedMode && config.expressionsEnabled && <TypeSelectorButton onClickType={onClickType} />} {!simplifiedQueryStep && config.expressionsEnabled && <TypeSelectorButton onClickType={onClickType} />}
{isPreviewLoading && ( {isPreviewLoading && (
<Button icon="spinner" type="button" variant="destructive" onClick={cancelQueries}> <Button icon="spinner" type="button" variant="destructive" onClick={cancelQueries}>
@ -653,7 +652,7 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange }: P
onClick={() => runQueriesPreview()} onClick={() => runQueriesPreview()}
disabled={emptyQueries} disabled={emptyQueries}
> >
{isAdvancedMode {!simplifiedQueryStep
? t('alerting.queryAndExpressionsStep.preview', 'Preview') ? t('alerting.queryAndExpressionsStep.preview', 'Preview')
: t('alerting.queryAndExpressionsStep.previewCondition', 'Preview alert rule condition')} : t('alerting.queryAndExpressionsStep.previewCondition', 'Preview alert rule condition')}
</Button> </Button>
@ -688,7 +687,7 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange }: P
confirmText="Deactivate" confirmText="Deactivate"
icon="exclamation-triangle" icon="exclamation-triangle"
onConfirm={() => { onConfirm={() => {
setValue('editorSettings.simplifiedNotificationEditor', true); setValue('editorSettings.simplifiedQueryEditor', true);
setShowResetModal(false); setShowResetModal(false);
dispatch(resetToSimpleCondition()); dispatch(resetToSimpleCondition());
}} }}
@ -768,7 +767,7 @@ const useSetExpressionAndDataSource = () => {
}; };
}; };
function isExpressionQueryInAlert( export function isExpressionQueryInAlert(
query: AlertQuery<AlertDataQuery | ExpressionQuery> query: AlertQuery<AlertDataQuery | ExpressionQuery>
): query is AlertQuery<ExpressionQuery> { ): query is AlertQuery<ExpressionQuery> {
return isExpressionQuery(query.model); return isExpressionQuery(query.model);

View File

@ -1,76 +1,26 @@
import { produce } from 'immer';
import { dataQuery, reduceExpression, thresholdExpression } from '../../../mocks';
import { determineAdvancedMode } from './useAdvancedMode'; import { determineAdvancedMode } from './useAdvancedMode';
const dataQueries = [dataQuery];
const expressionQueries = [reduceExpression, thresholdExpression];
describe('determineAdvancedMode', () => { describe('determineAdvancedMode', () => {
it('should return true if simplifiedQueryEditor is false', () => { it('should return true if simplifiedQueryEditor is false', () => {
const editorSettings = { simplifiedQueryEditor: false, simplifiedNotificationEditor: true };
const isGrafanaAlertingType = true; const isGrafanaAlertingType = true;
const isNewFromQueryParams = false;
const result = determineAdvancedMode( const result = determineAdvancedMode(false, isGrafanaAlertingType);
editorSettings,
isGrafanaAlertingType,
isNewFromQueryParams,
dataQueries,
expressionQueries
);
expect(result).toBe(true); expect(result).toBe(true);
}); });
it('should return true if isGrafanaAlertingType is false', () => { it('should return true if isGrafanaAlertingType is false', () => {
const editorSettings = { simplifiedQueryEditor: true, simplifiedNotificationEditor: true };
const isGrafanaAlertingType = false; const isGrafanaAlertingType = false;
const isNewFromQueryParams = false;
const result = determineAdvancedMode( const result = determineAdvancedMode(true, isGrafanaAlertingType);
editorSettings,
isGrafanaAlertingType,
isNewFromQueryParams,
dataQueries,
expressionQueries
);
expect(result).toBe(true);
});
const editorSettings = { simplifiedQueryEditor: true, simplifiedNotificationEditor: true };
it('should return true if isNewFromQueryParams is true and queries are not transformable', () => {
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); expect(result).toBe(true);
}); });
it('should return false if all conditions are false', () => { it('should return false if all conditions are false', () => {
const isGrafanaAlertingType = true; const isGrafanaAlertingType = true;
const isNewFromQueryParams = false;
const result = determineAdvancedMode( const result = determineAdvancedMode(true, isGrafanaAlertingType);
editorSettings,
isGrafanaAlertingType,
isNewFromQueryParams,
dataQueries,
expressionQueries
);
expect(result).toBe(false); expect(result).toBe(false);
}); });

View File

@ -5,8 +5,6 @@ import { EvalFunction } from 'app/features/alerting/state/alertDef';
import { ExpressionQuery } from 'app/features/expressions/types'; import { ExpressionQuery } from 'app/features/expressions/types';
import { AlertDataQuery, AlertQuery } from 'app/types/unified-alerting-dto'; import { AlertDataQuery, AlertQuery } from 'app/types/unified-alerting-dto';
import { SimplifiedEditor } from '../../../types/rule-form';
import { areQueriesTransformableToSimpleCondition } from './QueryAndExpressionsStep'; import { areQueriesTransformableToSimpleCondition } from './QueryAndExpressionsStep';
import { getSimpleConditionFromExpressions, SimpleCondition } from './SimpleCondition'; import { getSimpleConditionFromExpressions, SimpleCondition } from './SimpleCondition';
@ -27,19 +25,8 @@ function initializeSimpleCondition(
}; };
} }
} }
export function determineAdvancedMode( export function determineAdvancedMode(simplifiedQueryEditor: boolean | undefined, isGrafanaAlertingType: boolean) {
editorSettings: SimplifiedEditor | undefined, return simplifiedQueryEditor === false || !isGrafanaAlertingType;
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)
);
} }
/* /*
@ -47,29 +34,22 @@ export function determineAdvancedMode(
depending on the editor settings, the alert type, and the queries. depending on the editor settings, the alert type, and the queries.
*/ */
export const useAdvancedMode = ( export const useAdvancedMode = (
editorSettings: SimplifiedEditor | undefined, simplifiedQueryEditor: boolean | undefined,
isGrafanaAlertingType: boolean, isGrafanaAlertingType: boolean,
isNewFromQueryParams: boolean,
dataQueries: Array<AlertQuery<ExpressionQuery | AlertDataQuery>>, dataQueries: Array<AlertQuery<ExpressionQuery | AlertDataQuery>>,
expressionQueries: Array<AlertQuery<ExpressionQuery>> expressionQueries: Array<AlertQuery<ExpressionQuery>>
) => { ) => {
const isAdvancedMode = determineAdvancedMode( const isAdvancedMode = determineAdvancedMode(simplifiedQueryEditor, isGrafanaAlertingType);
editorSettings,
isGrafanaAlertingType,
isNewFromQueryParams,
dataQueries,
expressionQueries
);
const [simpleCondition, setSimpleCondition] = useState<SimpleCondition>( const [simpleCondition, setSimpleCondition] = useState<SimpleCondition>(
initializeSimpleCondition(isGrafanaAlertingType, dataQueries, expressionQueries) initializeSimpleCondition(isGrafanaAlertingType, dataQueries, expressionQueries)
); );
useEffect(() => { useEffect(() => {
if (!isAdvancedMode && isGrafanaAlertingType) { if (isGrafanaAlertingType && !isAdvancedMode) {
setSimpleCondition(getSimpleConditionFromExpressions(expressionQueries)); setSimpleCondition(getSimpleConditionFromExpressions(expressionQueries));
} }
}, [isAdvancedMode, expressionQueries, isGrafanaAlertingType]); }, [isAdvancedMode, expressionQueries, isGrafanaAlertingType]);
return { isAdvancedMode, simpleCondition, setSimpleCondition }; return { simpleCondition, setSimpleCondition };
}; };