From b1cdd45ca4b258a57ddb3a23266e501cc8704425 Mon Sep 17 00:00:00 2001 From: Konrad Lalik Date: Fri, 1 Aug 2025 15:36:46 +0200 Subject: [PATCH] Alerting: List V2 - datasource icons for rules (#109033) Add datasource icons to the rule list item components --- .../unified/rule-list/GrafanaRuleListItem.tsx | 1 + .../components/AlertRuleListItem.tsx | 72 +++++++++++++++++-- .../unified/rule-list/components/ListItem.tsx | 4 +- 3 files changed, 71 insertions(+), 6 deletions(-) diff --git a/public/app/features/alerting/unified/rule-list/GrafanaRuleListItem.tsx b/public/app/features/alerting/unified/rule-list/GrafanaRuleListItem.tsx index 5667069082b..ed90116bcaa 100644 --- a/public/app/features/alerting/unified/rule-list/GrafanaRuleListItem.tsx +++ b/public/app/features/alerting/unified/rule-list/GrafanaRuleListItem.tsx @@ -53,6 +53,7 @@ export function GrafanaRuleListItem({ isPaused: rule?.isPaused, application: 'grafana' as const, actions: , + querySourceUIDs: rule?.queriedDatasourceUIDs, }; if (prometheusRuleType.grafana.alertingRule(rule)) { diff --git a/public/app/features/alerting/unified/rule-list/components/AlertRuleListItem.tsx b/public/app/features/alerting/unified/rule-list/components/AlertRuleListItem.tsx index 5117a8516bd..2694bfc580d 100644 --- a/public/app/features/alerting/unified/rule-list/components/AlertRuleListItem.tsx +++ b/public/app/features/alerting/unified/rule-list/components/AlertRuleListItem.tsx @@ -1,8 +1,8 @@ -import { css } from '@emotion/css'; +import { css, cx } from '@emotion/css'; import pluralize from 'pluralize'; -import { ReactNode, useEffect, useId } from 'react'; +import { ReactNode, forwardRef, memo, useEffect, useId } from 'react'; -import { GrafanaTheme2 } from '@grafana/data'; +import { DataSourceInstanceSettings, GrafanaTheme2 } from '@grafana/data'; import { Trans, t } from '@grafana/i18n'; import { Alert, Stack, Text, TextLink, Tooltip, useStyles2 } from '@grafana/ui'; import { Rule, RuleGroupIdentifierV2, RuleHealth, RulesSourceIdentifier } from 'app/types/unified-alerting'; @@ -13,7 +13,7 @@ import { AlertLabels } from '../../components/AlertLabels'; import { MetaText } from '../../components/MetaText'; import { ProvisioningBadge } from '../../components/Provisioning'; import { PluginOriginBadge } from '../../plugins/PluginOriginBadge'; -import { GRAFANA_RULES_SOURCE_NAME } from '../../utils/datasource'; +import { GRAFANA_RULES_SOURCE_NAME, getDataSourceByUid } from '../../utils/datasource'; import { getGroupOriginName } from '../../utils/groupIdentifier'; import { labelsSize } from '../../utils/labels'; import { createContactPointSearchLink } from '../../utils/misc'; @@ -49,6 +49,7 @@ export interface AlertRuleListItemProps { operation?: RuleOperation; // the grouped view doesn't need to show the location again – it's redundant showLocation?: boolean; + querySourceUIDs?: string[]; } export const AlertRuleListItem = (props: AlertRuleListItemProps) => { @@ -75,6 +76,7 @@ export const AlertRuleListItem = (props: AlertRuleListItemProps) => { actions = null, operation, showLocation = true, + querySourceUIDs = [], } = props; const listItemAriaId = useId(); @@ -94,6 +96,10 @@ export const AlertRuleListItem = (props: AlertRuleListItemProps) => { ); } + if (querySourceUIDs.length > 0) { + metadata.push(); + } + if (!isPaused) { if (lastEvaluation && evaluationInterval) { metadata.push( @@ -179,6 +185,7 @@ export function RecordingRuleListItem({ origin, actions, showLocation = true, + querySourceUIDs = [], }: RecordingRuleListItemProps) { const metadata: ReactNode[] = []; if (namespace && group && showLocation) { @@ -195,6 +202,10 @@ export function RecordingRuleListItem({ ); } + if (querySourceUIDs.length > 0) { + metadata.push(); + } + return ( ds !== undefined); + + return ( + + {dataSources.map((dataSource) => { + return ( + + + + ); + })} + + ); +}); + function RuleLabels({ labels }: { labels: Labels }) { const styles = useStyles2(getStyles); @@ -417,3 +451,33 @@ export type RuleListItemCommonProps = Pick< AlertRuleListItemProps, Extract >; + +interface DataSourceLogoProps { + dataSource: DataSourceInstanceSettings; +} + +const DataSourceLogo = forwardRef(({ dataSource }, ref) => { + const styles = useStyles2(dataSourceLogoStyles); + + return ( + {`${dataSource.meta.name} + ); +}); + +const dataSourceLogoStyles = (theme: GrafanaTheme2) => ({ + logo: css({ + height: '14px', + width: '14px', + borderRadius: theme.shape.radius.default, + }), + filter: css({ + filter: `invert(${theme.isLight ? 1 : 0})`, + }), +}); diff --git a/public/app/features/alerting/unified/rule-list/components/ListItem.tsx b/public/app/features/alerting/unified/rule-list/components/ListItem.tsx index ce3ea7f6fb6..0e15e5fb696 100644 --- a/public/app/features/alerting/unified/rule-list/components/ListItem.tsx +++ b/public/app/features/alerting/unified/rule-list/components/ListItem.tsx @@ -39,7 +39,7 @@ export const ListItem = (props: ListItemProps) => { {/* metadata */} - + {meta?.map((item, index) => ( {index > 0 && } @@ -72,7 +72,7 @@ export const SkeletonListItem = () => { const Separator = () => ( - {'·'} + {'|'} );