Alerting: Remove reducer when creating and instant (#94246)

* Remove reducer when using a non complex query that is instant

* remove reducer when changing data source

* Fix whenField

* use DataSourceType instead of string literal

* add reducer when using range

* add tests

* use an object for SimpleCondition refids identifiers

* fix threshold expression to point to B after switching back to range

* address pr review comments

* refactor: extract reducer optimization to the reducer

* fix tests

* fix snapshot

* rename constants
This commit is contained in:
Sonia Aguilar 2024-11-15 11:28:54 +01:00 committed by GitHub
parent 20837d3837
commit 76a3d79231
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 348 additions and 57 deletions

View File

@ -17,6 +17,8 @@ import { QueryOperationRow } from 'app/core/components/QueryOperationRow/QueryOp
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
import { AlertDataQuery, AlertQuery } from 'app/types/unified-alerting-dto';
import { getInstantFromDataQuery } from '../../utils/rule-form';
import { AlertQueryOptions, EmptyQueryWrapper, QueryWrapper } from './QueryWrapper';
import { errorFromCurrentCondition, errorFromPreviewData, getThresholdsForQueries } from './util';
@ -234,6 +236,7 @@ function copyModel(item: AlertQuery, settings: DataSourceInstanceSettings): Omit
}
function newModel(item: AlertQuery, settings: DataSourceInstanceSettings): Omit<AlertQuery, 'datasource'> {
const isInstant = getInstantFromDataQuery(item.model, settings.type);
return {
refId: item.refId,
relativeTimeRange: item.relativeTimeRange,
@ -243,6 +246,7 @@ function newModel(item: AlertQuery, settings: DataSourceInstanceSettings): Omit<
refId: item.refId,
hide: false,
datasource: getDataSourceRef(settings),
instant: isInstant,
},
};
}

View File

