Alerting: Improve instance details drawer in Alerts (#113106)

* Add alert instance breadcrumbs, change instance drawer title

* Update translations

* Add instance drawer title component and unify its usage
This commit is contained in:
Konrad Lalik
2025-10-30 10:28:15 +01:00
committed by GitHub
parent 8b31ec5040
commit d399f116b8
3 changed files with 69 additions and 14 deletions
@@ -3,12 +3,11 @@ import { orderBy } from 'lodash';
import { Fragment, useMemo } from 'react';
import { useMeasure } from 'react-use';
import { AlertLabels } from '@grafana/alerting/unstable';
import { GrafanaTheme2, Labels } from '@grafana/data';
import { t } from '@grafana/i18n';
import { isFetchError } from '@grafana/runtime';
import { TimeRangePicker, useTimeRange } from '@grafana/scenes-react';
import { Alert, Box, Drawer, Icon, LoadingBar, Stack, Text, useStyles2 } from '@grafana/ui';
import { Alert, Box, Drawer, Icon, LoadingBar, LoadingPlaceholder, Stack, Text, useStyles2 } from '@grafana/ui';
import { AlertQuery, GrafanaRuleDefinition } from 'app/types/unified-alerting-dto';
import { alertRuleApi } from '../../api/alertRuleApi';
@@ -19,6 +18,7 @@ import { LogRecord, historyDataFrameToLogRecords } from '../../components/rules/
import { isAlertQueryOfAlertData } from '../../rule-editor/formProcessing';
import { stringifyErrorLike } from '../../utils/misc';
import { InstanceDetailsDrawerTitle } from './InstanceDetailsDrawerTitle';
import { QueryVisualization } from './QueryVisualization';
import { convertStateHistoryToAnnotations } from './stateHistoryUtils';
@@ -66,7 +66,7 @@ export function InstanceDetailsDrawer({ ruleUID, instanceLabels, onClose }: Inst
if (error) {
return (
<Drawer title={t('alerting.triage.instance-details', 'Instance Details')} onClose={onClose} size="md">
<Drawer title={<InstanceDetailsDrawerTitle instanceLabels={instanceLabels} />} onClose={onClose} size="md">
<ErrorContent error={error} />
</Drawer>
);
@@ -74,15 +74,15 @@ export function InstanceDetailsDrawer({ ruleUID, instanceLabels, onClose }: Inst
if (loading || !rule) {
return (
<Drawer title={t('alerting.triage.instance-details', 'Instance Details')} onClose={onClose} size="md">
<div>{t('alerting.common.loading', 'Loading...')}</div>
<Drawer title={<InstanceDetailsDrawerTitle instanceLabels={instanceLabels} />} onClose={onClose} size="md">
<LoadingPlaceholder text={t('alerting.common.loading', 'Loading...')} />
</Drawer>
);
}
return (
<Drawer
title={t('alerting.instance-details-drawer.title-instance-details', 'Instance Details')}
title={<InstanceDetailsDrawerTitle instanceLabels={instanceLabels} rule={rule.grafana_alert} />}
onClose={onClose}
size="lg"
>
@@ -106,10 +106,6 @@ export function InstanceDetailsDrawer({ ruleUID, instanceLabels, onClose }: Inst
</Box>
)}
<Box>
<AlertLabels labels={instanceLabels} />
</Box>
<Box ref={ref}>
<Text variant="h5">{t('alerting.instance-details.state-history', 'Recent State Changes')}</Text>
{stateHistoryFetching && <LoadingBar width={loadingBarWidth} />}
@@ -139,6 +135,27 @@ export function InstanceDetailsDrawer({ ruleUID, instanceLabels, onClose }: Inst
);
}
export interface InstanceLocationProps {
folderTitle: string;
groupName: string;
ruleName: string;
}
export function InstanceLocation({ folderTitle, groupName, ruleName }: InstanceLocationProps) {
return (
<Stack direction="row" alignItems="center" gap={1}>
<Icon size="xs" name="folder" />
<Stack direction="row" alignItems="center" gap={0.5}>
<Text variant="bodySmall">{folderTitle}</Text>
<Icon size="sm" name="angle-right" />
<Text variant="bodySmall">{groupName}</Text>
<Icon size="sm" name="angle-right" />
<Text variant="bodySmall">{ruleName}</Text>
</Stack>
</Stack>
);
}
function extractQueryDetails(rule: GrafanaRuleDefinition) {
const dataQueries = rule.data.filter((query: AlertQuery) => isAlertQueryOfAlertData(query));
@@ -0,0 +1,39 @@
import { AlertLabels } from '@grafana/alerting/unstable';
import { Labels } from '@grafana/data';
import { Trans, t } from '@grafana/i18n';
import { Box, Stack, Text } from '@grafana/ui';
import { GrafanaRuleDefinition } from 'app/types/unified-alerting-dto';
import { stringifyFolder, useFolder } from '../../hooks/useFolder';
import { InstanceLocation } from './InstanceDetailsDrawer';
interface InstanceDetailsDrawerTitleProps {
instanceLabels: Labels;
rule?: GrafanaRuleDefinition;
}
export function InstanceDetailsDrawerTitle({ instanceLabels, rule }: InstanceDetailsDrawerTitleProps) {
const { folder } = useFolder(rule?.namespace_uid);
return (
<Stack direction="column" gap={2}>
<Text variant="h3" element="h3" truncate>
<Trans i18nKey="alerting.triage.instance-details-drawer.instance-details">Instance details</Trans>
</Text>
<Stack direction="row" gap={2}>
<Box flex={3}>
{Object.keys(instanceLabels).length > 0 ? (
<AlertLabels labels={instanceLabels} />
) : (
<Text color="secondary">{t('alerting.triage.no-labels', 'No labels')}</Text>
)}
</Box>
<Box flex={1} />
</Stack>
{folder && rule && (
<InstanceLocation folderTitle={stringifyFolder(folder)} groupName={rule.rule_group} ruleName={rule.title} />
)}
</Stack>
);
}
+3 -4
View File
@@ -1662,9 +1662,6 @@
"no-history": "No recent state changes",
"state-history": "Recent State Changes"
},
"instance-details-drawer": {
"title-instance-details": "Instance Details"
},
"instance-match": {
"non-matching-labels": "Non-matching labels",
"notification-policy": "View route"
@@ -2950,7 +2947,9 @@
"alert-instances": "Alert instances",
"error-loading-rule": "Error loading rule",
"firing-instances-count": "{{firingCount}} firing instances",
"instance-details": "Instance Details",
"instance-details-drawer": {
"instance-details": "Instance details"
},
"no-instances-found": "No alert instances found for rule: {{ruleUID}}",
"no-labels": "No labels",
"open-in-sidebar": "Open in sidebar",