1import { AlertState } from '@grafana/data';
2import {
3  GrafanaAlertState,
4  PromAlertingRuleState,
5  PromRuleType,
6  RulerAlertingRuleDTO,
7  RulerGrafanaRuleDTO,
8  RulerRecordingRuleDTO,
9  RulerRuleDTO,
10} from 'app/types/unified-alerting-dto';
11import {
12  Alert,
13  AlertingRule,
14  CloudRuleIdentifier,
15  GrafanaRuleIdentifier,
16  PrometheusRuleIdentifier,
17  PromRuleWithLocation,
18  RecordingRule,
19  Rule,
20  RuleIdentifier,
21  RuleNamespace,
22} from 'app/types/unified-alerting';
23import { AsyncRequestState } from './redux';
24import { RULER_NOT_SUPPORTED_MSG } from './constants';
25import { capitalize } from 'lodash';
26import { State } from '../components/StateTag';
27
28export function isAlertingRule(rule: Rule | undefined): rule is AlertingRule {
29  return typeof rule === 'object' && rule.type === PromRuleType.Alerting;
30}
31
32export function isRecordingRule(rule: Rule): rule is RecordingRule {
33  return rule.type === PromRuleType.Recording;
34}
35
36export function isAlertingRulerRule(rule?: RulerRuleDTO): rule is RulerAlertingRuleDTO {
37  return typeof rule === 'object' && 'alert' in rule;
38}
39
40export function isRecordingRulerRule(rule?: RulerRuleDTO): rule is RulerRecordingRuleDTO {
41  return typeof rule === 'object' && 'record' in rule;
42}
43
44export function isGrafanaRulerRule(rule?: RulerRuleDTO): rule is RulerGrafanaRuleDTO {
45  return typeof rule === 'object' && 'grafana_alert' in rule;
46}
47
48export function alertInstanceKey(alert: Alert): string {
49  return JSON.stringify(alert.labels);
50}
51
52export function isRulerNotSupportedResponse(resp: AsyncRequestState<any>) {
53  return resp.error && resp.error?.message?.includes(RULER_NOT_SUPPORTED_MSG);
54}
55
56export function isGrafanaRuleIdentifier(identifier: RuleIdentifier): identifier is GrafanaRuleIdentifier {
57  return 'uid' in identifier;
58}
59
60export function isCloudRuleIdentifier(identifier: RuleIdentifier): identifier is CloudRuleIdentifier {
61  return 'rulerRuleHash' in identifier;
62}
63
64export function isPrometheusRuleIdentifier(identifier: RuleIdentifier): identifier is PrometheusRuleIdentifier {
65  return 'ruleHash' in identifier;
66}
67
68export function alertStateToReadable(state: PromAlertingRuleState | GrafanaAlertState | AlertState): string {
69  if (state === PromAlertingRuleState.Inactive) {
70    return 'Normal';
71  }
72  return capitalize(state);
73}
74
75export const flattenRules = (rules: RuleNamespace[]) => {
76  return rules.reduce<PromRuleWithLocation[]>((acc, { dataSourceName, name: namespaceName, groups }) => {
77    groups.forEach(({ name: groupName, rules }) => {
78      rules.forEach((rule) => {
79        if (isAlertingRule(rule)) {
80          acc.push({ dataSourceName, namespaceName, groupName, rule });
81        }
82      });
83    });
84    return acc;
85  }, []);
86};
87
88export const alertStateToState: Record<PromAlertingRuleState | GrafanaAlertState | AlertState, State> = {
89  [PromAlertingRuleState.Inactive]: 'good',
90  [PromAlertingRuleState.Firing]: 'bad',
91  [PromAlertingRuleState.Pending]: 'warning',
92  [GrafanaAlertState.Alerting]: 'bad',
93  [GrafanaAlertState.Error]: 'bad',
94  [GrafanaAlertState.NoData]: 'info',
95  [GrafanaAlertState.Normal]: 'good',
96  [GrafanaAlertState.Pending]: 'warning',
97  [AlertState.NoData]: 'info',
98  [AlertState.Paused]: 'warning',
99  [AlertState.Alerting]: 'bad',
100  [AlertState.OK]: 'good',
101  [AlertState.Pending]: 'warning',
102  [AlertState.Unknown]: 'info',
103};
104
105export function getFirstActiveAt(promRule: AlertingRule) {
106  if (!promRule.alerts) {
107    return null;
108  }
109  return promRule.alerts.reduce((prev, alert) => {
110    if (alert.activeAt && alert.state !== GrafanaAlertState.Normal) {
111      const activeAt = new Date(alert.activeAt);
112      if (prev === null || prev.getTime() > activeAt.getTime()) {
113        return activeAt;
114      }
115    }
116    return prev;
117  }, null as Date | null);
118}
119