@ -54,13 +54,7 @@ import { RuleEditorSection } from '../RuleEditorSection';
import { errorFromCurrentCondition, errorFromPreviewData, findRenamedDataQueryReferences, refIdExists } from '../util';
import { CloudDataSourceSelector } from './CloudDataSourceSelector';
import {
getSimpleConditionFromExpressions,
SIMPLE_CONDITION_QUERY_ID,
SIMPLE_CONDITION_REDUCER_ID,
SIMPLE_CONDITION_THRESHOLD_ID,
SimpleConditionEditor,
} from './SimpleCondition';
import { getSimpleConditionFromExpressions, SimpleConditionEditor, SimpleConditionIdentifier } from './SimpleCondition';
import { SmartAlertTypeDetector } from './SmartAlertTypeDetector';
import { DESCRIPTIONS } from './descriptions';
import {
@ -68,6 +62,7 @@ import {
addNewDataQuery,
addNewExpression,
duplicateQuery,
optimizeReduceExpression,
queriesAndExpressionsReducer,
removeExpression,
removeExpressions,
@ -90,19 +85,21 @@ export function areQueriesTransformableToSimpleCondition(
if (dataQueries.length !== 1) {
return false;
}
const singleReduceExpressionInInstantQuery =
'instant' in dataQueries[0].model && dataQueries[0].model.instant && expressionQueries.length === 1;
if (expressionQueries.length !== 2) {
if (expressionQueries.length !== 2 && !singleReduceExpressionInInstantQuery) {
return false;
}
const query = dataQueries[0];
if (query.refId !== SIMPLE_CONDITION_QUERY_ID) {
if (query.refId !== SimpleConditionIdentifier.queryId) {
return false;
}
const reduceExpressionIndex = expressionQueries.findIndex(
(query) => query.model.type === ExpressionQueryType.reduce && query.refId === SIMPLE_CONDITION_REDUCER_ID
(query) => query.model.type === ExpressionQueryType.reduce && query.refId === SimpleConditionIdentifier.reducerId
);
const reduceExpression = expressionQueries.at(reduceExpressionIndex);
const reduceOk =
@ -112,13 +109,16 @@ export function areQueriesTransformableToSimpleCondition(
reduceExpression.model.settings?.mode === undefined);
const thresholdExpressionIndex = expressionQueries.findIndex(
(query) => query.model.type === ExpressionQueryType.threshold && query.refId === SIMPLE_CONDITION_THRESHOLD_ID
(query) =>
query.model.type === ExpressionQueryType.threshold && query.refId === SimpleConditionIdentifier.thresholdId
);
const thresholdExpression = expressionQueries.at(thresholdExpressionIndex);
const conditions = thresholdExpression?.model.conditions ?? [];
const thresholdOk =
thresholdExpression && thresholdExpressionIndex === 1 && conditions[0]?.unloadEvaluator === undefined;
return Boolean(reduceOk) && Boolean(thresholdOk);
const thresholdIndexOk = singleReduceExpressionInInstantQuery
? thresholdExpressionIndex === 0
: thresholdExpressionIndex === 1;
const thresholdOk = thresholdExpression && thresholdIndexOk && conditions[0]?.unloadEvaluator === undefined;
return (Boolean(reduceOk) || Boolean(singleReduceExpressionInInstantQuery)) && Boolean(thresholdOk);
}
interface Props {
@ -200,8 +200,8 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange }: P
}
// we need to be sure the condition is set once we switch to simple mode
if (!isAdvancedMode) {
setValue('condition', SIMPLE_CONDITION_THRESHOLD_ID);
runQueries(getValues('queries'), SIMPLE_CONDITION_THRESHOLD_ID);
setValue('condition', SimpleConditionIdentifier.thresholdId);
runQueries(getValues('queries'), SimpleConditionIdentifier.thresholdId);
} else {
runQueries(getValues('queries'), condition || (getValues('condition') ?? ''));
}
@ -285,6 +285,12 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange }: P
setValue('queries', [...updatedQueries, ...expressionQueries], { shouldValidate: false });
updateExpressionAndDatasource(updatedQueries);
// we only remove or add the reducer(optimize reducer) expression when creating a new alert.
// When editing an alert, we assume the user wants to manually adjust expressions and queries for more control and customization.
if (!editingExistingRule) {
dispatch(optimizeReduceExpression({ updatedQueries, expressionQueries }));
}
dispatch(setDataQueries(updatedQueries));
dispatch(updateExpressionTimeRange());
@ -294,7 +300,7 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange }: P
dispatch(rewireExpressions({ oldRefId, newRefId }));
}
},
[queries, updateExpressionAndDatasource, getValues, setValue]
[queries, updateExpressionAndDatasource, getValues, setValue, editingExistingRule]
);
const onChangeRecordingRulesQueries = useCallback(

View File

@ -17,12 +17,13 @@ import { ExpressionResult } from '../../expressions/Expression';
import { updateExpression } from './reducer';
export const SIMPLE_CONDITION_QUERY_ID = 'A';
export const SIMPLE_CONDITION_REDUCER_ID = 'B';
export const SIMPLE_CONDITION_THRESHOLD_ID = 'C';
export const SimpleConditionIdentifier = {
queryId: 'A',
reducerId: 'B',
thresholdId: 'C',
} as const;
export interface SimpleCondition {
whenField: string;
whenField?: string;
evaluator: {
params: number[];
type: EvalFunction;
@ -106,15 +107,17 @@ export const SimpleConditionEditor = ({
</Text>
</header>
<InlineFieldRow className={styles.condition.container}>
<InlineField label="WHEN">
<Select
options={reducerTypes}
value={reducerTypes.find((o) => o.value === simpleCondition.whenField)}
onChange={onReducerTypeChange}
width={20}
/>
</InlineField>
<InlineField label="OF QUERY">
{simpleCondition.whenField && (
<InlineField label="WHEN">
<Select
options={reducerTypes}
value={reducerTypes.find((o) => o.value === simpleCondition.whenField)}
onChange={onReducerTypeChange}
width={20}
/>
</InlineField>
)}
<InlineField label={simpleCondition.whenField ? 'OF QUERY' : 'WHEN QUERY'}>
<Stack direction="row" gap={1} alignItems="center">
<ThresholdSelect onChange={onEvalFunctionChange} value={thresholdFunction} />
{isRange ? (
@ -156,7 +159,8 @@ function updateReduceExpression(
dispatch: Dispatch<UnknownAction>
) {
const reduceExpression = expressionQueriesList.find(
(query) => query.model.type === ExpressionQueryType.reduce && query.model.refId === SIMPLE_CONDITION_REDUCER_ID
(query) =>
query.model.type === ExpressionQueryType.reduce && query.model.refId === SimpleConditionIdentifier.reducerId
);
const newReduceExpression = reduceExpression
@ -176,7 +180,8 @@ function updateThresholdFunction(
dispatch: Dispatch<UnknownAction>
) {
const thresholdExpression = expressionQueriesList.find(
(query) => query.model.type === ExpressionQueryType.threshold && query.model.refId === SIMPLE_CONDITION_THRESHOLD_ID
(query) =>
query.model.type === ExpressionQueryType.threshold && query.model.refId === SimpleConditionIdentifier.thresholdId
);
const newThresholdExpression = produce(thresholdExpression, (draft) => {
@ -194,7 +199,8 @@ function updateThresholdValue(
dispatch: Dispatch<UnknownAction>
) {
const thresholdExpression = expressionQueriesList.find(
(query) => query.model.type === ExpressionQueryType.threshold && query.model.refId === SIMPLE_CONDITION_THRESHOLD_ID
(query) =>
query.model.type === ExpressionQueryType.threshold && query.model.refId === SimpleConditionIdentifier.thresholdId
);
const newThresholdExpression = produce(thresholdExpression, (draft) => {
@ -207,13 +213,14 @@ function updateThresholdValue(
export function getSimpleConditionFromExpressions(expressions: Array<AlertQuery<ExpressionQuery>>): SimpleCondition {
const reduceExpression = expressions.find(
(query) => query.model.type === ExpressionQueryType.reduce && query.refId === SIMPLE_CONDITION_REDUCER_ID
(query) => query.model.type === ExpressionQueryType.reduce && query.refId === SimpleConditionIdentifier.reducerId
);
const thresholdExpression = expressions.find(
(query) => query.model.type === ExpressionQueryType.threshold && query.refId === SIMPLE_CONDITION_THRESHOLD_ID
(query) =>
query.model.type === ExpressionQueryType.threshold && query.refId === SimpleConditionIdentifier.thresholdId
);
const conditionsFromThreshold = thresholdExpression?.model.conditions ?? [];
const whenField = reduceExpression?.model.reducer ?? ReducerID.last;
const whenField = reduceExpression?.model.reducer;
const params = conditionsFromThreshold[0]?.evaluator?.params
? [...conditionsFromThreshold[0]?.evaluator?.params]
: [0];

View File

@ -1,5 +1,3 @@
// QueryAndExpressionsStep.test.tsx
import { produce } from 'immer';
import { EvalFunction } from 'app/features/alerting/state/alertDef';
@ -24,7 +22,7 @@ describe('areQueriesTransformableToSimpleCondition', () => {
expect(result).toBe(false);
});
it('should return false if the dataQuery refId does not match SIMPLE_CONDITION_QUERY_ID', () => {
it('should return false if the dataQuery refId does not match SimpleConditionIdentifier.queryId', () => {
const dataQueries: Array<AlertQuery<AlertDataQuery | ExpressionQuery>> = [
{ refId: 'notSimpleCondition', datasourceUid: 'abc123', queryType: '', model: { refId: 'notSimpleCondition' } },
];

View File

@ -86,6 +86,70 @@ exports[`Query and expressions reducer should add query 1`] = `
}
`;
exports[`Query and expressions reducer should add reduce expression if there is no reduce expression and the query is not instant 1`] = `
{
"queries": [
{
"datasourceUid": "abc123",
"model": {
"instant": false,
"refId": "A",
},
"queryType": "query",
"refId": "A",
},
{
"datasourceUid": "__expr__",
"model": {
"conditions": [
{
"evaluator": {
"params": [
0,
0,
],
"type": "gt",
},
"operator": {
"type": "and",
},
"query": {
"params": [],
},
"reducer": {
"params": [],
"type": "avg",
},
"type": "query",
},
],
"datasource": {
"name": "Expression",
"type": "__expr__",
"uid": "__expr__",
},
"expression": "A",
"reducer": "last",
"refId": "B",
"type": "reduce",
},
"queryType": "expression",
"refId": "B",
},
{
"datasourceUid": "__expr__",
"model": {
"expression": "B",
"refId": "C",
"type": "threshold",
},
"queryType": "expression",
"refId": "C",
},
],
}
`;
exports[`Query and expressions reducer should duplicate query 1`] = `
{
"queries": [
@ -129,6 +193,31 @@ exports[`Query and expressions reducer should remove an expression or alert quer
}
`;
exports[`Query and expressions reducer should remove first reducer 1`] = `
{
"queries": [
{
"datasourceUid": "abc123",
"model": {
"refId": "A",
},
"queryType": "query",
"refId": "A",
},
{
"datasourceUid": "__expr__",
"model": {
"expression": "A",
"refId": "C",
"type": "threshold",
},
"queryType": "expression",
"refId": "C",
},
],
}
`;
exports[`Query and expressions reducer should rewire expressions 1`] = `
{
"queries": [

View File

@ -1,14 +1,21 @@
import { getDefaultRelativeTimeRange, RelativeTimeRange } from '@grafana/data';
import { getDataSourceSrv } from '@grafana/runtime/src/services/__mocks__/dataSourceSrv';
import { dataSource as expressionDatasource } from 'app/features/expressions/ExpressionDatasource';
import { ExpressionDatasourceUID, ExpressionQuery, ExpressionQueryType } from 'app/features/expressions/types';
import {
ExpressionDatasourceUID,
ExpressionQuery,
ExpressionQueryType,
ReducerMode,
} from 'app/features/expressions/types';
import { defaultCondition } from 'app/features/expressions/utils/expressionTypes';
import { AlertQuery } from 'app/types/unified-alerting-dto';
import { SimpleConditionIdentifier } from './SimpleCondition';
import {
addNewDataQuery,
addNewExpression,
duplicateQuery,
optimizeReduceExpression,
queriesAndExpressionsReducer,
QueriesAndExpressionsState,
removeExpression,
@ -20,6 +27,26 @@ import {
updateExpressionType,
} from './reducer';
const reduceExpression: AlertQuery<ExpressionQuery> = {
refId: SimpleConditionIdentifier.reducerId,
queryType: 'expression',
datasourceUid: '__expr__',
model: {
type: ExpressionQueryType.reduce,
refId: SimpleConditionIdentifier.reducerId,
settings: { mode: ReducerMode.Strict },
},
};
const thresholdExpression: AlertQuery<ExpressionQuery> = {
refId: SimpleConditionIdentifier.thresholdId,
queryType: 'expression',
datasourceUid: '__expr__',
model: {
type: ExpressionQueryType.threshold,
refId: SimpleConditionIdentifier.thresholdId,
},
};
jest.mock('@grafana/runtime', () => ({
...jest.requireActual('@grafana/runtime'),
getDataSourceSrv: getDataSourceSrv,
@ -358,4 +385,70 @@ describe('Query and expressions reducer', () => {
expect(newState).toMatchSnapshot();
});
it('should remove first reducer', () => {
const initialState: QueriesAndExpressionsState = {
queries: [alertQuery, reduceExpression, thresholdExpression],
};
const newState = queriesAndExpressionsReducer(
initialState,
optimizeReduceExpression({
updatedQueries: [alertQuery],
expressionQueries: [reduceExpression, thresholdExpression],
})
);
expect(newState).toMatchSnapshot();
});
it('should not remove first reducer if reducer is not the first expression', () => {
const initialState: QueriesAndExpressionsState = {
queries: [alertQuery, thresholdExpression, reduceExpression],
};
const newState = queriesAndExpressionsReducer(
initialState,
optimizeReduceExpression({
updatedQueries: [alertQuery],
expressionQueries: [thresholdExpression, reduceExpression],
})
);
expect(newState).toEqual(initialState);
});
it('should not remove first reducer if reducer is not the second query', () => {
const initialState: QueriesAndExpressionsState = {
queries: [alertQuery, alertQuery, reduceExpression, thresholdExpression],
};
const newState = queriesAndExpressionsReducer(
initialState,
optimizeReduceExpression({
updatedQueries: [alertQuery, alertQuery],
expressionQueries: [reduceExpression, thresholdExpression],
})
);
expect(newState).toEqual(initialState);
});
it('should add reduce expression if there is no reduce expression and the query is not instant', () => {
const alertQuery: AlertQuery = {
refId: 'A',
queryType: 'query',
datasourceUid: 'abc123',
model: {
refId: 'A',
instant: false,
},
};
const initialState: QueriesAndExpressionsState = {
queries: [alertQuery, thresholdExpression],
};
const newState = queriesAndExpressionsReducer(
initialState,
optimizeReduceExpression({ updatedQueries: [alertQuery], expressionQueries: [thresholdExpression] })
);
expect(newState).toMatchSnapshot();
});
});

View File

@ -6,8 +6,10 @@ import {
getDefaultRelativeTimeRange,
getNextRefId,
rangeUtil,
ReducerID,
RelativeTimeRange,
} from '@grafana/data';
import { getDataSourceSrv } from '@grafana/runtime';
import { dataSource as expressionDatasource } from 'app/features/expressions/ExpressionDatasource';
import { isExpressionQuery } from 'app/features/expressions/guards';
import { ExpressionDatasourceUID, ExpressionQuery, ExpressionQueryType } from 'app/features/expressions/types';
@ -15,11 +17,13 @@ import { defaultCondition } from 'app/features/expressions/utils/expressionTypes
import { AlertQuery } from 'app/types/unified-alerting-dto';
import { logError } from '../../../Analytics';
import { getDefaultOrFirstCompatibleDataSource } from '../../../utils/datasource';
import { getDefaultQueries } from '../../../utils/rule-form';
import { DataSourceType, getDefaultOrFirstCompatibleDataSource } from '../../../utils/datasource';
import { getDefaultQueries, getInstantFromDataQuery } from '../../../utils/rule-form';
import { createDagFromQueries, getOriginOfRefId } from '../dag';
import { queriesWithUpdatedReferences, refIdExists } from '../util';
import { SimpleConditionIdentifier } from './SimpleCondition';
export interface QueriesAndExpressionsState {
queries: AlertQuery[];
}
@ -60,7 +64,9 @@ export const updateMaxDataPoints = createAction<{ refId: string; maxDataPoints:
export const updateMinInterval = createAction<{ refId: string; minInterval: string }>('updateMinInterval');
export const resetToSimpleCondition = createAction('resetToSimpleCondition');
export const optimizeReduceExpression = createAction<{ updatedQueries: AlertQuery[]; expressionQueries: AlertQuery[] }>(
'optimizeReduceExpression'
);
export const setRecordingRulesQueries = createAction<{ recordingRuleQueries: AlertQuery[]; expression: string }>(
'setRecordingRulesQueries'
);
@ -225,6 +231,71 @@ export const queriesAndExpressionsReducer = createReducer(initialState, (builder
.addCase(rewireExpressions, (state, { payload }) => {
state.queries = queriesWithUpdatedReferences(state.queries, payload.oldRefId, payload.newRefId);
})
.addCase(optimizeReduceExpression, (state, { payload }) => {
const { updatedQueries, expressionQueries } = payload;
if (updatedQueries.length !== 1) {
// we only optimize when we have one data query
return;
}
//sometimes we dont have data source in the model yet
const getDataSourceSettingsForFirstQuery = getDataSourceSrv().getInstanceSettings(
updatedQueries[0].datasourceUid
);
if (!getDataSourceSettingsForFirstQuery) {
return;
}
const type = getDataSourceSettingsForFirstQuery?.type;
const firstQueryIsPromOrLoki = type === DataSourceType.Prometheus || type === DataSourceType.Loki;
const isInstant = getInstantFromDataQuery(updatedQueries[0].model, type);
const shouldRemoveReducer =
firstQueryIsPromOrLoki && updatedQueries.length === 1 && isInstant && expressionQueries.length === 2;
const onlyOneExpressionNotReducer =
expressionQueries.length === 1 &&
'type' in expressionQueries[0].model &&
expressionQueries[0].model.type !== ExpressionQueryType.reduce;
// we only add the reduce expression if we have one data query and one expression query. For other cases we don't do anything,
// and let the user add the reducer manually.
const shouldAddReduceExpression =
firstQueryIsPromOrLoki && updatedQueries.length === 1 && !isInstant && onlyOneExpressionNotReducer;
if (shouldRemoveReducer) {
const reduceExpressionIndex = state.queries.findIndex(
(query) => isExpressionQuery(query.model) && query.model.type === ExpressionQueryType.reduce
);
if (reduceExpressionIndex === 1) {
// means the reduce expression is the second query
state.queries.splice(reduceExpressionIndex, 1);
state.queries[1].model.expression = SimpleConditionIdentifier.queryId;
}
}
if (shouldAddReduceExpression) {
// add reducer to the second position
// we only update the refid and the model to point to the reducer expression
state.queries[1].model.expression = SimpleConditionIdentifier.reducerId;
// insert in second position the reducer expression
state.queries.splice(1, 0, {
datasourceUid: ExpressionDatasourceUID,
model: expressionDatasource.newQuery({
type: ExpressionQueryType.reduce,
reducer: ReducerID.last,
conditions: [{ ...defaultCondition, query: { params: [] } }],
expression: SimpleConditionIdentifier.queryId,
refId: SimpleConditionIdentifier.reducerId,
}),
refId: SimpleConditionIdentifier.reducerId,
queryType: 'expression',
});
}
})
.addCase(updateExpressionType, (state, action) => {
state.queries = state.queries.map((query) => {
return query.refId === action.payload.refId

View File

@ -64,11 +64,7 @@ import {
import { DashboardSearchItem, DashboardSearchItemType } from '../../search/types';
import {
SIMPLE_CONDITION_QUERY_ID,
SIMPLE_CONDITION_REDUCER_ID,
SIMPLE_CONDITION_THRESHOLD_ID,
} from './components/rule-editor/query-and-alert-condition/SimpleCondition';
import { SimpleConditionIdentifier } from './components/rule-editor/query-and-alert-condition/SimpleCondition';
import { parsePromQLStyleMatcherLooseSafe } from './utils/matchers';
let nextDataSourceId = 1;
@ -855,29 +851,29 @@ export function mockDashboardDto(
}
export const dataQuery: AlertQuery<AlertDataQuery | ExpressionQuery> = {
refId: SIMPLE_CONDITION_QUERY_ID,
refId: SimpleConditionIdentifier.queryId,
datasourceUid: 'abc123',
queryType: '',
model: { refId: SIMPLE_CONDITION_QUERY_ID },
model: { refId: SimpleConditionIdentifier.queryId },
};
export const reduceExpression: AlertQuery<ExpressionQuery> = {
refId: SIMPLE_CONDITION_REDUCER_ID,
refId: SimpleConditionIdentifier.reducerId,
queryType: 'expression',
datasourceUid: '__expr__',
model: {
type: ExpressionQueryType.reduce,
refId: SIMPLE_CONDITION_REDUCER_ID,
refId: SimpleConditionIdentifier.reducerId,
settings: { mode: ReducerMode.Strict },
reducer: ReducerID.last,
},
};
export const thresholdExpression: AlertQuery<ExpressionQuery> = {
refId: SIMPLE_CONDITION_THRESHOLD_ID,
refId: SimpleConditionIdentifier.thresholdId,
queryType: 'expression',
datasourceUid: '__expr__',
model: {
type: ExpressionQueryType.threshold,
refId: SIMPLE_CONDITION_THRESHOLD_ID,
refId: SimpleConditionIdentifier.thresholdId,
},
};

View File

@ -53,7 +53,12 @@ import {
import { getRulesAccess } from './access-control';
import { Annotation, defaultAnnotations } from './constants';
import { getDefaultOrFirstCompatibleDataSource, GRAFANA_RULES_SOURCE_NAME, isGrafanaRulesSource } from './datasource';
import {
DataSourceType,
getDefaultOrFirstCompatibleDataSource,
GRAFANA_RULES_SOURCE_NAME,
isGrafanaRulesSource,
} from './datasource';
import { arrayToRecord, recordToArray } from './misc';
import {
isAlertingRulerRule,
@ -499,7 +504,6 @@ export function recordingRulerRuleToRuleForm(
export const getDefaultQueries = (isRecordingRule = false): AlertQuery[] => {
const dataSource = getDefaultOrFirstCompatibleDataSource();
if (!dataSource) {
const expressions = isRecordingRule ? getDefaultExpressionsForRecording('A') : getDefaultExpressions('A', 'B');
return [...expressions];
@ -507,6 +511,7 @@ export const getDefaultQueries = (isRecordingRule = false): AlertQuery[] => {
const relativeTimeRange = getDefaultRelativeTimeRange();
const expressions = isRecordingRule ? getDefaultExpressionsForRecording('B') : getDefaultExpressions('B', 'C');
const isLokiOrPrometheus = dataSource?.type === DataSourceType.Prometheus || dataSource?.type === DataSourceType.Loki;
return [
{
refId: 'A',
@ -515,6 +520,7 @@ export const getDefaultQueries = (isRecordingRule = false): AlertQuery[] => {
relativeTimeRange,
model: {
refId: 'A',
instant: isLokiOrPrometheus ? true : undefined,
},
},
...expressions,
@ -899,3 +905,24 @@ export const ignoreHiddenQueries = (ruleDefinition: RuleFormValues): RuleFormVal
export function formValuesFromExistingRule(rule: RuleWithLocation<RulerRuleDTO>) {
return ignoreHiddenQueries(rulerRuleToFormValues(rule));
}
export function getInstantFromDataQuery(model: AlertDataQuery, type: string): boolean | undefined {
// if the datasource is not prometheus or loki, instant is defined in the model or defaults to undefined
if (type !== DataSourceType.Prometheus && type !== DataSourceType.Loki) {
if ('instant' in model) {
return model.instant;
} else {
if ('queryType' in model) {
return model.queryType === 'instant';
} else {
return undefined;
}
}
}
// if the datasource is prometheus or loki, instant is defined in the model, or defaults to true
const isInstantForPrometheus = 'instant' in model && model.instant !== undefined ? model.instant : true;
const isInstantForLoki = 'queryType' in model && model.queryType !== undefined ? model.queryType === 'instant' : true;
const isInstant = type === DataSourceType.Prometheus ? isInstantForPrometheus : isInstantForLoki;
return isInstant;
}