diff --git a/public/app/features/alerting/unified/rule-list/DataSourceRuleListItem.tsx b/public/app/features/alerting/unified/rule-list/DataSourceRuleListItem.tsx
index 3fc7eb8a808..3850092b40d 100644
--- a/public/app/features/alerting/unified/rule-list/DataSourceRuleListItem.tsx
+++ b/public/app/features/alerting/unified/rule-list/DataSourceRuleListItem.tsx
@@ -5,6 +5,7 @@ import { PromRuleType, RulerRuleDTO, RulesSourceApplication } from 'app/types/un
import { createReturnTo } from '../hooks/useReturnTo';
import { Annotation } from '../utils/constants';
+import { groups } from '../utils/navigation';
import { fromRule, fromRulerRule, stringifyIdentifier } from '../utils/rule-id';
import { getRuleName, getRulePluginOrigin, rulerRuleType } from '../utils/rules';
import { createRelativeUrl } from '../utils/url';
@@ -46,11 +47,14 @@ export function DataSourceRuleListItem({
const ruleName = rulerRule ? getRuleName(rulerRule) : rule.name;
const labels = rulerRule ? rulerRule.labels : rule.labels;
+ const groupUrl = groups.detailsPageLink(rulesSource.uid, namespace.name, groupName);
+
const commonProps: RuleListItemCommonProps = {
name: ruleName,
rulesSource: rulesSource,
application: application,
group: groupName,
+ groupUrl,
namespace: namespace.name,
href,
health: rule.health,
diff --git a/public/app/features/alerting/unified/rule-list/FilterView.test.tsx b/public/app/features/alerting/unified/rule-list/FilterView.test.tsx
index 908e5978d88..3a7348048da 100644
--- a/public/app/features/alerting/unified/rule-list/FilterView.test.tsx
+++ b/public/app/features/alerting/unified/rule-list/FilterView.test.tsx
@@ -107,6 +107,30 @@ describe('RuleList - FilterView', () => {
expect(await screen.findByText(/No matching rules found/)).toBeInTheDocument();
});
+
+ it('should render group names as clickable links', async () => {
+ render(
+
+ );
+
+ await loadMoreResults();
+
+ const groupLink = await screen.findByRole('link', {
+ name: 'test-group-4501',
+ });
+
+ expect(groupLink).toBeInTheDocument();
+ expect(groupLink).toHaveAttribute(
+ 'href',
+ '/alerting/mimir/namespaces/test-mimir-namespace/groups/test-group-4501/view'
+ );
+ });
});
async function loadMoreResults() {
diff --git a/public/app/features/alerting/unified/rule-list/GrafanaRuleListItem.tsx b/public/app/features/alerting/unified/rule-list/GrafanaRuleListItem.tsx
index 3113c991e09..5667069082b 100644
--- a/public/app/features/alerting/unified/rule-list/GrafanaRuleListItem.tsx
+++ b/public/app/features/alerting/unified/rule-list/GrafanaRuleListItem.tsx
@@ -1,7 +1,8 @@
import { GrafanaRuleGroupIdentifier } from 'app/types/unified-alerting';
import { GrafanaPromRuleDTO, PromRuleType } from 'app/types/unified-alerting-dto';
-import { GrafanaRulesSource } from '../utils/datasource';
+import { GRAFANA_RULES_SOURCE_NAME, GrafanaRulesSource } from '../utils/datasource';
+import { groups } from '../utils/navigation';
import { totalFromStats } from '../utils/ruleStats';
import { prometheusRuleType } from '../utils/rules';
import { createRelativeUrl } from '../utils/url';
@@ -32,10 +33,17 @@ export function GrafanaRuleListItem({
}: GrafanaRuleListItemProps) {
const { name, uid, labels, provenance } = rule;
+ const groupUrl = groups.detailsPageLink(
+ GRAFANA_RULES_SOURCE_NAME,
+ groupIdentifier.namespace.uid,
+ groupIdentifier.groupName
+ );
+
const commonProps: RuleListItemCommonProps = {
name,
rulesSource: GrafanaRulesSource,
group: groupIdentifier.groupName,
+ groupUrl,
namespace: namespaceName,
href: createRelativeUrl(`/alerting/grafana/${uid}/view`),
health: rule?.health,
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 3f8c01831e6..5117a8516bd 100644
--- a/public/app/features/alerting/unified/rule-list/components/AlertRuleListItem.tsx
+++ b/public/app/features/alerting/unified/rule-list/components/AlertRuleListItem.tsx
@@ -4,7 +4,7 @@ import { ReactNode, useEffect, useId } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Trans, t } from '@grafana/i18n';
-import { Alert, Icon, Stack, Text, TextLink, Tooltip, useStyles2 } from '@grafana/ui';
+import { Alert, Stack, Text, TextLink, Tooltip, useStyles2 } from '@grafana/ui';
import { Rule, RuleGroupIdentifierV2, RuleHealth, RulesSourceIdentifier } from 'app/types/unified-alerting';
import { Labels, PromAlertingRuleState, RulerRuleDTO, RulesSourceApplication } from 'app/types/unified-alerting-dto';
@@ -20,8 +20,8 @@ import { createContactPointSearchLink } from '../../utils/misc';
import { RulePluginOrigin } from '../../utils/rules';
import { ListItem } from './ListItem';
-import { DataSourceIcon } from './Namespace';
import { RuleListIcon, RuleOperation } from './RuleListIcon';
+import { RuleLocation } from './RuleLocation';
import { calculateNextEvaluationEstimate } from './util';
export interface AlertRuleListItemProps {
@@ -39,6 +39,7 @@ export interface AlertRuleListItemProps {
instancesCount?: number;
namespace?: string;
group?: string;
+ groupUrl?: string;
rulesSource?: RulesSourceIdentifier;
application?: RulesSourceApplication;
// used for alert rules that use simplified routing
@@ -65,6 +66,7 @@ export const AlertRuleListItem = (props: AlertRuleListItemProps) => {
instancesCount = 0,
namespace,
group,
+ groupUrl,
rulesSource,
application,
contactPoint,
@@ -81,7 +83,13 @@ export const AlertRuleListItem = (props: AlertRuleListItemProps) => {
if (namespace && group && showLocation) {
metadata.push(
-
+
);
}
@@ -160,6 +168,7 @@ export function RecordingRuleListItem({
name,
namespace,
group,
+ groupUrl,
rulesSource,
application,
href,
@@ -175,7 +184,13 @@ export function RecordingRuleListItem({
if (namespace && group && showLocation) {
metadata.push(
-
+
);
}
@@ -206,6 +221,7 @@ interface RuleOperationListItemProps {
name: string;
namespace: string;
group: string;
+ groupUrl?: string;
rulesSource?: RulesSourceIdentifier;
application?: RulesSourceApplication;
operation: RuleOperation;
@@ -216,6 +232,7 @@ export function RuleOperationListItem({
name,
namespace,
group,
+ groupUrl,
rulesSource,
application,
operation,
@@ -227,7 +244,13 @@ export function RuleOperationListItem({
if (namespace && group && showLocation) {
metadata.push(
-
+
);
}
@@ -368,38 +391,6 @@ export const UnknownRuleListItem = ({ ruleName, groupIdentifier, ruleDefinition
);
};
-interface RuleLocationProps {
- namespace: string;
- group: string;
- rulesSource?: RulesSourceIdentifier;
- application?: RulesSourceApplication;
-}
-
-// @TODO make the datasource / namespace / group click-able to allow further filtering of the list
-export const RuleLocation = ({ namespace, group, rulesSource, application }: RuleLocationProps) => {
- const isGrafanaApp = application === 'grafana';
- const isDataSourceApp = !!rulesSource && !!application && !isGrafanaApp;
-
- return (
-
- {isGrafanaApp && }
- {isDataSourceApp && (
-
-
-
-
-
- )}
-
-
- {namespace}
-
- {group}
-
-
- );
-};
-
const getStyles = (theme: GrafanaTheme2) => ({
alertListItemContainer: css({
position: 'relative',
diff --git a/public/app/features/alerting/unified/rule-list/components/RuleLocation.tsx b/public/app/features/alerting/unified/rule-list/components/RuleLocation.tsx
new file mode 100644
index 00000000000..b0d4b31de5d
--- /dev/null
+++ b/public/app/features/alerting/unified/rule-list/components/RuleLocation.tsx
@@ -0,0 +1,43 @@
+import { Icon, Stack, TextLink, Tooltip } from '@grafana/ui';
+import { RulesSourceIdentifier } from 'app/types/unified-alerting';
+import { RulesSourceApplication } from 'app/types/unified-alerting-dto';
+
+import { DataSourceIcon } from './Namespace';
+
+interface RuleLocationProps {
+ namespace: string;
+ group: string;
+ groupUrl?: string;
+ rulesSource?: RulesSourceIdentifier;
+ application?: RulesSourceApplication;
+}
+
+export function RuleLocation({ namespace, group, groupUrl, rulesSource, application }: RuleLocationProps) {
+ const isGrafanaApp = application === 'grafana';
+ const isDataSourceApp = !!rulesSource && !!application && !isGrafanaApp;
+
+ return (
+
+ {isGrafanaApp && }
+ {isDataSourceApp && (
+
+
+
+
+
+ )}
+
+
+ {namespace}
+
+ {groupUrl ? (
+
+ {group}
+
+ ) : (
+ group
+ )}
+
+
+ );
+}