Alerting: Hide reducer hint for alert creation editor (#98410)

This commit is contained in:
Gilles De Mey 2024-12-31 11:58:01 +01:00 committed by GitHub
parent bc96da3a95
commit 0e4b503352
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 54 additions and 27 deletions

View File

@ -122,5 +122,9 @@ describe('Directed acyclic graph', () => {
expect(() => dag.link('A', 'B')).toThrow('cannot link A to B since it would create a cycle');
expect(() => dag.link('A', 'E')).toThrow('cannot link A to E since it would create a cycle');
});
it('should return undefined for unknown node id', () => {
expect(dag.getNode('404')).toBeUndefined();
});
});
});

View File

@ -252,7 +252,7 @@ export class Graph {
return new Edge();
}
getNode(name: string): Node {
getNode(name: string): Node | undefined {
return this.nodes[name];
}
}

View File

@ -3,7 +3,15 @@ import { uniqueId } from 'lodash';
import { FC, useCallback, useState } from 'react';
import { useFormContext } from 'react-hook-form';
import { DataFrame, GrafanaTheme2, LoadingState, PanelData, dateTimeFormat, isTimeSeriesFrames } from '@grafana/data';
import {
CoreApp,
DataFrame,
GrafanaTheme2,
LoadingState,
PanelData,
dateTimeFormat,
isTimeSeriesFrames,
} from '@grafana/data';
import { Alert, AutoSizeInput, Button, IconButton, Stack, Text, clearButtonStyles, useStyles2 } from '@grafana/ui';
import { ClassicConditions } from 'app/features/expressions/components/ClassicConditions';
import { Math } from 'app/features/expressions/components/Math';
@ -95,7 +103,15 @@ export const Expression: FC<ExpressionProps> = ({
return <Math onChange={onChangeQuery} query={query} labelWidth={'auto'} onRunQuery={() => {}} />;
case ExpressionQueryType.reduce:
return <Reduce onChange={onChangeQuery} refIds={availableRefIds} labelWidth={'auto'} query={query} />;
return (
<Reduce
onChange={onChangeQuery}
refIds={availableRefIds}
labelWidth={'auto'}
app={CoreApp.UnifiedAlerting}
query={query}
/>
);
case ExpressionQueryType.resample:
return <Resample onChange={onChangeQuery} query={query} labelWidth={'auto'} refIds={availableRefIds} />;

View File

@ -56,21 +56,21 @@ describe('working with dag', () => {
dag.getNode('D');
}).not.toThrow();
expect(dag.getNode('A').inputEdges).toHaveLength(0);
expect(dag.getNode('A').outputEdges).toHaveLength(0);
expect(dag.getNode('A')!.inputEdges).toHaveLength(0);
expect(dag.getNode('A')!.outputEdges).toHaveLength(0);
expect(dag.getNode('B').inputEdges).toHaveLength(0);
expect(dag.getNode('B').outputEdges).toHaveLength(2);
expect(dag.getNode('B').outputEdges[0].outputNode).toHaveProperty('name', 'C');
expect(dag.getNode('B').outputEdges[1].outputNode).toHaveProperty('name', 'D');
expect(dag.getNode('B')!.inputEdges).toHaveLength(0);
expect(dag.getNode('B')!.outputEdges).toHaveLength(2);
expect(dag.getNode('B')!.outputEdges[0].outputNode).toHaveProperty('name', 'C');
expect(dag.getNode('B')!.outputEdges[1].outputNode).toHaveProperty('name', 'D');
expect(dag.getNode('C').inputEdges).toHaveLength(1);
expect(dag.getNode('C').inputEdges[0].inputNode).toHaveProperty('name', 'B');
expect(dag.getNode('C').outputEdges).toHaveLength(0);
expect(dag.getNode('C')!.inputEdges).toHaveLength(1);
expect(dag.getNode('C')!.inputEdges[0].inputNode).toHaveProperty('name', 'B');
expect(dag.getNode('C')!.outputEdges).toHaveLength(0);
expect(dag.getNode('D').inputEdges).toHaveLength(1);
expect(dag.getNode('D').inputEdges[0].inputNode).toHaveProperty('name', 'B');
expect(dag.getNode('D').outputEdges).toHaveLength(0);
expect(dag.getNode('D')!.inputEdges).toHaveLength(1);
expect(dag.getNode('D')!.inputEdges[0].inputNode).toHaveProperty('name', 'B');
expect(dag.getNode('D')!.outputEdges).toHaveLength(0);
});
test('data queries cannot have references', () => {

View File

@ -66,6 +66,9 @@ export const getDescendants = memoize(_getDescendants, (refId, graph) => refId +
export function _getOriginsOfRefId(refId: string, graph: Graph): string[] {
const node = graph.getNode(refId);
if (!node) {
return [];
}
const origins: Node[] = [];
@ -92,6 +95,10 @@ export function _getOriginsOfRefId(refId: string, graph: Graph): string[] {
// get all children (and children's children etc) from a given node
export function _getDescendants(refId: string, graph: Graph): string[] {
const node = graph.getNode(refId);
if (!node) {
return [];
}
const descendants: Node[] = [];
// recurse through "node > outputEdges > outputNode"

View File

@ -58,7 +58,7 @@ function useExpressionsCache() {
}
export function ExpressionQueryEditor(props: Props) {
const { query, queries, onRunQuery, onChange } = props;
const { query, queries, onRunQuery, onChange, app } = props;
const { getCachedExpression, setCachedExpression } = useExpressionsCache();
useEffect(() => {
@ -83,7 +83,7 @@ export function ExpressionQueryEditor(props: Props) {
return <Math onChange={onChange} query={query} labelWidth={labelWidth} onRunQuery={onRunQuery} />;
case ExpressionQueryType.reduce:
return <Reduce refIds={refIds} onChange={onChange} labelWidth={labelWidth} query={query} />;
return <Reduce refIds={refIds} onChange={onChange} labelWidth={labelWidth} query={query} app={app} />;
case ExpressionQueryType.resample:
return <Resample query={query} labelWidth={labelWidth} onChange={onChange} refIds={refIds} />;

View File

@ -1,19 +1,20 @@
import * as React from 'react';
import { SelectableValue } from '@grafana/data';
import { InlineField, InlineFieldRow, Input, Select, Alert } from '@grafana/ui';
import { CoreApp, SelectableValue } from '@grafana/data';
import { Alert, InlineField, InlineFieldRow, Input, Select, TextLink } from '@grafana/ui';
import { Trans, t } from 'app/core/internationalization';
import { ExpressionQuery, ExpressionQuerySettings, ReducerMode, reducerModes, reducerTypes } from '../types';
interface Props {
app?: CoreApp;
labelWidth?: number | 'auto';
refIds: Array<SelectableValue<string>>;
query: ExpressionQuery;
onChange: (query: ExpressionQuery) => void;
}
export const Reduce = ({ labelWidth = 'auto', onChange, refIds, query }: Props) => {
export const Reduce = ({ labelWidth = 'auto', onChange, app, refIds, query }: Props) => {
const reducer = reducerTypes.find((o) => o.value === query.reducer);
const onRefIdChange = (value: SelectableValue<string>) => {
@ -72,22 +73,21 @@ export const Reduce = ({ labelWidth = 'auto', onChange, refIds, query }: Props)
);
};
// for Alerting we really don't want to add additional confusing messages that would be unhelpful to the majority of our users
const strictModeNotification = () => {
if (mode !== ReducerMode.Strict) {
const isWithinAlerting = app === CoreApp.UnifiedAlerting;
if (mode !== ReducerMode.Strict || isWithinAlerting) {
return null;
}
return (
<Alert title={t('reduce.strictMode.title', 'Strict Mode Behaviour')} severity="info">
<Trans i18nKey="reduce.strictMode.description">
When <code>Reduce Strict mode</code> is used, the <code>fill(null)</code> function (InfluxQL) will result in{' '}
<code>NaN</code>.{' '}
<a
href="https://grafana.com/docs/grafana/latest/panels-visualizations/query-transform-data/expression-queries/#sum"
target="_blank"
rel="noopener noreferrer"
>
<TextLink href="https://grafana.com/docs/grafana/latest/panels-visualizations/query-transform-data/expression-queries/#reduction-modes">
See the documentation for more details.
</a>
</TextLink>
</Trans>
</Alert>
);