From d399f116b805ba210e09040e5fdc6c008a0e9b5e Mon Sep 17 00:00:00 2001 From: Konrad Lalik Date: Thu, 30 Oct 2025 10:28:15 +0100 Subject: [PATCH] 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 --- .../InstanceDetailsDrawer.tsx | 37 +++++++++++++----- .../InstanceDetailsDrawerTitle.tsx | 39 +++++++++++++++++++ public/locales/en-US/grafana.json | 7 ++-- 3 files changed, 69 insertions(+), 14 deletions(-) create mode 100644 public/app/features/alerting/unified/triage/instance-details/InstanceDetailsDrawerTitle.tsx diff --git a/public/app/features/alerting/unified/triage/instance-details/InstanceDetailsDrawer.tsx b/public/app/features/alerting/unified/triage/instance-details/InstanceDetailsDrawer.tsx index 704c4d54c47..7ce7e9ae6f7 100644 --- a/public/app/features/alerting/unified/triage/instance-details/InstanceDetailsDrawer.tsx +++ b/public/app/features/alerting/unified/triage/instance-details/InstanceDetailsDrawer.tsx @@ -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 ( - + } onClose={onClose} size="md"> ); @@ -74,15 +74,15 @@ export function InstanceDetailsDrawer({ ruleUID, instanceLabels, onClose }: Inst if (loading || !rule) { return ( - -
{t('alerting.common.loading', 'Loading...')}
+ } onClose={onClose} size="md"> + ); } return ( } onClose={onClose} size="lg" > @@ -106,10 +106,6 @@ export function InstanceDetailsDrawer({ ruleUID, instanceLabels, onClose }: Inst )} - - - - {t('alerting.instance-details.state-history', 'Recent State Changes')} {stateHistoryFetching && } @@ -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 ( + + + + {folderTitle} + + {groupName} + + {ruleName} + + + ); +} + function extractQueryDetails(rule: GrafanaRuleDefinition) { const dataQueries = rule.data.filter((query: AlertQuery) => isAlertQueryOfAlertData(query)); diff --git a/public/app/features/alerting/unified/triage/instance-details/InstanceDetailsDrawerTitle.tsx b/public/app/features/alerting/unified/triage/instance-details/InstanceDetailsDrawerTitle.tsx new file mode 100644 index 00000000000..1b07cdb284f --- /dev/null +++ b/public/app/features/alerting/unified/triage/instance-details/InstanceDetailsDrawerTitle.tsx @@ -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 ( + + + Instance details + + + + {Object.keys(instanceLabels).length > 0 ? ( + + ) : ( + {t('alerting.triage.no-labels', 'No labels')} + )} + + + + {folder && rule && ( + + )} + + ); +} diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index 2d5bd426837..b687292e3ad 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -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",