| 
									
										
										
										
											2024-04-04 22:24:35 +08:00
										 |  |  | import { clamp, omit } from 'lodash'; | 
					
						
							| 
									
										
										
										
											2023-10-12 15:04:59 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 15:59:48 +08:00
										 |  |  | import { | 
					
						
							|  |  |  |   DataQuery, | 
					
						
							| 
									
										
										
										
											2023-06-19 19:32:17 +08:00
										 |  |  |   DataSourceInstanceSettings, | 
					
						
							| 
									
										
										
										
											2022-04-20 00:43:33 +08:00
										 |  |  |   DataSourceRef, | 
					
						
							|  |  |  |   getDefaultRelativeTimeRange, | 
					
						
							| 
									
										
										
										
											2024-05-10 19:00:17 +08:00
										 |  |  |   getNextRefId, | 
					
						
							| 
									
										
										
										
											2022-04-20 00:43:33 +08:00
										 |  |  |   IntervalValues, | 
					
						
							| 
									
										
										
										
											2021-08-10 15:59:48 +08:00
										 |  |  |   rangeUtil, | 
					
						
							|  |  |  |   RelativeTimeRange, | 
					
						
							|  |  |  |   ScopedVars, | 
					
						
							|  |  |  |   TimeRange, | 
					
						
							|  |  |  | } from '@grafana/data'; | 
					
						
							| 
									
										
										
										
											2024-04-16 05:45:23 +08:00
										 |  |  | import { PromQuery } from '@grafana/prometheus'; | 
					
						
							| 
									
										
										
										
											2024-02-09 19:16:28 +08:00
										 |  |  | import { config, getDataSourceSrv } from '@grafana/runtime'; | 
					
						
							| 
									
										
										
										
											2022-04-20 00:43:33 +08:00
										 |  |  | import { ExpressionDatasourceRef } from '@grafana/runtime/src/utils/DataSourceWithBackend'; | 
					
						
							| 
									
										
										
										
											2024-02-07 19:59:18 +08:00
										 |  |  | import { sceneGraph, VizPanel } from '@grafana/scenes'; | 
					
						
							| 
									
										
										
										
											2023-03-22 20:21:15 +08:00
										 |  |  | import { DataSourceJsonData } from '@grafana/schema'; | 
					
						
							| 
									
										
										
										
											2021-05-17 15:39:42 +08:00
										 |  |  | import { DashboardModel, PanelModel } from 'app/features/dashboard/state'; | 
					
						
							| 
									
										
										
										
											2024-02-07 19:59:18 +08:00
										 |  |  | import { | 
					
						
							|  |  |  |   getDashboardSceneFor, | 
					
						
							|  |  |  |   getPanelIdForVizPanel, | 
					
						
							|  |  |  |   getQueryRunnerFor, | 
					
						
							|  |  |  | } from 'app/features/dashboard-scene/utils/utils'; | 
					
						
							| 
									
										
										
										
											2023-06-19 19:32:17 +08:00
										 |  |  | import { ExpressionDatasourceUID, ExpressionQuery, ExpressionQueryType } from 'app/features/expressions/types'; | 
					
						
							| 
									
										
										
										
											2023-03-30 02:42:47 +08:00
										 |  |  | import { LokiQuery } from 'app/plugins/datasource/loki/types'; | 
					
						
							| 
									
										
										
										
											2021-04-16 16:08:26 +08:00
										 |  |  | import { RuleWithLocation } from 'app/types/unified-alerting'; | 
					
						
							|  |  |  | import { | 
					
						
							| 
									
										
										
										
											2022-10-27 23:22:23 +08:00
										 |  |  |   AlertDataQuery, | 
					
						
							| 
									
										
										
										
											2022-04-20 00:43:33 +08:00
										 |  |  |   AlertQuery, | 
					
						
							| 
									
										
										
										
											2021-04-16 16:08:26 +08:00
										 |  |  |   Annotations, | 
					
						
							| 
									
										
										
										
											2021-05-06 16:21:58 +08:00
										 |  |  |   GrafanaAlertStateDecision, | 
					
						
							| 
									
										
										
										
											2024-01-09 15:39:43 +08:00
										 |  |  |   GrafanaNotificationSettings, | 
					
						
							|  |  |  |   GrafanaRuleDefinition, | 
					
						
							| 
									
										
										
										
											2021-04-16 16:08:26 +08:00
										 |  |  |   Labels, | 
					
						
							|  |  |  |   PostableRuleGrafanaRuleDTO, | 
					
						
							| 
									
										
										
										
											2022-09-08 18:52:36 +08:00
										 |  |  |   RulerAlertingRuleDTO, | 
					
						
							|  |  |  |   RulerRecordingRuleDTO, | 
					
						
							| 
									
										
										
										
											2021-08-24 16:31:56 +08:00
										 |  |  |   RulerRuleDTO, | 
					
						
							| 
									
										
										
										
											2021-04-16 16:08:26 +08:00
										 |  |  | } from 'app/types/unified-alerting-dto'; | 
					
						
							| 
									
										
										
										
											2022-04-22 21:33:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-22 20:57:23 +08:00
										 |  |  | type KVObject = { key: string; value: string }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-04 22:31:25 +08:00
										 |  |  | import { EvalFunction } from '../../state/alertDef'; | 
					
						
							| 
									
										
										
										
											2024-09-26 14:33:14 +08:00
										 |  |  | import { | 
					
						
							|  |  |  |   AlertManagerManualRouting, | 
					
						
							|  |  |  |   ContactPoint, | 
					
						
							|  |  |  |   RuleFormType, | 
					
						
							|  |  |  |   RuleFormValues, | 
					
						
							|  |  |  |   SimplifiedEditor, | 
					
						
							|  |  |  | } from '../types/rule-form'; | 
					
						
							| 
									
										
										
										
											2022-04-22 21:33:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-20 00:43:33 +08:00
										 |  |  | import { getRulesAccess } from './access-control'; | 
					
						
							| 
									
										
										
										
											2023-06-21 22:15:12 +08:00
										 |  |  | import { Annotation, defaultAnnotations } from './constants'; | 
					
						
							| 
									
										
										
										
											2024-11-15 18:28:54 +08:00
										 |  |  | import { | 
					
						
							|  |  |  |   DataSourceType, | 
					
						
							|  |  |  |   getDefaultOrFirstCompatibleDataSource, | 
					
						
							|  |  |  |   GRAFANA_RULES_SOURCE_NAME, | 
					
						
							|  |  |  |   isGrafanaRulesSource, | 
					
						
							|  |  |  | } from './datasource'; | 
					
						
							| 
									
										
										
										
											2021-04-16 16:08:26 +08:00
										 |  |  | import { arrayToRecord, recordToArray } from './misc'; | 
					
						
							| 
									
										
										
										
											2024-07-26 19:52:22 +08:00
										 |  |  | import { | 
					
						
							|  |  |  |   isAlertingRulerRule, | 
					
						
							|  |  |  |   isGrafanaAlertingRuleByType, | 
					
						
							|  |  |  |   isGrafanaRecordingRule, | 
					
						
							| 
									
										
										
										
											2024-08-22 20:57:23 +08:00
										 |  |  |   isGrafanaRecordingRuleByType, | 
					
						
							| 
									
										
										
										
											2024-07-26 19:52:22 +08:00
										 |  |  |   isGrafanaRulerRule, | 
					
						
							|  |  |  |   isRecordingRulerRule, | 
					
						
							|  |  |  | } from './rules'; | 
					
						
							| 
									
										
										
										
											2024-04-04 22:24:35 +08:00
										 |  |  | import { formatPrometheusDuration, parseInterval, safeParsePrometheusDuration } from './time'; | 
					
						
							| 
									
										
										
										
											2021-04-16 16:08:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-30 02:42:47 +08:00
										 |  |  | export type PromOrLokiQuery = PromQuery | LokiQuery; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-09 19:16:28 +08:00
										 |  |  | export const MANUAL_ROUTING_KEY = 'grafana.alerting.manualRouting'; | 
					
						
							| 
									
										
										
										
											2024-09-26 14:33:14 +08:00
										 |  |  | export const SIMPLIFIED_QUERY_EDITOR_KEY = 'grafana.alerting.simplifiedQueryEditor'; | 
					
						
							| 
									
										
										
										
											2024-02-09 19:16:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-04 22:24:35 +08:00
										 |  |  | // even if the min interval is < 1m we should default to 1m, but allow arbitrary values for minInterval > 1m
 | 
					
						
							|  |  |  | const GROUP_EVALUATION_MIN_INTERVAL_MS = safeParsePrometheusDuration(config.unifiedAlerting?.minInterval ?? '10s'); | 
					
						
							|  |  |  | const GROUP_EVALUATION_INTERVAL_LOWER_BOUND = safeParsePrometheusDuration('1m'); | 
					
						
							|  |  |  | const GROUP_EVALUATION_INTERVAL_UPPER_BOUND = Infinity; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export const DEFAULT_GROUP_EVALUATION_INTERVAL = formatPrometheusDuration( | 
					
						
							|  |  |  |   clamp(GROUP_EVALUATION_MIN_INTERVAL_MS, GROUP_EVALUATION_INTERVAL_LOWER_BOUND, GROUP_EVALUATION_INTERVAL_UPPER_BOUND) | 
					
						
							|  |  |  | ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-20 00:43:33 +08:00
										 |  |  | export const getDefaultFormValues = (): RuleFormValues => { | 
					
						
							|  |  |  |   const { canCreateGrafanaRules, canCreateCloudRules } = getRulesAccess(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return Object.freeze({ | 
					
						
							| 
									
										
										
										
											2021-05-17 16:15:17 +08:00
										 |  |  |     name: '', | 
					
						
							| 
									
										
										
										
											2023-06-19 19:32:17 +08:00
										 |  |  |     uid: '', | 
					
						
							| 
									
										
										
										
											2021-05-17 16:15:17 +08:00
										 |  |  |     labels: [{ key: '', value: '' }], | 
					
						
							| 
									
										
										
										
											2023-06-21 22:15:12 +08:00
										 |  |  |     annotations: defaultAnnotations, | 
					
						
							| 
									
										
										
										
											2024-08-22 20:57:23 +08:00
										 |  |  |     dataSourceName: GRAFANA_RULES_SOURCE_NAME, // let's use Grafana-managed alert rule by default
 | 
					
						
							| 
									
										
										
										
											2022-04-20 00:43:33 +08:00
										 |  |  |     type: canCreateGrafanaRules ? RuleFormType.grafana : canCreateCloudRules ? RuleFormType.cloudAlerting : undefined, // viewers can't create prom alerts
 | 
					
						
							| 
									
										
										
										
											2022-04-20 17:41:33 +08:00
										 |  |  |     group: '', | 
					
						
							| 
									
										
										
										
											2021-04-16 16:08:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-19 00:14:57 +08:00
										 |  |  |     // grafana
 | 
					
						
							| 
									
										
										
										
											2024-11-19 18:41:31 +08:00
										 |  |  |     folder: undefined, | 
					
						
							| 
									
										
										
										
											2021-05-17 16:15:17 +08:00
										 |  |  |     queries: [], | 
					
						
							| 
									
										
										
										
											2023-03-22 20:21:15 +08:00
										 |  |  |     recordingRulesQueries: [], | 
					
						
							| 
									
										
										
										
											2021-05-17 16:15:17 +08:00
										 |  |  |     condition: '', | 
					
						
							|  |  |  |     noDataState: GrafanaAlertStateDecision.NoData, | 
					
						
							| 
									
										
										
										
											2022-09-19 17:42:04 +08:00
										 |  |  |     execErrState: GrafanaAlertStateDecision.Error, | 
					
						
							| 
									
										
										
										
											2024-04-04 22:24:35 +08:00
										 |  |  |     evaluateFor: DEFAULT_GROUP_EVALUATION_INTERVAL, | 
					
						
							|  |  |  |     evaluateEvery: DEFAULT_GROUP_EVALUATION_INTERVAL, | 
					
						
							| 
									
										
										
										
											2024-02-09 19:16:28 +08:00
										 |  |  |     manualRouting: getDefautManualRouting(), // we default to true if the feature toggle is enabled and the user hasn't set local storage to false
 | 
					
						
							| 
									
										
										
										
											2024-01-02 15:43:31 +08:00
										 |  |  |     contactPoints: {}, | 
					
						
							|  |  |  |     overrideGrouping: false, | 
					
						
							|  |  |  |     overrideTimings: false, | 
					
						
							|  |  |  |     muteTimeIntervals: [], | 
					
						
							| 
									
										
										
										
											2024-09-26 14:33:14 +08:00
										 |  |  |     editorSettings: getDefaultEditorSettings(), | 
					
						
							| 
									
										
										
										
											2021-04-16 16:08:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-19 00:14:57 +08:00
										 |  |  |     // cortex / loki
 | 
					
						
							| 
									
										
										
										
											2021-05-17 16:15:17 +08:00
										 |  |  |     namespace: '', | 
					
						
							|  |  |  |     expression: '', | 
					
						
							|  |  |  |     forTime: 1, | 
					
						
							|  |  |  |     forTimeUnit: 'm', | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2022-04-20 00:43:33 +08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2021-04-14 20:57:36 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-09 19:16:28 +08:00
										 |  |  | export const getDefautManualRouting = () => { | 
					
						
							|  |  |  |   // first check if feature toggle for simplified routing is enabled
 | 
					
						
							|  |  |  |   const simplifiedRoutingToggleEnabled = config.featureToggles.alertingSimplifiedRouting ?? false; | 
					
						
							|  |  |  |   if (!simplifiedRoutingToggleEnabled) { | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   //then, check in local storage if the user has enabled simplified routing
 | 
					
						
							|  |  |  |   // if it's not set, we'll default to true
 | 
					
						
							|  |  |  |   const manualRouting = localStorage.getItem(MANUAL_ROUTING_KEY); | 
					
						
							|  |  |  |   return manualRouting !== 'false'; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-26 14:33:14 +08:00
										 |  |  | function getDefaultEditorSettings() { | 
					
						
							|  |  |  |   const editorSettingsEnabled = config.featureToggles.alertingQueryAndExpressionsStepMode ?? false; | 
					
						
							|  |  |  |   if (!editorSettingsEnabled) { | 
					
						
							|  |  |  |     return undefined; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   //then, check in local storage if the user has saved last rule with simplified query editor
 | 
					
						
							|  |  |  |   const queryEditorSettings = localStorage.getItem(SIMPLIFIED_QUERY_EDITOR_KEY); | 
					
						
							|  |  |  |   return { | 
					
						
							|  |  |  |     simplifiedQueryEditor: queryEditorSettings !== 'false', | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-24 16:31:56 +08:00
										 |  |  | export function formValuesToRulerRuleDTO(values: RuleFormValues): RulerRuleDTO { | 
					
						
							| 
									
										
										
										
											2023-09-22 04:02:53 +08:00
										 |  |  |   const { name, expression, forTime, forTimeUnit, keepFiringForTime, keepFiringForTimeUnit, type } = values; | 
					
						
							| 
									
										
										
										
											2024-08-22 20:57:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   const annotations = arrayToRecord(cleanAnnotations(values.annotations)); | 
					
						
							|  |  |  |   const labels = arrayToRecord(cleanLabels(values.labels)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-24 16:31:56 +08:00
										 |  |  |   if (type === RuleFormType.cloudAlerting) { | 
					
						
							| 
									
										
										
										
											2023-09-22 04:02:53 +08:00
										 |  |  |     let keepFiringFor: string | undefined; | 
					
						
							|  |  |  |     if (keepFiringForTime && keepFiringForTimeUnit) { | 
					
						
							|  |  |  |       keepFiringFor = `${keepFiringForTime}${keepFiringForTimeUnit}`; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-24 16:31:56 +08:00
										 |  |  |     return { | 
					
						
							|  |  |  |       alert: name, | 
					
						
							|  |  |  |       for: `${forTime}${forTimeUnit}`, | 
					
						
							| 
									
										
										
										
											2023-09-22 04:02:53 +08:00
										 |  |  |       keep_firing_for: keepFiringFor, | 
					
						
							| 
									
										
										
										
											2024-08-22 20:57:23 +08:00
										 |  |  |       annotations, | 
					
						
							|  |  |  |       labels, | 
					
						
							| 
									
										
										
										
											2021-08-24 16:31:56 +08:00
										 |  |  |       expr: expression, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   } else if (type === RuleFormType.cloudRecording) { | 
					
						
							|  |  |  |     return { | 
					
						
							|  |  |  |       record: name, | 
					
						
							| 
									
										
										
										
											2024-08-22 20:57:23 +08:00
										 |  |  |       labels, | 
					
						
							| 
									
										
										
										
											2021-08-24 16:31:56 +08:00
										 |  |  |       expr: expression, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   throw new Error(`unexpected rule type: ${type}`); | 
					
						
							| 
									
										
										
										
											2021-04-14 20:57:36 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-22 20:57:23 +08:00
										 |  |  | export function listifyLabelsOrAnnotations(item: Labels | Annotations | undefined, addEmpty: boolean): KVObject[] { | 
					
						
							| 
									
										
										
										
											2023-06-21 22:15:12 +08:00
										 |  |  |   const list = [...recordToArray(item || {})]; | 
					
						
							|  |  |  |   if (addEmpty) { | 
					
						
							|  |  |  |     list.push({ key: '', value: '' }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return list; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //make sure default annotations are always shown in order even if empty
 | 
					
						
							| 
									
										
										
										
											2024-08-22 20:57:23 +08:00
										 |  |  | export function normalizeDefaultAnnotations(annotations: KVObject[]) { | 
					
						
							| 
									
										
										
										
											2023-06-21 22:15:12 +08:00
										 |  |  |   const orderedAnnotations = [...annotations]; | 
					
						
							|  |  |  |   const defaultAnnotationKeys = defaultAnnotations.map((annotation) => annotation.key); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   defaultAnnotationKeys.forEach((defaultAnnotationKey, index) => { | 
					
						
							|  |  |  |     const fieldIndex = orderedAnnotations.findIndex((field) => field.key === defaultAnnotationKey); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (fieldIndex === -1) { | 
					
						
							|  |  |  |       //add the default annotation if abstent
 | 
					
						
							|  |  |  |       const emptyValue = { key: defaultAnnotationKey, value: '' }; | 
					
						
							|  |  |  |       orderedAnnotations.splice(index, 0, emptyValue); | 
					
						
							|  |  |  |     } else if (fieldIndex !== index) { | 
					
						
							|  |  |  |       //move it to the correct position if present
 | 
					
						
							|  |  |  |       orderedAnnotations.splice(index, 0, orderedAnnotations.splice(fieldIndex, 1)[0]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   return orderedAnnotations; | 
					
						
							| 
									
										
										
										
											2021-04-16 16:08:26 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-09 15:39:43 +08:00
										 |  |  | export function getNotificationSettingsForDTO( | 
					
						
							|  |  |  |   manualRouting: boolean, | 
					
						
							|  |  |  |   contactPoints?: AlertManagerManualRouting | 
					
						
							|  |  |  | ): GrafanaNotificationSettings | undefined { | 
					
						
							|  |  |  |   if (contactPoints?.grafana?.selectedContactPoint && manualRouting) { | 
					
						
							|  |  |  |     return { | 
					
						
							|  |  |  |       receiver: contactPoints?.grafana?.selectedContactPoint, | 
					
						
							| 
									
										
										
										
											2024-02-07 16:54:31 +08:00
										 |  |  |       mute_time_intervals: contactPoints?.grafana?.muteTimeIntervals, | 
					
						
							| 
									
										
										
										
											2024-01-09 15:39:43 +08:00
										 |  |  |       group_by: contactPoints?.grafana?.overrideGrouping ? contactPoints?.grafana?.groupBy : undefined, | 
					
						
							| 
									
										
										
										
											2024-01-26 23:17:14 +08:00
										 |  |  |       group_wait: | 
					
						
							|  |  |  |         contactPoints?.grafana?.overrideTimings && contactPoints?.grafana?.groupWaitValue | 
					
						
							|  |  |  |           ? contactPoints?.grafana?.groupWaitValue | 
					
						
							|  |  |  |           : undefined, | 
					
						
							|  |  |  |       group_interval: | 
					
						
							|  |  |  |         contactPoints?.grafana?.overrideTimings && contactPoints?.grafana?.groupIntervalValue | 
					
						
							|  |  |  |           ? contactPoints?.grafana?.groupIntervalValue | 
					
						
							|  |  |  |           : undefined, | 
					
						
							|  |  |  |       repeat_interval: | 
					
						
							|  |  |  |         contactPoints?.grafana?.overrideTimings && contactPoints?.grafana?.repeatIntervalValue | 
					
						
							|  |  |  |           ? contactPoints?.grafana?.repeatIntervalValue | 
					
						
							|  |  |  |           : undefined, | 
					
						
							| 
									
										
										
										
											2024-01-09 15:39:43 +08:00
										 |  |  |     }; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return undefined; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2024-09-26 14:33:14 +08:00
										 |  |  | function getEditorSettingsForDTO(simplifiedEditor: SimplifiedEditor) { | 
					
						
							|  |  |  |   return { | 
					
						
							|  |  |  |     simplified_query_and_expressions_section: simplifiedEditor.simplifiedQueryEditor, | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-04-16 16:08:26 +08:00
										 |  |  | export function formValuesToRulerGrafanaRuleDTO(values: RuleFormValues): PostableRuleGrafanaRuleDTO { | 
					
						
							| 
									
										
										
										
											2024-07-26 19:52:22 +08:00
										 |  |  |   const { | 
					
						
							|  |  |  |     name, | 
					
						
							|  |  |  |     condition, | 
					
						
							|  |  |  |     noDataState, | 
					
						
							|  |  |  |     execErrState, | 
					
						
							|  |  |  |     evaluateFor, | 
					
						
							|  |  |  |     queries, | 
					
						
							|  |  |  |     isPaused, | 
					
						
							|  |  |  |     contactPoints, | 
					
						
							|  |  |  |     manualRouting, | 
					
						
							|  |  |  |     type, | 
					
						
							|  |  |  |     metric, | 
					
						
							|  |  |  |   } = values; | 
					
						
							| 
									
										
										
										
											2024-08-22 20:57:23 +08:00
										 |  |  |   if (!condition) { | 
					
						
							|  |  |  |     throw new Error('You cannot create an alert rule without specifying the alert condition'); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const notificationSettings = getNotificationSettingsForDTO(manualRouting, contactPoints); | 
					
						
							| 
									
										
										
										
											2024-09-26 14:33:14 +08:00
										 |  |  |   const metadata = values.editorSettings | 
					
						
							|  |  |  |     ? { editor_settings: getEditorSettingsForDTO(values.editorSettings) } | 
					
						
							|  |  |  |     : undefined; | 
					
						
							| 
									
										
										
										
											2024-08-22 20:57:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   const annotations = arrayToRecord(cleanAnnotations(values.annotations)); | 
					
						
							|  |  |  |   const labels = arrayToRecord(cleanLabels(values.labels)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const wantsAlertingRule = isGrafanaAlertingRuleByType(type); | 
					
						
							|  |  |  |   const wantsRecordingRule = isGrafanaRecordingRuleByType(type!); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (wantsAlertingRule) { | 
					
						
							|  |  |  |     return { | 
					
						
							|  |  |  |       grafana_alert: { | 
					
						
							|  |  |  |         title: name, | 
					
						
							|  |  |  |         condition, | 
					
						
							|  |  |  |         data: queries.map(fixBothInstantAndRangeQuery), | 
					
						
							|  |  |  |         is_paused: Boolean(isPaused), | 
					
						
							| 
									
										
										
										
											2024-07-26 19:52:22 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // Alerting rule specific
 | 
					
						
							| 
									
										
										
										
											2024-08-22 20:57:23 +08:00
										 |  |  |         no_data_state: noDataState, | 
					
						
							|  |  |  |         exec_err_state: execErrState, | 
					
						
							|  |  |  |         notification_settings: notificationSettings, | 
					
						
							| 
									
										
										
										
											2024-09-26 14:33:14 +08:00
										 |  |  |         metadata, | 
					
						
							| 
									
										
										
										
											2024-08-22 20:57:23 +08:00
										 |  |  |       }, | 
					
						
							|  |  |  |       annotations, | 
					
						
							|  |  |  |       labels, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Alerting rule specific
 | 
					
						
							|  |  |  |       for: evaluateFor, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   } else if (wantsRecordingRule) { | 
					
						
							|  |  |  |     return { | 
					
						
							|  |  |  |       grafana_alert: { | 
					
						
							|  |  |  |         title: name, | 
					
						
							|  |  |  |         condition, | 
					
						
							|  |  |  |         data: queries.map(fixBothInstantAndRangeQuery), | 
					
						
							|  |  |  |         is_paused: Boolean(isPaused), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Recording rule specific
 | 
					
						
							|  |  |  |         record: { | 
					
						
							|  |  |  |           metric: metric ?? name, | 
					
						
							|  |  |  |           from: condition, | 
					
						
							| 
									
										
										
										
											2024-07-26 19:52:22 +08:00
										 |  |  |         }, | 
					
						
							| 
									
										
										
										
											2024-08-22 20:57:23 +08:00
										 |  |  |       }, | 
					
						
							|  |  |  |       annotations, | 
					
						
							|  |  |  |       labels, | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2021-04-14 20:57:36 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2024-08-22 20:57:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   throw new Error(`Failed to convert form values to Grafana rule: unknown type ${type}`); | 
					
						
							| 
									
										
										
										
											2021-04-14 20:57:36 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-04-16 16:08:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-22 20:57:23 +08:00
										 |  |  | export const cleanAnnotations = (kvs: KVObject[]) => | 
					
						
							|  |  |  |   kvs.map(trimKeyAndValue).filter(({ key, value }: KVObject): Boolean => Boolean(key) && Boolean(value)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export const cleanLabels = (kvs: KVObject[]) => | 
					
						
							|  |  |  |   kvs.map(trimKeyAndValue).filter(({ key }: KVObject): Boolean => Boolean(key)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const trimKeyAndValue = ({ key, value }: KVObject): KVObject => ({ | 
					
						
							|  |  |  |   key: key.trim(), | 
					
						
							|  |  |  |   value: value.trim(), | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-09 15:39:43 +08:00
										 |  |  | export function getContactPointsFromDTO(ga: GrafanaRuleDefinition): AlertManagerManualRouting | undefined { | 
					
						
							|  |  |  |   const contactPoint: ContactPoint | undefined = ga.notification_settings | 
					
						
							|  |  |  |     ? { | 
					
						
							|  |  |  |         selectedContactPoint: ga.notification_settings.receiver, | 
					
						
							| 
									
										
										
										
											2024-02-07 16:54:31 +08:00
										 |  |  |         muteTimeIntervals: ga.notification_settings.mute_time_intervals ?? [], | 
					
						
							| 
									
										
										
										
											2024-01-26 23:17:14 +08:00
										 |  |  |         overrideGrouping: | 
					
						
							|  |  |  |           Array.isArray(ga.notification_settings.group_by) && ga.notification_settings.group_by.length > 0, | 
					
						
							|  |  |  |         overrideTimings: [ | 
					
						
							|  |  |  |           ga.notification_settings.group_wait, | 
					
						
							|  |  |  |           ga.notification_settings.group_interval, | 
					
						
							|  |  |  |           ga.notification_settings.repeat_interval, | 
					
						
							|  |  |  |         ].some(Boolean), | 
					
						
							| 
									
										
										
										
											2024-01-09 15:39:43 +08:00
										 |  |  |         groupBy: ga.notification_settings.group_by || [], | 
					
						
							|  |  |  |         groupWaitValue: ga.notification_settings.group_wait || '', | 
					
						
							|  |  |  |         groupIntervalValue: ga.notification_settings.group_interval || '', | 
					
						
							|  |  |  |         repeatIntervalValue: ga.notification_settings.repeat_interval || '', | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     : undefined; | 
					
						
							|  |  |  |   const routingSettings: AlertManagerManualRouting | undefined = contactPoint | 
					
						
							|  |  |  |     ? { | 
					
						
							|  |  |  |         [GRAFANA_RULES_SOURCE_NAME]: contactPoint, | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     : undefined; | 
					
						
							|  |  |  |   return routingSettings; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-26 14:33:14 +08:00
										 |  |  | function getEditorSettingsFromDTO(ga: GrafanaRuleDefinition) { | 
					
						
							|  |  |  |   // we need to check if the feature toggle is enabled as it might be disabled after the rule was created with the feature enabled
 | 
					
						
							|  |  |  |   if (!config.featureToggles.alertingQueryAndExpressionsStepMode) { | 
					
						
							|  |  |  |     return undefined; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (ga.metadata?.editor_settings) { | 
					
						
							|  |  |  |     return { | 
					
						
							|  |  |  |       simplifiedQueryEditor: ga.metadata.editor_settings.simplified_query_and_expressions_section, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return { | 
					
						
							|  |  |  |     simplifiedQueryEditor: false, | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-16 16:08:26 +08:00
										 |  |  | export function rulerRuleToFormValues(ruleWithLocation: RuleWithLocation): RuleFormValues { | 
					
						
							|  |  |  |   const { ruleSourceName, namespace, group, rule } = ruleWithLocation; | 
					
						
							| 
									
										
										
										
											2021-05-17 16:15:17 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   const defaultFormValues = getDefaultFormValues(); | 
					
						
							| 
									
										
										
										
											2021-04-16 16:08:26 +08:00
										 |  |  |   if (isGrafanaRulesSource(ruleSourceName)) { | 
					
						
							| 
									
										
										
										
											2024-07-26 19:52:22 +08:00
										 |  |  |     // GRAFANA-MANAGED RULES
 | 
					
						
							|  |  |  |     if (isGrafanaRecordingRule(rule)) { | 
					
						
							|  |  |  |       // grafana recording rule
 | 
					
						
							| 
									
										
										
										
											2021-04-16 16:08:26 +08:00
										 |  |  |       const ga = rule.grafana_alert; | 
					
						
							|  |  |  |       return { | 
					
						
							|  |  |  |         ...defaultFormValues, | 
					
						
							|  |  |  |         name: ga.title, | 
					
						
							| 
									
										
										
										
											2024-07-26 19:52:22 +08:00
										 |  |  |         type: RuleFormType.grafanaRecording, | 
					
						
							| 
									
										
										
										
											2022-04-20 17:41:33 +08:00
										 |  |  |         group: group.name, | 
					
						
							| 
									
										
										
										
											2022-12-15 15:28:47 +08:00
										 |  |  |         evaluateEvery: group.interval || defaultFormValues.evaluateEvery, | 
					
						
							| 
									
										
										
										
											2021-04-16 16:08:26 +08:00
										 |  |  |         queries: ga.data, | 
					
						
							|  |  |  |         condition: ga.condition, | 
					
						
							| 
									
										
										
										
											2023-06-21 22:15:12 +08:00
										 |  |  |         annotations: normalizeDefaultAnnotations(listifyLabelsOrAnnotations(rule.annotations, false)), | 
					
						
							|  |  |  |         labels: listifyLabelsOrAnnotations(rule.labels, true), | 
					
						
							| 
									
										
										
										
											2023-06-19 19:32:17 +08:00
										 |  |  |         folder: { title: namespace, uid: ga.namespace_uid }, | 
					
						
							| 
									
										
										
										
											2023-02-01 20:15:03 +08:00
										 |  |  |         isPaused: ga.is_paused, | 
					
						
							| 
									
										
										
										
											2024-07-26 19:52:22 +08:00
										 |  |  |         metric: ga.record?.metric, | 
					
						
							| 
									
										
										
										
											2021-04-16 16:08:26 +08:00
										 |  |  |       }; | 
					
						
							| 
									
										
										
										
											2024-07-26 19:52:22 +08:00
										 |  |  |     } else if (isGrafanaRulerRule(rule)) { | 
					
						
							|  |  |  |       // grafana alerting rule
 | 
					
						
							|  |  |  |       const ga = rule.grafana_alert; | 
					
						
							|  |  |  |       const routingSettings: AlertManagerManualRouting | undefined = getContactPointsFromDTO(ga); | 
					
						
							|  |  |  |       if (ga.no_data_state !== undefined && ga.exec_err_state !== undefined) { | 
					
						
							|  |  |  |         return { | 
					
						
							|  |  |  |           ...defaultFormValues, | 
					
						
							|  |  |  |           name: ga.title, | 
					
						
							|  |  |  |           type: RuleFormType.grafana, | 
					
						
							|  |  |  |           group: group.name, | 
					
						
							|  |  |  |           evaluateEvery: group.interval || defaultFormValues.evaluateEvery, | 
					
						
							|  |  |  |           evaluateFor: rule.for || '0', | 
					
						
							|  |  |  |           noDataState: ga.no_data_state, | 
					
						
							|  |  |  |           execErrState: ga.exec_err_state, | 
					
						
							|  |  |  |           queries: ga.data, | 
					
						
							|  |  |  |           condition: ga.condition, | 
					
						
							|  |  |  |           annotations: normalizeDefaultAnnotations(listifyLabelsOrAnnotations(rule.annotations, false)), | 
					
						
							|  |  |  |           labels: listifyLabelsOrAnnotations(rule.labels, true), | 
					
						
							|  |  |  |           folder: { title: namespace, uid: ga.namespace_uid }, | 
					
						
							|  |  |  |           isPaused: ga.is_paused, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           contactPoints: routingSettings, | 
					
						
							|  |  |  |           manualRouting: Boolean(routingSettings), | 
					
						
							| 
									
										
										
										
											2024-09-26 14:33:14 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |           editorSettings: getEditorSettingsFromDTO(ga), | 
					
						
							| 
									
										
										
										
											2024-07-26 19:52:22 +08:00
										 |  |  |         }; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         throw new Error('Unexpected type of rule for grafana rules source'); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2021-04-16 16:08:26 +08:00
										 |  |  |     } else { | 
					
						
							|  |  |  |       throw new Error('Unexpected type of rule for grafana rules source'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } else { | 
					
						
							| 
									
										
										
										
											2024-07-26 19:52:22 +08:00
										 |  |  |     // DATASOURCE-MANAGED RULES
 | 
					
						
							| 
									
										
										
										
											2021-04-16 16:08:26 +08:00
										 |  |  |     if (isAlertingRulerRule(rule)) { | 
					
						
							| 
									
										
										
										
											2023-08-04 22:46:58 +08:00
										 |  |  |       const datasourceUid = getDataSourceSrv().getInstanceSettings(ruleSourceName)?.uid ?? ''; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const defaultQuery = { | 
					
						
							|  |  |  |         refId: 'A', | 
					
						
							|  |  |  |         datasourceUid, | 
					
						
							|  |  |  |         queryType: '', | 
					
						
							|  |  |  |         relativeTimeRange: getDefaultRelativeTimeRange(), | 
					
						
							|  |  |  |         expr: rule.expr, | 
					
						
							|  |  |  |         model: { | 
					
						
							|  |  |  |           refId: 'A', | 
					
						
							|  |  |  |           hide: false, | 
					
						
							|  |  |  |           expr: rule.expr, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-08 18:52:36 +08:00
										 |  |  |       const alertingRuleValues = alertingRulerRuleToRuleForm(rule); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-16 16:08:26 +08:00
										 |  |  |       return { | 
					
						
							|  |  |  |         ...defaultFormValues, | 
					
						
							| 
									
										
										
										
											2022-09-08 18:52:36 +08:00
										 |  |  |         ...alertingRuleValues, | 
					
						
							| 
									
										
										
										
											2023-08-04 22:46:58 +08:00
										 |  |  |         queries: [defaultQuery], | 
					
						
							| 
									
										
										
										
											2023-07-26 04:34:14 +08:00
										 |  |  |         annotations: normalizeDefaultAnnotations(listifyLabelsOrAnnotations(rule.annotations, false)), | 
					
						
							| 
									
										
										
										
											2021-08-24 16:31:56 +08:00
										 |  |  |         type: RuleFormType.cloudAlerting, | 
					
						
							| 
									
										
										
										
											2021-04-16 16:08:26 +08:00
										 |  |  |         dataSourceName: ruleSourceName, | 
					
						
							| 
									
										
										
										
											2021-04-16 19:57:33 +08:00
										 |  |  |         namespace, | 
					
						
							|  |  |  |         group: group.name, | 
					
						
							| 
									
										
										
										
											2021-04-16 16:08:26 +08:00
										 |  |  |       }; | 
					
						
							| 
									
										
										
										
											2021-08-24 16:31:56 +08:00
										 |  |  |     } else if (isRecordingRulerRule(rule)) { | 
					
						
							| 
									
										
										
										
											2022-09-08 18:52:36 +08:00
										 |  |  |       const recordingRuleValues = recordingRulerRuleToRuleForm(rule); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-24 16:31:56 +08:00
										 |  |  |       return { | 
					
						
							|  |  |  |         ...defaultFormValues, | 
					
						
							| 
									
										
										
										
											2022-09-08 18:52:36 +08:00
										 |  |  |         ...recordingRuleValues, | 
					
						
							| 
									
										
										
										
											2021-08-24 16:31:56 +08:00
										 |  |  |         type: RuleFormType.cloudRecording, | 
					
						
							|  |  |  |         dataSourceName: ruleSourceName, | 
					
						
							|  |  |  |         namespace, | 
					
						
							|  |  |  |         group: group.name, | 
					
						
							|  |  |  |       }; | 
					
						
							| 
									
										
										
										
											2021-04-16 16:08:26 +08:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2021-08-24 16:31:56 +08:00
										 |  |  |       throw new Error('Unexpected type of rule for cloud rules source'); | 
					
						
							| 
									
										
										
										
											2021-04-16 16:08:26 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-05-04 22:31:25 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-08 18:52:36 +08:00
										 |  |  | export function alertingRulerRuleToRuleForm( | 
					
						
							|  |  |  |   rule: RulerAlertingRuleDTO | 
					
						
							| 
									
										
										
										
											2023-09-22 04:02:53 +08:00
										 |  |  | ): Pick< | 
					
						
							|  |  |  |   RuleFormValues, | 
					
						
							|  |  |  |   | 'name' | 
					
						
							|  |  |  |   | 'forTime' | 
					
						
							|  |  |  |   | 'forTimeUnit' | 
					
						
							|  |  |  |   | 'keepFiringForTime' | 
					
						
							|  |  |  |   | 'keepFiringForTimeUnit' | 
					
						
							|  |  |  |   | 'expression' | 
					
						
							|  |  |  |   | 'annotations' | 
					
						
							|  |  |  |   | 'labels' | 
					
						
							|  |  |  | > { | 
					
						
							| 
									
										
										
										
											2022-09-08 18:52:36 +08:00
										 |  |  |   const defaultFormValues = getDefaultFormValues(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-02 19:58:04 +08:00
										 |  |  |   const [forTime, forTimeUnit] = rule.for ? parseInterval(rule.for) : [0, 's']; | 
					
						
							| 
									
										
										
										
											2022-09-08 18:52:36 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-22 04:02:53 +08:00
										 |  |  |   const [keepFiringForTime, keepFiringForTimeUnit] = rule.keep_firing_for | 
					
						
							|  |  |  |     ? parseInterval(rule.keep_firing_for) | 
					
						
							|  |  |  |     : [defaultFormValues.keepFiringForTime, defaultFormValues.keepFiringForTimeUnit]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-08 18:52:36 +08:00
										 |  |  |   return { | 
					
						
							|  |  |  |     name: rule.alert, | 
					
						
							|  |  |  |     expression: rule.expr, | 
					
						
							|  |  |  |     forTime, | 
					
						
							|  |  |  |     forTimeUnit, | 
					
						
							| 
									
										
										
										
											2023-09-22 04:02:53 +08:00
										 |  |  |     keepFiringForTime, | 
					
						
							|  |  |  |     keepFiringForTimeUnit, | 
					
						
							| 
									
										
										
										
											2023-06-21 22:15:12 +08:00
										 |  |  |     annotations: listifyLabelsOrAnnotations(rule.annotations, false), | 
					
						
							|  |  |  |     labels: listifyLabelsOrAnnotations(rule.labels, true), | 
					
						
							| 
									
										
										
										
											2022-09-08 18:52:36 +08:00
										 |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function recordingRulerRuleToRuleForm( | 
					
						
							|  |  |  |   rule: RulerRecordingRuleDTO | 
					
						
							|  |  |  | ): Pick<RuleFormValues, 'name' | 'expression' | 'labels'> { | 
					
						
							|  |  |  |   return { | 
					
						
							|  |  |  |     name: rule.record, | 
					
						
							|  |  |  |     expression: rule.expr, | 
					
						
							| 
									
										
										
										
											2023-06-21 22:15:12 +08:00
										 |  |  |     labels: listifyLabelsOrAnnotations(rule.labels, true), | 
					
						
							| 
									
										
										
										
											2022-09-08 18:52:36 +08:00
										 |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-22 16:22:42 +08:00
										 |  |  | export const getDefaultQueries = (isRecordingRule = false): AlertQuery[] => { | 
					
						
							| 
									
										
										
										
											2022-06-28 16:05:53 +08:00
										 |  |  |   const dataSource = getDefaultOrFirstCompatibleDataSource(); | 
					
						
							| 
									
										
										
										
											2021-05-04 22:31:25 +08:00
										 |  |  |   if (!dataSource) { | 
					
						
							| 
									
										
										
										
											2024-10-22 16:22:42 +08:00
										 |  |  |     const expressions = isRecordingRule ? getDefaultExpressionsForRecording('A') : getDefaultExpressions('A', 'B'); | 
					
						
							|  |  |  |     return [...expressions]; | 
					
						
							| 
									
										
										
										
											2021-05-04 22:31:25 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-05-19 15:42:40 +08:00
										 |  |  |   const relativeTimeRange = getDefaultRelativeTimeRange(); | 
					
						
							| 
									
										
										
										
											2021-05-04 22:31:25 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-22 16:22:42 +08:00
										 |  |  |   const expressions = isRecordingRule ? getDefaultExpressionsForRecording('B') : getDefaultExpressions('B', 'C'); | 
					
						
							| 
									
										
										
										
											2024-11-15 18:28:54 +08:00
										 |  |  |   const isLokiOrPrometheus = dataSource?.type === DataSourceType.Prometheus || dataSource?.type === DataSourceType.Loki; | 
					
						
							| 
									
										
										
										
											2021-05-04 22:31:25 +08:00
										 |  |  |   return [ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       refId: 'A', | 
					
						
							|  |  |  |       datasourceUid: dataSource.uid, | 
					
						
							|  |  |  |       queryType: '', | 
					
						
							|  |  |  |       relativeTimeRange, | 
					
						
							|  |  |  |       model: { | 
					
						
							|  |  |  |         refId: 'A', | 
					
						
							| 
									
										
										
										
											2024-11-15 18:28:54 +08:00
										 |  |  |         instant: isLokiOrPrometheus ? true : undefined, | 
					
						
							| 
									
										
										
										
											2021-05-04 22:31:25 +08:00
										 |  |  |       }, | 
					
						
							|  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2024-10-22 16:22:42 +08:00
										 |  |  |     ...expressions, | 
					
						
							| 
									
										
										
										
											2021-05-04 22:31:25 +08:00
										 |  |  |   ]; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-22 20:21:15 +08:00
										 |  |  | export const getDefaultRecordingRulesQueries = ( | 
					
						
							|  |  |  |   rulesSourcesWithRuler: Array<DataSourceInstanceSettings<DataSourceJsonData>> | 
					
						
							|  |  |  | ): AlertQuery[] => { | 
					
						
							|  |  |  |   const relativeTimeRange = getDefaultRelativeTimeRange(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return [ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       refId: 'A', | 
					
						
							|  |  |  |       datasourceUid: rulesSourcesWithRuler[0]?.uid || '', | 
					
						
							|  |  |  |       queryType: '', | 
					
						
							|  |  |  |       relativeTimeRange, | 
					
						
							|  |  |  |       model: { | 
					
						
							|  |  |  |         refId: 'A', | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |   ]; | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2022-10-05 20:35:15 +08:00
										 |  |  | const getDefaultExpressions = (...refIds: [string, string]): AlertQuery[] => { | 
					
						
							|  |  |  |   const refOne = refIds[0]; | 
					
						
							|  |  |  |   const refTwo = refIds[1]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const reduceExpression: ExpressionQuery = { | 
					
						
							|  |  |  |     refId: refIds[0], | 
					
						
							|  |  |  |     type: ExpressionQueryType.reduce, | 
					
						
							| 
									
										
										
										
											2021-10-30 01:57:24 +08:00
										 |  |  |     datasource: { | 
					
						
							|  |  |  |       uid: ExpressionDatasourceUID, | 
					
						
							| 
									
										
										
										
											2021-12-21 22:11:11 +08:00
										 |  |  |       type: ExpressionDatasourceRef.type, | 
					
						
							| 
									
										
										
										
											2021-10-30 01:57:24 +08:00
										 |  |  |     }, | 
					
						
							| 
									
										
										
										
											2021-05-04 22:31:25 +08:00
										 |  |  |     conditions: [ | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         type: 'query', | 
					
						
							|  |  |  |         evaluator: { | 
					
						
							| 
									
										
										
										
											2022-10-05 20:35:15 +08:00
										 |  |  |           params: [], | 
					
						
							| 
									
										
										
										
											2021-05-04 22:31:25 +08:00
										 |  |  |           type: EvalFunction.IsAbove, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         operator: { | 
					
						
							|  |  |  |           type: 'and', | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         query: { | 
					
						
							| 
									
										
										
										
											2022-10-05 20:35:15 +08:00
										 |  |  |           params: [refOne], | 
					
						
							| 
									
										
										
										
											2021-05-04 22:31:25 +08:00
										 |  |  |         }, | 
					
						
							|  |  |  |         reducer: { | 
					
						
							|  |  |  |           params: [], | 
					
						
							|  |  |  |           type: 'last', | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |     ], | 
					
						
							| 
									
										
										
										
											2022-10-05 20:35:15 +08:00
										 |  |  |     reducer: 'last', | 
					
						
							| 
									
										
										
										
											2022-07-12 17:50:58 +08:00
										 |  |  |     expression: 'A', | 
					
						
							| 
									
										
										
										
											2021-05-04 22:31:25 +08:00
										 |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-05 20:35:15 +08:00
										 |  |  |   const thresholdExpression: ExpressionQuery = { | 
					
						
							|  |  |  |     refId: refTwo, | 
					
						
							|  |  |  |     type: ExpressionQueryType.threshold, | 
					
						
							|  |  |  |     datasource: { | 
					
						
							|  |  |  |       uid: ExpressionDatasourceUID, | 
					
						
							|  |  |  |       type: ExpressionDatasourceRef.type, | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     conditions: [ | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         type: 'query', | 
					
						
							|  |  |  |         evaluator: { | 
					
						
							|  |  |  |           params: [0], | 
					
						
							|  |  |  |           type: EvalFunction.IsAbove, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         operator: { | 
					
						
							|  |  |  |           type: 'and', | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         query: { | 
					
						
							|  |  |  |           params: [refTwo], | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         reducer: { | 
					
						
							|  |  |  |           params: [], | 
					
						
							|  |  |  |           type: 'last', | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |     ], | 
					
						
							|  |  |  |     expression: refOne, | 
					
						
							| 
									
										
										
										
											2021-05-04 22:31:25 +08:00
										 |  |  |   }; | 
					
						
							| 
									
										
										
										
											2022-10-05 20:35:15 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return [ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       refId: refOne, | 
					
						
							|  |  |  |       datasourceUid: ExpressionDatasourceUID, | 
					
						
							|  |  |  |       queryType: '', | 
					
						
							|  |  |  |       model: reduceExpression, | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       refId: refTwo, | 
					
						
							|  |  |  |       datasourceUid: ExpressionDatasourceUID, | 
					
						
							|  |  |  |       queryType: '', | 
					
						
							|  |  |  |       model: thresholdExpression, | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |   ]; | 
					
						
							| 
									
										
										
										
											2021-05-04 22:31:25 +08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2024-10-22 16:22:42 +08:00
										 |  |  | const getDefaultExpressionsForRecording = (refOne: string): AlertQuery[] => { | 
					
						
							|  |  |  |   const reduceExpression: ExpressionQuery = { | 
					
						
							|  |  |  |     refId: refOne, | 
					
						
							|  |  |  |     type: ExpressionQueryType.reduce, | 
					
						
							|  |  |  |     datasource: { | 
					
						
							|  |  |  |       uid: ExpressionDatasourceUID, | 
					
						
							|  |  |  |       type: ExpressionDatasourceRef.type, | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     conditions: [ | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         type: 'query', | 
					
						
							|  |  |  |         evaluator: { | 
					
						
							|  |  |  |           params: [], | 
					
						
							|  |  |  |           type: EvalFunction.IsAbove, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         operator: { | 
					
						
							|  |  |  |           type: 'and', | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         query: { | 
					
						
							|  |  |  |           params: [refOne], | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         reducer: { | 
					
						
							|  |  |  |           params: [], | 
					
						
							|  |  |  |           type: 'last', | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |     ], | 
					
						
							|  |  |  |     reducer: 'last', | 
					
						
							|  |  |  |     expression: 'A', | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return [ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       refId: refOne, | 
					
						
							|  |  |  |       datasourceUid: ExpressionDatasourceUID, | 
					
						
							|  |  |  |       queryType: '', | 
					
						
							|  |  |  |       model: reduceExpression, | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |   ]; | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2021-05-17 15:39:42 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 15:59:48 +08:00
										 |  |  | const dataQueriesToGrafanaQueries = async ( | 
					
						
							| 
									
										
										
										
											2021-05-17 15:39:42 +08:00
										 |  |  |   queries: DataQuery[], | 
					
						
							|  |  |  |   relativeTimeRange: RelativeTimeRange, | 
					
						
							| 
									
										
										
										
											2021-08-10 15:59:48 +08:00
										 |  |  |   scopedVars: ScopedVars | {}, | 
					
						
							| 
									
										
										
										
											2021-10-30 01:57:24 +08:00
										 |  |  |   panelDataSourceRef?: DataSourceRef, | 
					
						
							| 
									
										
										
										
											2021-08-10 15:59:48 +08:00
										 |  |  |   maxDataPoints?: number, | 
					
						
							|  |  |  |   minInterval?: string | 
					
						
							|  |  |  | ): Promise<AlertQuery[]> => { | 
					
						
							|  |  |  |   const result: AlertQuery[] = []; | 
					
						
							| 
									
										
										
										
											2021-10-30 01:57:24 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 15:59:48 +08:00
										 |  |  |   for (const target of queries) { | 
					
						
							| 
									
										
										
										
											2021-10-30 01:57:24 +08:00
										 |  |  |     const datasource = await getDataSourceSrv().get(target.datasource?.uid ? target.datasource : panelDataSourceRef); | 
					
						
							|  |  |  |     const dsRef = { uid: datasource.uid, type: datasource.type }; | 
					
						
							| 
									
										
										
										
											2021-08-10 15:59:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const range = rangeUtil.relativeToTimeRange(relativeTimeRange); | 
					
						
							|  |  |  |     const { interval, intervalMs } = getIntervals(range, minInterval ?? datasource.interval, maxDataPoints); | 
					
						
							|  |  |  |     const queryVariables = { | 
					
						
							|  |  |  |       __interval: { text: interval, value: interval }, | 
					
						
							|  |  |  |       __interval_ms: { text: intervalMs, value: intervalMs }, | 
					
						
							|  |  |  |       ...scopedVars, | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2021-10-30 01:57:24 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 15:59:48 +08:00
										 |  |  |     const interpolatedTarget = datasource.interpolateVariablesInQueries | 
					
						
							| 
									
										
										
										
											2024-02-07 19:59:18 +08:00
										 |  |  |       ? datasource.interpolateVariablesInQueries([target], queryVariables)[0] | 
					
						
							| 
									
										
										
										
											2021-08-10 15:59:48 +08:00
										 |  |  |       : target; | 
					
						
							| 
									
										
										
										
											2021-10-30 01:57:24 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // expressions
 | 
					
						
							|  |  |  |     if (dsRef.uid === ExpressionDatasourceUID) { | 
					
						
							|  |  |  |       const newQuery: AlertQuery = { | 
					
						
							|  |  |  |         refId: interpolatedTarget.refId, | 
					
						
							|  |  |  |         queryType: '', | 
					
						
							|  |  |  |         relativeTimeRange, | 
					
						
							|  |  |  |         datasourceUid: ExpressionDatasourceUID, | 
					
						
							|  |  |  |         model: interpolatedTarget, | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |       result.push(newQuery); | 
					
						
							|  |  |  |       // queries
 | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       const datasourceSettings = getDataSourceSrv().getInstanceSettings(dsRef); | 
					
						
							|  |  |  |       if (datasourceSettings && datasourceSettings.meta.alerting) { | 
					
						
							| 
									
										
										
										
											2021-05-27 18:29:10 +08:00
										 |  |  |         const newQuery: AlertQuery = { | 
					
						
							| 
									
										
										
										
											2021-08-10 15:59:48 +08:00
										 |  |  |           refId: interpolatedTarget.refId, | 
					
						
							| 
									
										
										
										
											2021-10-30 01:57:24 +08:00
										 |  |  |           queryType: interpolatedTarget.queryType ?? '', | 
					
						
							| 
									
										
										
										
											2021-05-17 15:39:42 +08:00
										 |  |  |           relativeTimeRange, | 
					
						
							| 
									
										
										
										
											2021-10-30 01:57:24 +08:00
										 |  |  |           datasourceUid: datasourceSettings.uid, | 
					
						
							|  |  |  |           model: { | 
					
						
							|  |  |  |             ...interpolatedTarget, | 
					
						
							|  |  |  |             maxDataPoints, | 
					
						
							|  |  |  |             intervalMs, | 
					
						
							|  |  |  |           }, | 
					
						
							| 
									
										
										
										
											2021-05-17 15:39:42 +08:00
										 |  |  |         }; | 
					
						
							| 
									
										
										
										
											2021-08-10 15:59:48 +08:00
										 |  |  |         result.push(newQuery); | 
					
						
							| 
									
										
										
										
											2021-05-17 15:39:42 +08:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-08-10 15:59:48 +08:00
										 |  |  |   } | 
					
						
							|  |  |  |   return result; | 
					
						
							| 
									
										
										
										
											2021-05-17 15:39:42 +08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 15:59:48 +08:00
										 |  |  | export const panelToRuleFormValues = async ( | 
					
						
							| 
									
										
										
										
											2021-05-17 15:39:42 +08:00
										 |  |  |   panel: PanelModel, | 
					
						
							|  |  |  |   dashboard: DashboardModel | 
					
						
							| 
									
										
										
										
											2021-08-10 15:59:48 +08:00
										 |  |  | ): Promise<Partial<RuleFormValues> | undefined> => { | 
					
						
							| 
									
										
										
										
											2021-05-17 15:39:42 +08:00
										 |  |  |   const { targets } = panel; | 
					
						
							| 
									
										
										
										
											2021-10-13 14:53:36 +08:00
										 |  |  |   if (!panel.id || !dashboard.uid) { | 
					
						
							| 
									
										
										
										
											2021-05-17 15:39:42 +08:00
										 |  |  |     return undefined; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const relativeTimeRange = rangeUtil.timeRangeToRelative(rangeUtil.convertRawToRange(dashboard.time)); | 
					
						
							| 
									
										
										
										
											2021-08-10 15:59:48 +08:00
										 |  |  |   const queries = await dataQueriesToGrafanaQueries( | 
					
						
							|  |  |  |     targets, | 
					
						
							|  |  |  |     relativeTimeRange, | 
					
						
							|  |  |  |     panel.scopedVars || {}, | 
					
						
							|  |  |  |     panel.datasource ?? undefined, | 
					
						
							|  |  |  |     panel.maxDataPoints ?? undefined, | 
					
						
							|  |  |  |     panel.interval ?? undefined | 
					
						
							|  |  |  |   ); | 
					
						
							| 
									
										
										
										
											2021-05-17 15:39:42 +08:00
										 |  |  |   // if no alerting capable queries are found, can't create a rule
 | 
					
						
							|  |  |  |   if (!queries.length || !queries.find((query) => query.datasourceUid !== ExpressionDatasourceUID)) { | 
					
						
							|  |  |  |     return undefined; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!queries.find((query) => query.datasourceUid === ExpressionDatasourceUID)) { | 
					
						
							| 
									
										
										
										
											2024-05-10 19:00:17 +08:00
										 |  |  |     const [reduceExpression, _thresholdExpression] = getDefaultExpressions(getNextRefId(queries), '-'); | 
					
						
							| 
									
										
										
										
											2022-10-05 20:35:15 +08:00
										 |  |  |     queries.push(reduceExpression); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const [_reduceExpression, thresholdExpression] = getDefaultExpressions( | 
					
						
							|  |  |  |       reduceExpression.refId, | 
					
						
							| 
									
										
										
										
											2024-05-10 19:00:17 +08:00
										 |  |  |       getNextRefId(queries) | 
					
						
							| 
									
										
										
										
											2022-10-05 20:35:15 +08:00
										 |  |  |     ); | 
					
						
							|  |  |  |     queries.push(thresholdExpression); | 
					
						
							| 
									
										
										
										
											2021-05-17 15:39:42 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-19 19:32:17 +08:00
										 |  |  |   const { folderTitle, folderUid } = dashboard.meta; | 
					
						
							| 
									
										
										
										
											2024-11-19 18:41:31 +08:00
										 |  |  |   const folder = | 
					
						
							|  |  |  |     folderUid && folderTitle | 
					
						
							|  |  |  |       ? { | 
					
						
							|  |  |  |           kind: 'folder', | 
					
						
							|  |  |  |           uid: folderUid, | 
					
						
							|  |  |  |           title: folderTitle, | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       : undefined; | 
					
						
							| 
									
										
										
										
											2021-05-17 15:39:42 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   const formValues = { | 
					
						
							| 
									
										
										
										
											2021-05-19 00:14:57 +08:00
										 |  |  |     type: RuleFormType.grafana, | 
					
						
							| 
									
										
										
										
											2024-11-19 18:41:31 +08:00
										 |  |  |     folder, | 
					
						
							| 
									
										
										
										
											2021-05-17 15:39:42 +08:00
										 |  |  |     queries, | 
					
						
							|  |  |  |     name: panel.title, | 
					
						
							| 
									
										
										
										
											2021-08-10 15:59:48 +08:00
										 |  |  |     condition: queries[queries.length - 1].refId, | 
					
						
							| 
									
										
										
										
											2021-05-17 15:39:42 +08:00
										 |  |  |     annotations: [ | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         key: Annotation.dashboardUID, | 
					
						
							|  |  |  |         value: dashboard.uid, | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         key: Annotation.panelID, | 
					
						
							| 
									
										
										
										
											2021-10-13 14:53:36 +08:00
										 |  |  |         value: String(panel.id), | 
					
						
							| 
									
										
										
										
											2021-05-17 15:39:42 +08:00
										 |  |  |       }, | 
					
						
							|  |  |  |     ], | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  |   return formValues; | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2021-08-10 15:59:48 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-07 19:59:18 +08:00
										 |  |  | export const scenesPanelToRuleFormValues = async (vizPanel: VizPanel): Promise<Partial<RuleFormValues> | undefined> => { | 
					
						
							|  |  |  |   if (!vizPanel.state.key) { | 
					
						
							|  |  |  |     return undefined; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const timeRange = sceneGraph.getTimeRange(vizPanel); | 
					
						
							|  |  |  |   const queryRunner = getQueryRunnerFor(vizPanel); | 
					
						
							|  |  |  |   if (!queryRunner) { | 
					
						
							|  |  |  |     return undefined; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   const { queries, datasource, maxDataPoints, minInterval } = queryRunner.state; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const dashboard = getDashboardSceneFor(vizPanel); | 
					
						
							|  |  |  |   if (!dashboard || !dashboard.state.uid) { | 
					
						
							|  |  |  |     return undefined; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const grafanaQueries = await dataQueriesToGrafanaQueries( | 
					
						
							|  |  |  |     queries, | 
					
						
							|  |  |  |     rangeUtil.timeRangeToRelative(rangeUtil.convertRawToRange(timeRange.state.value.raw)), | 
					
						
							|  |  |  |     { __sceneObject: { value: vizPanel } }, | 
					
						
							|  |  |  |     datasource, | 
					
						
							|  |  |  |     maxDataPoints, | 
					
						
							|  |  |  |     minInterval | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // if no alerting capable queries are found, can't create a rule
 | 
					
						
							|  |  |  |   if (!grafanaQueries.length || !grafanaQueries.find((query) => query.datasourceUid !== ExpressionDatasourceUID)) { | 
					
						
							|  |  |  |     return undefined; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!grafanaQueries.find((query) => query.datasourceUid === ExpressionDatasourceUID)) { | 
					
						
							| 
									
										
										
										
											2024-05-10 19:00:17 +08:00
										 |  |  |     const [reduceExpression, _thresholdExpression] = getDefaultExpressions(getNextRefId(grafanaQueries), '-'); | 
					
						
							| 
									
										
										
										
											2024-02-07 19:59:18 +08:00
										 |  |  |     grafanaQueries.push(reduceExpression); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const [_reduceExpression, thresholdExpression] = getDefaultExpressions( | 
					
						
							|  |  |  |       reduceExpression.refId, | 
					
						
							| 
									
										
										
										
											2024-05-10 19:00:17 +08:00
										 |  |  |       getNextRefId(grafanaQueries) | 
					
						
							| 
									
										
										
										
											2024-02-07 19:59:18 +08:00
										 |  |  |     ); | 
					
						
							|  |  |  |     grafanaQueries.push(thresholdExpression); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const { folderTitle, folderUid } = dashboard.state.meta; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-19 18:41:31 +08:00
										 |  |  |   const folder = | 
					
						
							|  |  |  |     folderUid && folderTitle | 
					
						
							|  |  |  |       ? { | 
					
						
							|  |  |  |           kind: 'folder', | 
					
						
							|  |  |  |           uid: folderUid, | 
					
						
							|  |  |  |           title: folderTitle, | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       : undefined; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-07 19:59:18 +08:00
										 |  |  |   const formValues = { | 
					
						
							|  |  |  |     type: RuleFormType.grafana, | 
					
						
							| 
									
										
										
										
											2024-11-19 18:41:31 +08:00
										 |  |  |     folder, | 
					
						
							| 
									
										
										
										
											2024-02-07 19:59:18 +08:00
										 |  |  |     queries: grafanaQueries, | 
					
						
							|  |  |  |     name: vizPanel.state.title, | 
					
						
							|  |  |  |     condition: grafanaQueries[grafanaQueries.length - 1].refId, | 
					
						
							|  |  |  |     annotations: [ | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         key: Annotation.dashboardUID, | 
					
						
							|  |  |  |         value: dashboard.state.uid, | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         key: Annotation.panelID, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         value: String(getPanelIdForVizPanel(vizPanel)), | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |     ], | 
					
						
							|  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2024-11-19 18:41:31 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-07 19:59:18 +08:00
										 |  |  |   return formValues; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 15:59:48 +08:00
										 |  |  | export function getIntervals(range: TimeRange, lowLimit?: string, resolution?: number): IntervalValues { | 
					
						
							|  |  |  |   if (!resolution) { | 
					
						
							|  |  |  |     if (lowLimit && rangeUtil.intervalToMs(lowLimit) > 1000) { | 
					
						
							|  |  |  |       return { | 
					
						
							|  |  |  |         interval: lowLimit, | 
					
						
							|  |  |  |         intervalMs: rangeUtil.intervalToMs(lowLimit), | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return { interval: '1s', intervalMs: 1000 }; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return rangeUtil.calculateInterval(range, resolution, lowLimit); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-10-27 23:22:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | export function fixBothInstantAndRangeQuery(query: AlertQuery) { | 
					
						
							|  |  |  |   const model = query.model; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!isPromQuery(model)) { | 
					
						
							|  |  |  |     return query; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const isBothInstantAndRange = model.instant && model.range; | 
					
						
							|  |  |  |   if (isBothInstantAndRange) { | 
					
						
							|  |  |  |     return { ...query, model: { ...model, range: true, instant: false } }; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return query; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function isPromQuery(model: AlertDataQuery): model is PromQuery { | 
					
						
							|  |  |  |   return 'expr' in model && 'instant' in model && 'range' in model; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-03-30 02:42:47 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | export function isPromOrLokiQuery(model: AlertDataQuery): model is PromOrLokiQuery { | 
					
						
							|  |  |  |   return 'expr' in model; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-10-12 15:04:59 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // 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.
 | 
					
						
							|  |  |  | export const ignoreHiddenQueries = (ruleDefinition: RuleFormValues): RuleFormValues => { | 
					
						
							|  |  |  |   return { | 
					
						
							|  |  |  |     ...ruleDefinition, | 
					
						
							|  |  |  |     queries: ruleDefinition.queries?.map((query) => omit(query, 'model.hide')), | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function formValuesFromExistingRule(rule: RuleWithLocation<RulerRuleDTO>) { | 
					
						
							|  |  |  |   return ignoreHiddenQueries(rulerRuleToFormValues(rule)); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2024-11-15 18:28:54 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 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; | 
					
						
							|  |  |  | } |