Submit
Path:
~
/
/
usr
/
share
/
grafana
/
public
/
app
/
features
/
alerting
/
unified
/
components
/
rule-viewer
/
tabs
/
File Content:
Details.tsx
import { css } from '@emotion/css'; import { formatDistanceToNowStrict } from 'date-fns'; import React, { 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 ( <Stack direction="column" gap={3}> <div className={styles.metadataWrapper}> {/* type and identifier (optional) */} <MetaText direction="column"> Rule type <Text color="primary">{ruleType}</Text> </MetaText> <MetaText direction="column"> {isGrafanaRulerRule(rule.rulerRule) && ( <> Rule Identifier <Stack direction="row" alignItems="center" gap={0.5}> <Text color="primary"> {rule.rulerRule.grafana_alert.uid} <ClipboardButton fill="text" variant="secondary" icon="copy" size="sm" getText={copyRuleUID} /> </Text> </Stack> </> )} </MetaText> {/* evaluation duration and pending period */} <MetaText direction="column"> {hasEvaluationDuration && ( <> Last evaluation {evaluationTimestamp && evaluationDuration && ( <span> <Text color="primary">{formatDistanceToNowStrict(new Date(evaluationTimestamp))} ago</Text>, took{' '} <Text color="primary">{evaluationDuration}ms</Text> </span> )} </> )} </MetaText> <MetaText direction="column"> {!isRecordingRulerRule(rule.rulerRule) && ( <> Pending period <Text color="primary">{rule.rulerRule?.for ?? '0s'}</Text> </> )} </MetaText> {/* nodata and execution error state mapping */} {isGrafanaRulerRule(rule.rulerRule) && ( <> <MetaText direction="column"> Alert state if no data or all values are null <Text color="primary">{rule.rulerRule.grafana_alert.no_data_state}</Text> </MetaText> <MetaText direction="column"> Alert state if execution error or timeout <Text color="primary">{rule.rulerRule.grafana_alert.exec_err_state}</Text> </MetaText> </> )} </div> {/* annotations go here */} {annotations && ( <> <Text variant="h4">Annotations</Text> {Object.keys(annotations).length === 0 ? ( <Text variant="bodySmall" color="secondary" italic> No annotations </Text> ) : ( <div className={styles.metadataWrapper}> {Object.entries(annotations).map(([name, value]) => ( <MetaText direction="column" key={name}> {name} <AnnotationValue value={value} /> </MetaText> ))} </div> )} </> )} </Stack> ); }; interface AnnotationValueProps { value: string; } function AnnotationValue({ value }: AnnotationValueProps) { const needsExternalLink = value && value.startsWith('http'); const tokenizeValue = <Tokenize input={value} delimiter={['{{', '}}']} />; if (needsExternalLink) { return ( <TextLink variant="bodySmall" href={value} external> {value} </TextLink> ); } return <Text color="primary">{tokenizeValue}</Text>; } const getStyles = (theme: GrafanaTheme2) => ({ metadataWrapper: css({ display: 'grid', gridTemplateColumns: 'auto auto', rowGap: theme.spacing(3), columnGap: theme.spacing(12), }), }); export { Details };
Submit
FILE
FOLDER
INFO
Name
Size
Permission
Action
Details.tsx
5210 bytes
0644
History.tsx
1600 bytes
0644
Instances.tsx
498 bytes
0644
Query.tsx
4604 bytes
0644
Routing.tsx
85 bytes
0644
N4ST4R_ID | Naxtarrr