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

pull/52102/head
Konrad Lalik 3 years ago committed by GitHub
parent 3761e9efa8
commit e46ee78bed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      public/app/features/alerting/unified/PanelAlertTabContent.test.tsx
  2. 7
      public/app/features/alerting/unified/components/rule-editor/QueryEditor.tsx
  3. 1
      public/app/features/alerting/unified/utils/rule-form.ts
  4. 4
      public/app/features/expressions/ExpressionDatasource.ts
  5. 89
      public/app/features/expressions/ExpressionQueryEditor.tsx
  6. 5
      public/app/features/expressions/components/ClassicConditions.tsx
  7. 7
      public/app/features/expressions/utils/expressionTypes.ts
  8. 1
      public/app/types/unified-alerting-dto.ts

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

@ -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,
}),
})
);

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

@ -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,
};
}
}

@ -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>>;
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;
renderExpressionType() {
const { onChange, onRunQuery, query, queries } = this.props;
// 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);
return (
<div>
<InlineField label="Operation" labelWidth={labelWidth}>
<Select options={gelTypes} value={selected} onChange={this.onSelectExpressionType} width={25} />
</InlineField>
{this.renderExpressionType()}
</div>
);
}
};
const selected = gelTypes.find((o) => o.value === query.type);
return (
<div>
<InlineField label="Operation" labelWidth={labelWidth}>
<Select options={gelTypes} value={selected} onChange={onSelectExpressionType} width={25} />
</InlineField>
{renderExpressionType()}
</div>
);
}

@ -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],
});
}
};

@ -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:

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

Loading…
Cancel
Save