Alerting: Remove threshold as default expression for grafana-managed recording rules (#94949)

* remove threshold as default expression for grafana-managed recording rule

* fix

* remove eslint disable line
pull/94979/head
Sonia Aguilar 1 year ago committed by GitHub
parent b420fbe940
commit bef9ff3b1a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 68
      public/app/features/alerting/unified/components/expressions/Expression.tsx
  2. 6
      public/app/features/alerting/unified/components/rule-editor/alert-rule-form/AlertRuleForm.tsx
  3. 49
      public/app/features/alerting/unified/utils/rule-form.ts

@ -20,6 +20,8 @@ import {
import { AlertQuery, PromAlertingRuleState } from 'app/types/unified-alerting-dto';
import { usePagination } from '../../hooks/usePagination';
import { RuleFormValues } from '../../types/rule-form';
import { isGrafanaRecordingRuleByType } from '../../utils/rules';
import { PopupCard } from '../HoverCard';
import { Spacer } from '../Spacer';
import { AlertStateTag } from '../rules/AlertStateTag';
@ -58,7 +60,9 @@ export const Expression: FC<ExpressionProps> = ({
const queryType = query?.type;
const { setError, clearErrors } = useFormContext();
const { setError, clearErrors, watch } = useFormContext<RuleFormValues>();
const type = watch('type');
const isGrafanaRecordingRule = type ? isGrafanaRecordingRuleByType(type) : false;
const onQueriesValidationError = useCallback(
(errorMsg: string | undefined) => {
@ -158,20 +162,25 @@ export const Expression: FC<ExpressionProps> = ({
</div>
{hasResults && (
<>
<ExpressionResult series={series} isAlertCondition={isAlertCondition} />
<div className={styles.footer}>
<Stack direction="row" alignItems="center">
<Spacer />
<PreviewSummary
isCondition={Boolean(isAlertCondition)}
firing={groupedByState[PromAlertingRuleState.Firing].length}
normal={groupedByState[PromAlertingRuleState.Inactive].length}
seriesCount={seriesCount}
/>
</Stack>
</div>
<ExpressionResult
series={series}
isAlertCondition={isAlertCondition}
isRecordingRule={isGrafanaRecordingRule}
/>
{!isGrafanaRecordingRule && (
<div className={styles.footer}>
<Stack direction="row" alignItems="center">
<Spacer />
<PreviewSummary
isCondition={Boolean(isAlertCondition)}
firing={groupedByState[PromAlertingRuleState.Firing].length}
normal={groupedByState[PromAlertingRuleState.Inactive].length}
seriesCount={seriesCount}
/>
</Stack>
</div>
)}
</>
)}
</div>
@ -182,9 +191,10 @@ export const Expression: FC<ExpressionProps> = ({
interface ExpressionResultProps {
series: DataFrame[];
isAlertCondition?: boolean;
isRecordingRule?: boolean;
}
export const PAGE_SIZE = 20;
export const ExpressionResult: FC<ExpressionResultProps> = ({ series, isAlertCondition }) => {
export const ExpressionResult: FC<ExpressionResultProps> = ({ series, isAlertCondition, isRecordingRule = false }) => {
const { pageItems, previousPage, nextPage, numberOfPages, pageStart, pageEnd } = usePagination(series, 1, PAGE_SIZE);
const styles = useStyles2(getStyles);
@ -212,7 +222,13 @@ export const ExpressionResult: FC<ExpressionResultProps> = ({ series, isAlertCon
!isTimeSeriesResults &&
pageItems.map((frame, index) => (
// There's no way to uniquely identify a frame that doesn't cause render bugs :/ (Gilles)
<FrameRow key={uniqueId()} frame={frame} index={pageStart + index} isAlertCondition={isAlertCondition} />
<FrameRow
key={uniqueId()}
frame={frame}
index={pageStart + index}
isAlertCondition={isAlertCondition}
isRecordingRule={isRecordingRule}
/>
))}
{emptyResults && <div className={cx(styles.expression.noData, styles.mutedText)}>No data</div>}
{shouldShowPagination && (
@ -353,6 +369,7 @@ const Header: FC<HeaderProps> = ({
interface FrameProps extends Pick<ExpressionProps, 'isAlertCondition'> {
frame: DataFrame;
index: number;
isRecordingRule?: boolean;
}
const OpeningBracket = () => <span>{'{'}</span>;
@ -361,7 +378,7 @@ const ClosingBracket = () => <span>{'}'}</span>;
const Quote = () => <span>&quot;</span>;
const Equals = () => <span>{'='}</span>;
const FrameRow: FC<FrameProps> = ({ frame, index, isAlertCondition }) => {
function FrameRow({ frame, index, isAlertCondition, isRecordingRule }: FrameProps) {
const styles = useStyles2(getStyles);
const name = getSeriesName(frame) || 'Series ' + index;
@ -374,6 +391,7 @@ const FrameRow: FC<FrameProps> = ({ frame, index, isAlertCondition }) => {
const showNormal = isAlertCondition && value === 0;
const title = `${hasLabels ? '' : name}${hasLabels ? `{${formatLabels(labelsRecord)}}` : ''}`;
const shouldRenderSumary = !isRecordingRule;
return (
<div className={styles.expression.resultsRow}>
@ -401,14 +419,18 @@ const FrameRow: FC<FrameProps> = ({ frame, index, isAlertCondition }) => {
</Text>
</div>
<div className={styles.expression.resultValue}>{value}</div>
{showFiring && <AlertStateTag state={PromAlertingRuleState.Firing} size="sm" />}
{showNormal && <AlertStateTag state={PromAlertingRuleState.Inactive} size="sm" />}
{shouldRenderSumary && (
<>
{showFiring && <AlertStateTag state={PromAlertingRuleState.Firing} size="sm" />}
{showNormal && <AlertStateTag state={PromAlertingRuleState.Inactive} size="sm" />}
</>
)}
</Stack>
</div>
);
};
const TimeseriesRow: FC<FrameProps & { index: number }> = ({ frame, index }) => {
}
interface TimeseriesRowProps extends Omit<FrameProps, 'isRecordingRule'> {}
const TimeseriesRow: FC<TimeseriesRowProps & { index: number }> = ({ frame, index }) => {
const styles = useStyles2(getStyles);
const valueField = frame.fields[1]; // field 0 is "time", field 1 is "value"

@ -53,6 +53,7 @@ import {
} from '../../../utils/rule-form';
import * as ruleId from '../../../utils/rule-id';
import { fromRulerRule, fromRulerRuleAndRuleGroupIdentifier, stringifyIdentifier } from '../../../utils/rule-id';
import { isGrafanaRecordingRuleByType } from '../../../utils/rules';
import { createRelativeUrl } from '../../../utils/url';
import { GrafanaRuleExporter } from '../../export/GrafanaRuleExporter';
import { AlertRuleNameAndMetric } from '../AlertRuleNameInput';
@ -102,12 +103,13 @@ export const AlertRuleForm = ({ existing, prefill }: Props) => {
if (queryParams.has('defaults')) {
return formValuesFromQueryParams(queryParams.get('defaults') ?? '', ruleType);
}
const defaultRuleType = ruleType || RuleFormType.grafana;
return {
...getDefaultFormValues(),
condition: 'C',
queries: getDefaultQueries(),
type: ruleType || RuleFormType.grafana,
queries: getDefaultQueries(isGrafanaRecordingRuleByType(defaultRuleType)),
type: defaultRuleType,
evaluateEvery: evaluateEvery,
};
}, [existing, prefill, queryParams, evaluateEvery, ruleType]);

@ -497,14 +497,16 @@ export function recordingRulerRuleToRuleForm(
};
}
export const getDefaultQueries = (): AlertQuery[] => {
export const getDefaultQueries = (isRecordingRule = false): AlertQuery[] => {
const dataSource = getDefaultOrFirstCompatibleDataSource();
if (!dataSource) {
return [...getDefaultExpressions('A', 'B')];
const expressions = isRecordingRule ? getDefaultExpressionsForRecording('A') : getDefaultExpressions('A', 'B');
return [...expressions];
}
const relativeTimeRange = getDefaultRelativeTimeRange();
const expressions = isRecordingRule ? getDefaultExpressionsForRecording('B') : getDefaultExpressions('B', 'C');
return [
{
refId: 'A',
@ -515,7 +517,7 @@ export const getDefaultQueries = (): AlertQuery[] => {
refId: 'A',
},
},
...getDefaultExpressions('B', 'C'),
...expressions,
];
};
@ -536,7 +538,6 @@ export const getDefaultRecordingRulesQueries = (
},
];
};
const getDefaultExpressions = (...refIds: [string, string]): AlertQuery[] => {
const refOne = refIds[0];
const refTwo = refIds[1];
@ -615,6 +616,46 @@ const getDefaultExpressions = (...refIds: [string, string]): AlertQuery[] => {
},
];
};
const getDefaultExpressionsForRecording = (refOne: string): AlertQuery[] => {
const reduceExpression: ExpressionQuery = {
refId: refOne,
type: ExpressionQueryType.reduce,
datasource: {
uid: ExpressionDatasourceUID,
type: ExpressionDatasourceRef.type,
},
conditions: [
{
type: 'query',
evaluator: {
params: [],
type: EvalFunction.IsAbove,
},
operator: {
type: 'and',
},
query: {
params: [refOne],
},
reducer: {
params: [],
type: 'last',
},
},
],
reducer: 'last',
expression: 'A',
};
return [
{
refId: refOne,
datasourceUid: ExpressionDatasourceUID,
queryType: '',
model: reduceExpression,
},
];
};
const dataQueriesToGrafanaQueries = async (
queries: DataQuery[],

Loading…
Cancel
Save