mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Allow executing "hidden" queries (#70064)
This commit is contained in:
parent
6e2c811fd8
commit
7952907e48
@ -1905,8 +1905,7 @@ exports[`better eslint`] = {
|
|||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
|
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
|
||||||
],
|
],
|
||||||
"public/app/features/alerting/unified/components/rule-editor/AlertRuleForm.tsx:5381": [
|
"public/app/features/alerting/unified/components/rule-editor/AlertRuleForm.tsx:5381": [
|
||||||
[0, 0, 0, "Do not use any type assertions.", "0"],
|
[0, 0, 0, "Do not use any type assertions.", "0"]
|
||||||
[0, 0, 0, "Do not use any type assertions.", "1"]
|
|
||||||
],
|
],
|
||||||
"public/app/features/alerting/unified/components/rule-editor/AnnotationKeyInput.tsx:5381": [
|
"public/app/features/alerting/unified/components/rule-editor/AnnotationKeyInput.tsx:5381": [
|
||||||
[0, 0, 0, "Do not use any type assertions.", "0"]
|
[0, 0, 0, "Do not use any type assertions.", "0"]
|
||||||
|
@ -67,7 +67,6 @@ exports[`PanelAlertTabContent Will render alerts belonging to panel and a button
|
|||||||
"uid": "__expr__",
|
"uid": "__expr__",
|
||||||
},
|
},
|
||||||
"expression": "A",
|
"expression": "A",
|
||||||
"hide": false,
|
|
||||||
"reducer": "last",
|
"reducer": "last",
|
||||||
"refId": "B",
|
"refId": "B",
|
||||||
"type": "reduce",
|
"type": "reduce",
|
||||||
@ -106,7 +105,6 @@ exports[`PanelAlertTabContent Will render alerts belonging to panel and a button
|
|||||||
"uid": "__expr__",
|
"uid": "__expr__",
|
||||||
},
|
},
|
||||||
"expression": "B",
|
"expression": "B",
|
||||||
"hide": false,
|
|
||||||
"refId": "C",
|
"refId": "C",
|
||||||
"type": "threshold",
|
"type": "threshold",
|
||||||
},
|
},
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
|
import { omit } from 'lodash';
|
||||||
import React, { useEffect, useMemo, useState } from 'react';
|
import React, { useEffect, useMemo, useState } from 'react';
|
||||||
import { DeepMap, FieldError, FormProvider, useForm, useFormContext, UseFormWatch } from 'react-hook-form';
|
import { DeepMap, FieldError, FormProvider, useForm, useFormContext, UseFormWatch } from 'react-hook-form';
|
||||||
import { Link, useParams } from 'react-router-dom';
|
import { Link, useParams } from 'react-router-dom';
|
||||||
@ -12,6 +13,7 @@ import { useCleanup } from 'app/core/hooks/useCleanup';
|
|||||||
import { useQueryParams } from 'app/core/hooks/useQueryParams';
|
import { useQueryParams } from 'app/core/hooks/useQueryParams';
|
||||||
import { useDispatch } from 'app/types';
|
import { useDispatch } from 'app/types';
|
||||||
import { RuleWithLocation } from 'app/types/unified-alerting';
|
import { RuleWithLocation } from 'app/types/unified-alerting';
|
||||||
|
import { RulerRuleDTO } from 'app/types/unified-alerting-dto';
|
||||||
|
|
||||||
import { LogMessages, trackNewAlerRuleFormError } from '../../Analytics';
|
import { LogMessages, trackNewAlerRuleFormError } from '../../Analytics';
|
||||||
import { useUnifiedAlertingSelector } from '../../hooks/useUnifiedAlertingSelector';
|
import { useUnifiedAlertingSelector } from '../../hooks/useUnifiedAlertingSelector';
|
||||||
@ -90,21 +92,21 @@ export const AlertRuleForm = ({ existing, prefill }: Props) => {
|
|||||||
|
|
||||||
const defaultValues: RuleFormValues = useMemo(() => {
|
const defaultValues: RuleFormValues = useMemo(() => {
|
||||||
if (existing) {
|
if (existing) {
|
||||||
return rulerRuleToFormValues(existing);
|
return formValuesFromExistingRule(existing);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prefill) {
|
if (prefill) {
|
||||||
return {
|
return formValuesFromPrefill(prefill);
|
||||||
...getDefaultFormValues(),
|
}
|
||||||
...prefill,
|
|
||||||
};
|
if (typeof queryParams['defaults'] === 'string') {
|
||||||
|
return formValuesFromQueryParams(queryParams['defaults'], ruleType);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...getDefaultFormValues(),
|
...getDefaultFormValues(),
|
||||||
queries: getDefaultQueries(),
|
|
||||||
condition: 'C',
|
condition: 'C',
|
||||||
...(queryParams['defaults'] ? JSON.parse(queryParams['defaults'] as string) : {}),
|
queries: getDefaultQueries(),
|
||||||
type: ruleType || RuleFormType.grafana,
|
type: ruleType || RuleFormType.grafana,
|
||||||
evaluateEvery: evaluateEvery,
|
evaluateEvery: evaluateEvery,
|
||||||
};
|
};
|
||||||
@ -281,6 +283,49 @@ const isCortexLokiOrRecordingRule = (watch: UseFormWatch<RuleFormValues>) => {
|
|||||||
return (ruleType === RuleFormType.cloudAlerting || ruleType === RuleFormType.cloudRecording) && dataSourceName !== '';
|
return (ruleType === RuleFormType.cloudAlerting || ruleType === RuleFormType.cloudRecording) && dataSourceName !== '';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// the backend will always execute "hidden" queries, so we have no choice but to remove the property in the front-end
|
||||||
|
// to avoid confusion. The query editor shows them as "disabled" and that's a different semantic meaning.
|
||||||
|
// furthermore the "AlertingQueryRunner" calls `filterQuery` on each data source and those will skip running queries that are "hidden"."
|
||||||
|
// It seems like we have no choice but to act like "hidden" queries don't exist in alerting.
|
||||||
|
const ignoreHiddenQueries = (ruleDefinition: RuleFormValues): RuleFormValues => {
|
||||||
|
return {
|
||||||
|
...ruleDefinition,
|
||||||
|
queries: ruleDefinition.queries?.map((query) => omit(query, 'model.hide')),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function formValuesFromQueryParams(ruleDefinition: string, type: RuleFormType): RuleFormValues {
|
||||||
|
let ruleFromQueryParams: Partial<RuleFormValues>;
|
||||||
|
|
||||||
|
try {
|
||||||
|
ruleFromQueryParams = JSON.parse(ruleDefinition);
|
||||||
|
} catch (err) {
|
||||||
|
return {
|
||||||
|
...getDefaultFormValues(),
|
||||||
|
queries: getDefaultQueries(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return ignoreHiddenQueries({
|
||||||
|
...getDefaultFormValues(),
|
||||||
|
...ruleFromQueryParams,
|
||||||
|
queries: ruleFromQueryParams.queries ?? getDefaultQueries(),
|
||||||
|
type: type || RuleFormType.grafana,
|
||||||
|
evaluateEvery: MINUTE,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function formValuesFromPrefill(rule: Partial<RuleFormValues>): RuleFormValues {
|
||||||
|
return ignoreHiddenQueries({
|
||||||
|
...getDefaultFormValues(),
|
||||||
|
...rule,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function formValuesFromExistingRule(rule: RuleWithLocation<RulerRuleDTO>) {
|
||||||
|
return ignoreHiddenQueries(rulerRuleToFormValues(rule));
|
||||||
|
}
|
||||||
|
|
||||||
const getStyles = (theme: GrafanaTheme2) => {
|
const getStyles = (theme: GrafanaTheme2) => {
|
||||||
return {
|
return {
|
||||||
buttonSpinner: css`
|
buttonSpinner: css`
|
||||||
|
@ -3,6 +3,7 @@ import React, { PureComponent, useState } from 'react';
|
|||||||
import { DragDropContext, Droppable, DropResult } from 'react-beautiful-dnd';
|
import { DragDropContext, Droppable, DropResult } from 'react-beautiful-dnd';
|
||||||
|
|
||||||
import { DataQuery, DataSourceInstanceSettings, LoadingState, PanelData, RelativeTimeRange } from '@grafana/data';
|
import { DataQuery, DataSourceInstanceSettings, LoadingState, PanelData, RelativeTimeRange } from '@grafana/data';
|
||||||
|
import { Stack } from '@grafana/experimental';
|
||||||
import { getDataSourceSrv } from '@grafana/runtime';
|
import { getDataSourceSrv } from '@grafana/runtime';
|
||||||
import { Button, Card, Icon } from '@grafana/ui';
|
import { Button, Card, Icon } from '@grafana/ui';
|
||||||
import { QueryOperationRow } from 'app/core/components/QueryOperationRow/QueryOperationRow';
|
import { QueryOperationRow } from 'app/core/components/QueryOperationRow/QueryOperationRow';
|
||||||
@ -142,59 +143,61 @@ export class QueryRows extends PureComponent<Props> {
|
|||||||
{(provided) => {
|
{(provided) => {
|
||||||
return (
|
return (
|
||||||
<div ref={provided.innerRef} {...provided.droppableProps}>
|
<div ref={provided.innerRef} {...provided.droppableProps}>
|
||||||
{queries.map((query, index) => {
|
<Stack direction="column">
|
||||||
const data: PanelData = this.props.data?.[query.refId] ?? {
|
{queries.map((query, index) => {
|
||||||
series: [],
|
const data: PanelData = this.props.data?.[query.refId] ?? {
|
||||||
state: LoadingState.NotStarted,
|
series: [],
|
||||||
};
|
state: LoadingState.NotStarted,
|
||||||
const dsSettings = this.getDataSourceSettings(query);
|
};
|
||||||
|
const dsSettings = this.getDataSourceSettings(query);
|
||||||
|
|
||||||
const isAlertCondition = this.props.condition === query.refId;
|
const isAlertCondition = this.props.condition === query.refId;
|
||||||
const error = isAlertCondition ? errorFromSeries(data.series) : undefined;
|
const error = isAlertCondition ? errorFromSeries(data.series) : undefined;
|
||||||
|
|
||||||
|
if (!dsSettings) {
|
||||||
|
return (
|
||||||
|
<DatasourceNotFound
|
||||||
|
key={`${query.refId}-${index}`}
|
||||||
|
index={index}
|
||||||
|
model={query.model}
|
||||||
|
onUpdateDatasource={() => {
|
||||||
|
const defaultDataSource = getDatasourceSrv().getInstanceSettings(null);
|
||||||
|
if (defaultDataSource) {
|
||||||
|
this.onChangeDataSource(defaultDataSource, index);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onRemoveQuery={() => {
|
||||||
|
this.onRemoveQuery(query);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (!dsSettings) {
|
|
||||||
return (
|
return (
|
||||||
<DatasourceNotFound
|
<QueryWrapper
|
||||||
key={`${query.refId}-${index}`}
|
|
||||||
index={index}
|
index={index}
|
||||||
model={query.model}
|
key={query.refId}
|
||||||
onUpdateDatasource={() => {
|
dsSettings={dsSettings}
|
||||||
const defaultDataSource = getDatasourceSrv().getInstanceSettings(null);
|
data={data}
|
||||||
if (defaultDataSource) {
|
error={error}
|
||||||
this.onChangeDataSource(defaultDataSource, index);
|
query={query}
|
||||||
}
|
onChangeQuery={this.onChangeQuery}
|
||||||
}}
|
onRemoveQuery={this.onRemoveQuery}
|
||||||
onRemoveQuery={() => {
|
queries={[...queries, ...expressions]}
|
||||||
this.onRemoveQuery(query);
|
onChangeDataSource={this.onChangeDataSource}
|
||||||
}}
|
onDuplicateQuery={this.props.onDuplicateQuery}
|
||||||
|
onChangeTimeRange={this.onChangeTimeRange}
|
||||||
|
onChangeQueryOptions={this.onChangeQueryOptions}
|
||||||
|
thresholds={thresholdByRefId[query.refId]?.config}
|
||||||
|
thresholdsType={thresholdByRefId[query.refId]?.mode}
|
||||||
|
onRunQueries={this.props.onRunQueries}
|
||||||
|
condition={this.props.condition}
|
||||||
|
onSetCondition={this.props.onSetCondition}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
})}
|
||||||
|
{provided.placeholder}
|
||||||
return (
|
</Stack>
|
||||||
<QueryWrapper
|
|
||||||
index={index}
|
|
||||||
key={query.refId}
|
|
||||||
dsSettings={dsSettings}
|
|
||||||
data={data}
|
|
||||||
error={error}
|
|
||||||
query={query}
|
|
||||||
onChangeQuery={this.onChangeQuery}
|
|
||||||
onRemoveQuery={this.onRemoveQuery}
|
|
||||||
queries={[...queries, ...expressions]}
|
|
||||||
onChangeDataSource={this.onChangeDataSource}
|
|
||||||
onDuplicateQuery={this.props.onDuplicateQuery}
|
|
||||||
onChangeTimeRange={this.onChangeTimeRange}
|
|
||||||
onChangeQueryOptions={this.onChangeQueryOptions}
|
|
||||||
thresholds={thresholdByRefId[query.refId]?.config}
|
|
||||||
thresholdsType={thresholdByRefId[query.refId]?.mode}
|
|
||||||
onRunQueries={this.props.onRunQueries}
|
|
||||||
condition={this.props.condition}
|
|
||||||
onSetCondition={this.props.onSetCondition}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
{provided.placeholder}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
@ -4,7 +4,6 @@ import React, { ChangeEvent, useState } from 'react';
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
CoreApp,
|
CoreApp,
|
||||||
DataQuery,
|
|
||||||
DataSourceApi,
|
DataSourceApi,
|
||||||
DataSourceInstanceSettings,
|
DataSourceInstanceSettings,
|
||||||
getDefaultRelativeTimeRange,
|
getDefaultRelativeTimeRange,
|
||||||
@ -15,6 +14,7 @@ import {
|
|||||||
ThresholdsConfig,
|
ThresholdsConfig,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Stack } from '@grafana/experimental';
|
||||||
|
import { DataQuery } from '@grafana/schema';
|
||||||
import {
|
import {
|
||||||
GraphTresholdsStyleMode,
|
GraphTresholdsStyleMode,
|
||||||
Icon,
|
Icon,
|
||||||
@ -82,6 +82,11 @@ export const QueryWrapper = ({
|
|||||||
const [dsInstance, setDsInstance] = useState<DataSourceApi>();
|
const [dsInstance, setDsInstance] = useState<DataSourceApi>();
|
||||||
const defaults = dsInstance?.getDefaultQuery ? dsInstance.getDefaultQuery(CoreApp.UnifiedAlerting) : {};
|
const defaults = dsInstance?.getDefaultQuery ? dsInstance.getDefaultQuery(CoreApp.UnifiedAlerting) : {};
|
||||||
|
|
||||||
|
const queryWithDefaults = {
|
||||||
|
...defaults,
|
||||||
|
...cloneDeep(query.model),
|
||||||
|
};
|
||||||
|
|
||||||
function SelectingDataSourceTooltip() {
|
function SelectingDataSourceTooltip() {
|
||||||
const styles = useStyles2(getStyles);
|
const styles = useStyles2(getStyles);
|
||||||
return (
|
return (
|
||||||
@ -139,6 +144,8 @@ export const QueryWrapper = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const showVizualisation = data.state !== LoadingState.NotStarted;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack direction="column" gap={0.5}>
|
<Stack direction="column" gap={0.5}>
|
||||||
<div className={styles.wrapper}>
|
<div className={styles.wrapper}>
|
||||||
@ -151,10 +158,7 @@ export const QueryWrapper = ({
|
|||||||
index={index}
|
index={index}
|
||||||
key={query.refId}
|
key={query.refId}
|
||||||
data={data}
|
data={data}
|
||||||
query={{
|
query={queryWithDefaults}
|
||||||
...defaults,
|
|
||||||
...cloneDeep(query.model),
|
|
||||||
}}
|
|
||||||
onChange={(query) => onChangeQuery(query, index)}
|
onChange={(query) => onChangeQuery(query, index)}
|
||||||
onRemoveQuery={onRemoveQuery}
|
onRemoveQuery={onRemoveQuery}
|
||||||
onAddQuery={() => onDuplicateQuery(cloneDeep(query))}
|
onAddQuery={() => onDuplicateQuery(cloneDeep(query))}
|
||||||
@ -165,7 +169,7 @@ export const QueryWrapper = ({
|
|||||||
hideDisableQuery={true}
|
hideDisableQuery={true}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{data.state !== LoadingState.NotStarted && (
|
{showVizualisation && (
|
||||||
<VizWrapper
|
<VizWrapper
|
||||||
data={data}
|
data={data}
|
||||||
thresholds={thresholds}
|
thresholds={thresholds}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { defaultsDeep } from 'lodash';
|
||||||
import { Observable, of, throwError } from 'rxjs';
|
import { Observable, of, throwError } from 'rxjs';
|
||||||
import { delay, take } from 'rxjs/operators';
|
import { delay, take } from 'rxjs/operators';
|
||||||
import { createFetchResponse } from 'test/helpers/createFetchResponse';
|
import { createFetchResponse } from 'test/helpers/createFetchResponse';
|
||||||
@ -14,7 +15,7 @@ import {
|
|||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { DataSourceSrv, FetchResponse } from '@grafana/runtime';
|
import { DataSourceSrv, FetchResponse } from '@grafana/runtime';
|
||||||
import { BackendSrv } from 'app/core/services/backend_srv';
|
import { BackendSrv } from 'app/core/services/backend_srv';
|
||||||
import { AlertQuery } from 'app/types/unified-alerting-dto';
|
import { AlertDataQuery, AlertQuery } from 'app/types/unified-alerting-dto';
|
||||||
|
|
||||||
import { AlertingQueryResponse, AlertingQueryRunner } from './AlertingQueryRunner';
|
import { AlertingQueryResponse, AlertingQueryRunner } from './AlertingQueryRunner';
|
||||||
|
|
||||||
@ -188,7 +189,7 @@ describe('AlertingQueryRunner', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not execute if a query fails filterQuery check', async () => {
|
it('should not execute if all queries fail filterQuery check', async () => {
|
||||||
const runner = new AlertingQueryRunner(
|
const runner = new AlertingQueryRunner(
|
||||||
mockBackendSrv({
|
mockBackendSrv({
|
||||||
fetch: () => throwError(new Error("shouldn't happen")),
|
fetch: () => throwError(new Error("shouldn't happen")),
|
||||||
@ -209,6 +210,39 @@ describe('AlertingQueryRunner', () => {
|
|||||||
expect(data.B.series).toHaveLength(0);
|
expect(data.B.series).toHaveLength(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should skip hidden queries', async () => {
|
||||||
|
const results = createFetchResponse<AlertingQueryResponse>({
|
||||||
|
results: {
|
||||||
|
B: { frames: [createDataFrameJSON([1, 2, 3])] },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const runner = new AlertingQueryRunner(
|
||||||
|
mockBackendSrv({
|
||||||
|
fetch: () => of(results),
|
||||||
|
}),
|
||||||
|
mockDataSourceSrv({ filterQuery: (model: AlertDataQuery) => model.hide !== true })
|
||||||
|
);
|
||||||
|
|
||||||
|
const data = runner.get();
|
||||||
|
runner.run([
|
||||||
|
createQuery('A', {
|
||||||
|
model: {
|
||||||
|
refId: 'A',
|
||||||
|
hide: true,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
createQuery('B'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
await expect(data.pipe(take(1))).toEmitValuesWith((values) => {
|
||||||
|
const [loading, _data] = values;
|
||||||
|
|
||||||
|
expect(loading.A).toBeUndefined();
|
||||||
|
expect(loading.B.state).toEqual(LoadingState.Done);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
type MockBackendSrvConfig = {
|
type MockBackendSrvConfig = {
|
||||||
@ -269,12 +303,12 @@ const createDataFrameJSON = (values: number[]): DataFrameJSON => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const createQuery = (refId: string): AlertQuery => {
|
const createQuery = (refId: string, options?: Partial<AlertQuery>): AlertQuery => {
|
||||||
return {
|
return defaultsDeep(options, {
|
||||||
refId,
|
refId,
|
||||||
queryType: '',
|
queryType: '',
|
||||||
datasourceUid: '',
|
datasourceUid: '',
|
||||||
model: { refId },
|
model: { refId },
|
||||||
relativeTimeRange: getDefaultRelativeTimeRange(),
|
relativeTimeRange: getDefaultRelativeTimeRange(),
|
||||||
};
|
});
|
||||||
};
|
};
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { reject } from 'lodash';
|
||||||
import { Observable, of, OperatorFunction, ReplaySubject, Unsubscribable } from 'rxjs';
|
import { Observable, of, OperatorFunction, ReplaySubject, Unsubscribable } from 'rxjs';
|
||||||
import { catchError, map, share } from 'rxjs/operators';
|
import { catchError, map, share } from 'rxjs/operators';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
@ -44,24 +45,33 @@ export class AlertingQueryRunner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async run(queries: AlertQuery[]) {
|
async run(queries: AlertQuery[]) {
|
||||||
if (queries.length === 0) {
|
const empty = initialState(queries, LoadingState.Done);
|
||||||
const empty = initialState(queries, LoadingState.Done);
|
const queriesToExclude: string[] = [];
|
||||||
return this.subject.next(empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
// do not execute if one more of the queries are not runnable,
|
// do not execute if one more of the queries are not runnable,
|
||||||
// for example not completely configured
|
// for example not completely configured
|
||||||
for (const query of queries) {
|
for (const query of queries) {
|
||||||
if (!isExpressionQuery(query.model)) {
|
const refId = query.model.refId;
|
||||||
const ds = await this.dataSourceSrv.get(query.datasourceUid);
|
|
||||||
if (ds.filterQuery && !ds.filterQuery(query.model)) {
|
if (isExpressionQuery(query.model)) {
|
||||||
const empty = initialState(queries, LoadingState.Done);
|
continue;
|
||||||
return this.subject.next(empty);
|
}
|
||||||
}
|
|
||||||
|
const dataSourceInstance = await this.dataSourceSrv.get(query.datasourceUid);
|
||||||
|
const skipRunningQuery = dataSourceInstance.filterQuery && !dataSourceInstance.filterQuery(query.model);
|
||||||
|
|
||||||
|
if (skipRunningQuery) {
|
||||||
|
queriesToExclude.push(refId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.subscription = runRequest(this.backendSrv, queries).subscribe({
|
const queriesToRun = reject(queries, (q) => queriesToExclude.includes(q.model.refId));
|
||||||
|
|
||||||
|
if (queriesToRun.length === 0) {
|
||||||
|
return this.subject.next(empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.subscription = runRequest(this.backendSrv, queriesToRun).subscribe({
|
||||||
next: (dataPerQuery) => {
|
next: (dataPerQuery) => {
|
||||||
const nextResult = applyChange(dataPerQuery, (refId, data) => {
|
const nextResult = applyChange(dataPerQuery, (refId, data) => {
|
||||||
const previous = this.lastResult[refId];
|
const previous = this.lastResult[refId];
|
||||||
|
@ -127,6 +127,7 @@ export function rulerRuleToFormValues(ruleWithLocation: RuleWithLocation): RuleF
|
|||||||
if (isGrafanaRulesSource(ruleSourceName)) {
|
if (isGrafanaRulesSource(ruleSourceName)) {
|
||||||
if (isGrafanaRulerRule(rule)) {
|
if (isGrafanaRulerRule(rule)) {
|
||||||
const ga = rule.grafana_alert;
|
const ga = rule.grafana_alert;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...defaultFormValues,
|
...defaultFormValues,
|
||||||
name: ga.title,
|
name: ga.title,
|
||||||
@ -220,7 +221,6 @@ export const getDefaultQueries = (): AlertQuery[] => {
|
|||||||
relativeTimeRange,
|
relativeTimeRange,
|
||||||
model: {
|
model: {
|
||||||
refId: 'A',
|
refId: 'A',
|
||||||
hide: false,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
...getDefaultExpressions('B', 'C'),
|
...getDefaultExpressions('B', 'C'),
|
||||||
@ -240,7 +240,6 @@ export const getDefaultRecordingRulesQueries = (
|
|||||||
relativeTimeRange,
|
relativeTimeRange,
|
||||||
model: {
|
model: {
|
||||||
refId: 'A',
|
refId: 'A',
|
||||||
hide: false,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@ -252,7 +251,6 @@ const getDefaultExpressions = (...refIds: [string, string]): AlertQuery[] => {
|
|||||||
|
|
||||||
const reduceExpression: ExpressionQuery = {
|
const reduceExpression: ExpressionQuery = {
|
||||||
refId: refIds[0],
|
refId: refIds[0],
|
||||||
hide: false,
|
|
||||||
type: ExpressionQueryType.reduce,
|
type: ExpressionQueryType.reduce,
|
||||||
datasource: {
|
datasource: {
|
||||||
uid: ExpressionDatasourceUID,
|
uid: ExpressionDatasourceUID,
|
||||||
@ -283,7 +281,6 @@ const getDefaultExpressions = (...refIds: [string, string]): AlertQuery[] => {
|
|||||||
|
|
||||||
const thresholdExpression: ExpressionQuery = {
|
const thresholdExpression: ExpressionQuery = {
|
||||||
refId: refTwo,
|
refId: refTwo,
|
||||||
hide: false,
|
|
||||||
type: ExpressionQueryType.threshold,
|
type: ExpressionQueryType.threshold,
|
||||||
datasource: {
|
datasource: {
|
||||||
uid: ExpressionDatasourceUID,
|
uid: ExpressionDatasourceUID,
|
||||||
|
Loading…
Reference in New Issue
Block a user