Alerting: Add default input parameters for expressions (#51810)

This commit is contained in:
Konrad Lalik 2022-07-12 11:50:58 +02:00 committed by GitHub
parent 3761e9efa8
commit e46ee78bed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 85 additions and 26 deletions

View File

@ -328,6 +328,7 @@ describe('PanelAlertTabContent', () => {
model: {
refId: 'B',
hide: false,
expression: 'A',
type: 'classic_conditions',
datasource: {
type: ExpressionDatasourceRef.type,

View File

@ -35,6 +35,7 @@ interface Props {
interface State {
panelDataByRefId: Record<string, PanelData>;
}
export class QueryEditor extends PureComponent<Props, State> {
private runner: AlertingQueryRunner;
private queries: AlertQuery[];
@ -100,12 +101,16 @@ export class QueryEditor extends PureComponent<Props, State> {
onNewExpressionQuery = () => {
const { queries } = this;
const lastQuery = queries.at(-1);
const defaultParams = lastQuery ? [lastQuery.refId] : [];
this.onChangeQueries(
addQuery(queries, {
datasourceUid: ExpressionDatasourceUID,
model: expressionDatasource.newQuery({
type: ExpressionQueryType.classic,
conditions: [defaultCondition],
conditions: [{ ...defaultCondition, query: { params: defaultParams } }],
expression: lastQuery?.refId,
}),
})
);

View File

@ -220,6 +220,7 @@ const getDefaultExpression = (refId: string): AlertQuery => {
},
},
],
expression: 'A',
};
return {

View File

@ -53,9 +53,9 @@ export class ExpressionDatasourceApi extends DataSourceWithBackend<ExpressionQue
newQuery(query?: Partial<ExpressionQuery>): ExpressionQuery {
return {
refId: '--', // Replaced with query
type: query?.type ?? ExpressionQueryType.math,
datasource: ExpressionDatasourceRef,
conditions: query?.conditions ?? undefined,
type: query?.type ?? ExpressionQueryType.math,
...query,
};
}
}

View File

@ -1,4 +1,4 @@
import React, { PureComponent } from 'react';
import React, { useCallback, useEffect, useRef } from 'react';
import { DataSourceApi, QueryEditorProps, SelectableValue } from '@grafana/data';
import { InlineField, Select } from '@grafana/ui';
@ -13,15 +13,61 @@ import { getDefaults } from './utils/expressionTypes';
type Props = QueryEditorProps<DataSourceApi<ExpressionQuery>, ExpressionQuery>;
const labelWidth = 14;
export class ExpressionQueryEditor extends PureComponent<Props> {
onSelectExpressionType = (item: SelectableValue<ExpressionQueryType>) => {
const { query, onChange } = this.props;
onChange(getDefaults({ ...query, type: item.value! }));
};
type NonClassicExpressionType = Exclude<ExpressionQueryType, ExpressionQueryType.classic>;
type ExpressionTypeConfigStorage = Partial<Record<NonClassicExpressionType, string>>;
renderExpressionType() {
const { onChange, onRunQuery, query, queries } = this.props;
function useExpressionsCache() {
const expressionCache = useRef<ExpressionTypeConfigStorage>({});
const getCachedExpression = useCallback((queryType: ExpressionQueryType) => {
switch (queryType) {
case ExpressionQueryType.math:
case ExpressionQueryType.reduce:
case ExpressionQueryType.resample:
return expressionCache.current[queryType];
case ExpressionQueryType.classic:
return undefined;
}
}, []);
const setCachedExpression = useCallback((queryType: ExpressionQueryType, value: string | undefined) => {
switch (queryType) {
case ExpressionQueryType.math:
expressionCache.current.math = value;
break;
// We want to use the same value for Reduce and Resample
case ExpressionQueryType.reduce:
case ExpressionQueryType.resample:
expressionCache.current.reduce = value;
expressionCache.current.resample = value;
break;
}
}, []);
return { getCachedExpression, setCachedExpression };
}
export function ExpressionQueryEditor(props: Props) {
const { query, queries, onRunQuery, onChange } = props;
const { getCachedExpression, setCachedExpression } = useExpressionsCache();
useEffect(() => {
setCachedExpression(query.type, query.expression);
}, [query.expression, query.type, setCachedExpression]);
const onSelectExpressionType = useCallback(
(item: SelectableValue<ExpressionQueryType>) => {
const cachedExpression = getCachedExpression(item.value!);
const defaults = getDefaults({ ...query, type: item.value! });
onChange({ ...defaults, expression: cachedExpression ?? defaults.expression });
},
[query, onChange, getCachedExpression]
);
const renderExpressionType = () => {
const refIds = queries!.filter((q) => query.refId !== q.refId).map((q) => ({ value: q.refId, label: q.refId }));
switch (query.type) {
@ -37,19 +83,16 @@ export class ExpressionQueryEditor extends PureComponent<Props> {
case ExpressionQueryType.classic:
return <ClassicConditions onChange={onChange} query={query} refIds={refIds} />;
}
}
};
render() {
const { query } = this.props;
const selected = gelTypes.find((o) => o.value === query.type);
const selected = gelTypes.find((o) => o.value === query.type);
return (
<div>
<InlineField label="Operation" labelWidth={labelWidth}>
<Select options={gelTypes} value={selected} onChange={this.onSelectExpressionType} width={25} />
</InlineField>
{this.renderExpressionType()}
</div>
);
}
return (
<div>
<InlineField label="Operation" labelWidth={labelWidth}>
<Select options={gelTypes} value={selected} onChange={onSelectExpressionType} width={25} />
</InlineField>
{renderExpressionType()}
</div>
);
}

View File

@ -26,9 +26,12 @@ export const ClassicConditions: FC<Props> = ({ onChange, query, refIds }) => {
const onAddCondition = () => {
if (query.conditions) {
const lastParams = query.conditions.at(-1)?.query?.params ?? [];
const newCondition: ClassicCondition = { ...defaultCondition, query: { params: lastParams } };
onChange({
...query,
conditions: query.conditions.length > 0 ? [...query.conditions, defaultCondition] : [defaultCondition],
conditions: query.conditions.length > 0 ? [...query.conditions, newCondition] : [newCondition],
});
}
};

View File

@ -9,7 +9,7 @@ export const getDefaults = (query: ExpressionQuery) => {
if (!query.reducer) {
query.reducer = ReducerID.mean;
}
query.expression = undefined;
break;
case ExpressionQueryType.resample:
@ -24,10 +24,15 @@ export const getDefaults = (query: ExpressionQuery) => {
query.reducer = undefined;
break;
case ExpressionQueryType.math:
query.expression = undefined;
break;
case ExpressionQueryType.classic:
if (!query.conditions) {
query.conditions = [defaultCondition];
}
break;
default:

View File

@ -159,6 +159,7 @@ export enum GrafanaAlertStateDecision {
export interface AlertDataQuery extends DataQuery {
maxDataPoints?: number;
intervalMs?: number;
expression?: string;
}
export interface AlertQuery {