import { css } from '@emotion/css'; import { formatDistanceToNowStrict } from 'date-fns'; import { useCallback } from 'react'; import { GrafanaTheme2 } from '@grafana/data'; import { Text, Stack, useStyles2, ClipboardButton, TextLink } from '@grafana/ui'; import { CombinedRule } from 'app/types/unified-alerting'; import { Annotations } from 'app/types/unified-alerting-dto'; import { isGrafanaRulerRule, isRecordingRulerRule } from '../../../utils/rules'; import { MetaText } from '../../MetaText'; import { Tokenize } from '../../Tokenize'; interface DetailsProps { rule: CombinedRule; } enum RuleType { GrafanaManagedAlertRule = 'Grafana-managed alert rule', CloudAlertRule = 'Cloud alert rule', CloudRecordingRule = 'Cloud recording rule', } const Details = ({ rule }: DetailsProps) => { const styles = useStyles2(getStyles); let ruleType: RuleType; if (isGrafanaRulerRule(rule.rulerRule)) { ruleType = RuleType.GrafanaManagedAlertRule; } else if (isRecordingRulerRule(rule.rulerRule)) { ruleType = RuleType.CloudRecordingRule; } else { // probably not the greatest assumption ruleType = RuleType.CloudAlertRule; } const evaluationDuration = rule.promRule?.evaluationTime; const evaluationTimestamp = rule.promRule?.lastEvaluation; const copyRuleUID = useCallback(() => { if (isGrafanaRulerRule(rule.rulerRule)) { return rule.rulerRule.grafana_alert.uid; } else { return ''; } }, [rule.rulerRule]); const annotations: Annotations | undefined = !isRecordingRulerRule(rule.rulerRule) ? rule.annotations ?? [] : undefined; const hasEvaluationDuration = Number.isFinite(evaluationDuration); return (
{/* type and identifier (optional) */} Rule type {ruleType} {isGrafanaRulerRule(rule.rulerRule) && ( <> Rule Identifier {rule.rulerRule.grafana_alert.uid} )} {/* evaluation duration and pending period */} {hasEvaluationDuration && ( <> Last evaluation {evaluationTimestamp && evaluationDuration ? ( {formatDistanceToNowStrict(new Date(evaluationTimestamp))} ago, took{' '} {evaluationDuration}ms ) : null} )} {!isRecordingRulerRule(rule.rulerRule) && ( <> Pending period {rule.rulerRule?.for ?? '0s'} )} {/* nodata and execution error state mapping */} {isGrafanaRulerRule(rule.rulerRule) && ( <> Alert state if no data or all values are null {rule.rulerRule.grafana_alert.no_data_state} Alert state if execution error or timeout {rule.rulerRule.grafana_alert.exec_err_state} )}
{/* annotations go here */} {annotations && ( <> Annotations {Object.keys(annotations).length === 0 ? ( No annotations ) : (
{Object.entries(annotations).map(([name, value]) => ( {name} ))}
)} )}
); }; interface AnnotationValueProps { value: string; } export function AnnotationValue({ value }: AnnotationValueProps) { const needsExternalLink = value && value.startsWith('http'); const tokenizeValue = ; if (needsExternalLink) { return ( {value} ); } return {tokenizeValue}; } const getStyles = (theme: GrafanaTheme2) => ({ metadataWrapper: css({ display: 'grid', gridTemplateColumns: 'auto auto', rowGap: theme.spacing(3), columnGap: theme.spacing(12), }), }); export { Details };