diff --git a/public/app/features/alerting/unified/components/rule-viewer/RuleViewer.tsx b/public/app/features/alerting/unified/components/rule-viewer/RuleViewer.tsx index e5d5463ebf2..5a4b4da2178 100644 --- a/public/app/features/alerting/unified/components/rule-viewer/RuleViewer.tsx +++ b/public/app/features/alerting/unified/components/rule-viewer/RuleViewer.tsx @@ -93,6 +93,7 @@ const RuleViewer = () => { // we want to be able to show a modal if the rule has been provisioned explain the limitations // of duplicating provisioned alert rules const [duplicateRuleIdentifier, setDuplicateRuleIdentifier] = useState(); + const { returnTo } = useReturnTo('/alerting/list'); const { annotations, promRule, rulerRule } = rule; const hasError = isErrorHealth(promRule?.health); @@ -119,7 +120,7 @@ const RuleViewer = () => { health={promRule?.health} ruleType={promRule?.type} ruleOrigin={ruleOrigin} - returnToHref="/alerting/list" + returnToHref={returnTo} /> )} actions={} diff --git a/public/app/features/alerting/unified/rule-list/DataSourceGroupLoader.test.tsx b/public/app/features/alerting/unified/rule-list/DataSourceGroupLoader.test.tsx index 0064e7f953d..c1fe5eeec29 100644 --- a/public/app/features/alerting/unified/rule-list/DataSourceGroupLoader.test.tsx +++ b/public/app/features/alerting/unified/rule-list/DataSourceGroupLoader.test.tsx @@ -57,7 +57,7 @@ describe('DataSourceGroupLoader', () => { promGroup.rules.forEach((rule, index) => { const ruleLink = within(ruleListItems[index]).getByRole('link', { name: `prom-only-rule-${index + 1}` }); - expect(ruleLink).toHaveAttribute('href', createViewLinkV2(groupIdentifier, rule)); + expect(ruleLink).toHaveAttribute('href', expect.stringContaining(createViewLinkV2(groupIdentifier, rule))); }); }); @@ -103,7 +103,7 @@ describe('DataSourceGroupLoader', () => { expect(ruleListItems).toHaveLength(1); const ruleLink = within(ruleListItems[0]).getByRole('link', { name: 'mimir-rule-1' }); - expect(ruleLink).toHaveAttribute('href', getRuleLink(groupIdentifier, rulerRule)); + expect(ruleLink).toHaveAttribute('href', expect.stringContaining(getRuleLink(groupIdentifier, rulerRule))); }); it('should render Edit and More buttons for rules that are present in ruler and prometheus', async () => { diff --git a/public/app/features/alerting/unified/rule-list/DataSourceGroupLoader.tsx b/public/app/features/alerting/unified/rule-list/DataSourceGroupLoader.tsx index 5e8bce32165..a9430c488e1 100644 --- a/public/app/features/alerting/unified/rule-list/DataSourceGroupLoader.tsx +++ b/public/app/features/alerting/unified/rule-list/DataSourceGroupLoader.tsx @@ -141,6 +141,7 @@ export function DataSourceGroupLoader({ groupIdentifier, expectedRulesCount = 3 rule={rule} groupIdentifier={groupIdentifier} application={dsFeatures?.application} + showLocation={false} /> ))} @@ -194,6 +195,7 @@ export function RulerBasedGroupRules({ actions={ } + showLocation={false} /> ) : ( ); })} @@ -216,6 +219,7 @@ export function RulerBasedGroupRules({ rulesSource={groupIdentifier.rulesSource} application={application} operation={RuleOperation.Deleting} + showLocation={false} /> ))} diff --git a/public/app/features/alerting/unified/rule-list/DataSourceRuleListItem.tsx b/public/app/features/alerting/unified/rule-list/DataSourceRuleListItem.tsx index f93e63d3d92..3fc7eb8a808 100644 --- a/public/app/features/alerting/unified/rule-list/DataSourceRuleListItem.tsx +++ b/public/app/features/alerting/unified/rule-list/DataSourceRuleListItem.tsx @@ -3,6 +3,7 @@ import React from 'react'; import { DataSourceRuleGroupIdentifier, Rule, RuleIdentifier } from 'app/types/unified-alerting'; import { PromRuleType, RulerRuleDTO, RulesSourceApplication } from 'app/types/unified-alerting-dto'; +import { createReturnTo } from '../hooks/useReturnTo'; import { Annotation } from '../utils/constants'; import { fromRule, fromRulerRule, stringifyIdentifier } from '../utils/rule-id'; import { getRuleName, getRulePluginOrigin, rulerRuleType } from '../utils/rules'; @@ -21,6 +22,7 @@ export interface DataSourceRuleListItemProps { groupIdentifier: DataSourceRuleGroupIdentifier; application?: RulesSourceApplication; actions?: React.ReactNode; + showLocation?: boolean; } export function DataSourceRuleListItem({ @@ -29,13 +31,15 @@ export function DataSourceRuleListItem({ groupIdentifier, application, actions, + showLocation = true, }: DataSourceRuleListItemProps) { + const returnTo = createReturnTo(); const { rulesSource, namespace, groupName } = groupIdentifier; const ruleIdentifier = rulerRule ? fromRulerRule(rulesSource.name, namespace.name, groupName, rulerRule) : fromRule(rulesSource.name, namespace.name, groupName, rule); - const href = createViewLinkFromIdentifier(ruleIdentifier); + const href = createViewLinkFromIdentifier(ruleIdentifier, returnTo); const originMeta = getRulePluginOrigin(rule); // If ruler rule is available, we should use it as it contains fresh data @@ -54,6 +58,7 @@ export function DataSourceRuleListItem({ labels, actions, origin: originMeta, + showLocation, }; switch (rule.type) { diff --git a/public/app/features/alerting/unified/rule-list/GrafanaGroupLoader.test.tsx b/public/app/features/alerting/unified/rule-list/GrafanaGroupLoader.test.tsx index 783c0c23d91..621cd6ecd2e 100644 --- a/public/app/features/alerting/unified/rule-list/GrafanaGroupLoader.test.tsx +++ b/public/app/features/alerting/unified/rule-list/GrafanaGroupLoader.test.tsx @@ -49,7 +49,10 @@ describe('GrafanaGroupLoader', () => { expect(ruleStatus).toBeInTheDocument(); const ruleLink = ui.ruleLink(rule1.grafana_alert.title).get(ruleListItem); - expect(ruleLink).toHaveAttribute('href', `/alerting/grafana/${rule1.grafana_alert.uid}/view`); + expect(ruleLink).toHaveAttribute( + 'href', + expect.stringContaining(`/alerting/grafana/${rule1.grafana_alert.uid}/view`) + ); }); it('should render rule with url and creating state when only ruler rule exists', async () => { @@ -66,7 +69,10 @@ describe('GrafanaGroupLoader', () => { expect(creatingIcon).toBeInTheDocument(); const ruleLink = ui.ruleLink(rule1.grafana_alert.title).get(ruleListItem); - expect(ruleLink).toHaveAttribute('href', `/alerting/grafana/${rule1.grafana_alert.uid}/view`); + expect(ruleLink).toHaveAttribute( + 'href', + expect.stringContaining(`/alerting/grafana/${rule1.grafana_alert.uid}/view`) + ); }); it('should render delete rule operation list item when only prom rule exists', async () => { diff --git a/public/app/features/alerting/unified/rule-list/GrafanaGroupLoader.tsx b/public/app/features/alerting/unified/rule-list/GrafanaGroupLoader.tsx index 7bc5bf031b4..e8c024d4504 100644 --- a/public/app/features/alerting/unified/rule-list/GrafanaGroupLoader.tsx +++ b/public/app/features/alerting/unified/rule-list/GrafanaGroupLoader.tsx @@ -98,6 +98,7 @@ export function GrafanaGroupLoader({ groupIdentifier={groupIdentifier} namespaceName={namespaceName} operation={RuleOperation.Creating} + showLocation={false} /> ); } @@ -109,6 +110,8 @@ export function GrafanaGroupLoader({ rulerRule={rulerRule} groupIdentifier={groupIdentifier} namespaceName={namespaceName} + // we don't show the location again for rules, it's redundant because they are shown in a folder > group hierarchy + showLocation={false} /> ); })} @@ -121,6 +124,7 @@ export function GrafanaGroupLoader({ rulesSource={GrafanaRulesSource} application="grafana" operation={RuleOperation.Deleting} + showLocation={false} /> ))} diff --git a/public/app/features/alerting/unified/rule-list/GrafanaRuleLoader.tsx b/public/app/features/alerting/unified/rule-list/GrafanaRuleLoader.tsx index 13388bde92c..3ca5e6a7496 100644 --- a/public/app/features/alerting/unified/rule-list/GrafanaRuleLoader.tsx +++ b/public/app/features/alerting/unified/rule-list/GrafanaRuleLoader.tsx @@ -5,6 +5,7 @@ import { GrafanaPromRuleDTO, PromRuleType, RulerGrafanaRuleDTO } from 'app/types import { alertRuleApi } from '../api/alertRuleApi'; import { prometheusApi } from '../api/prometheusApi'; +import { createReturnTo } from '../hooks/useReturnTo'; import { GrafanaRulesSource } from '../utils/datasource'; import { totalFromStats } from '../utils/ruleStats'; import { rulerRuleType } from '../utils/rules'; @@ -91,6 +92,7 @@ interface GrafanaRuleListItemProps { groupIdentifier: GrafanaRuleGroupIdentifier; namespaceName: string; operation?: RuleOperation; + showLocation?: boolean; } export function GrafanaRuleListItem({ @@ -99,7 +101,10 @@ export function GrafanaRuleListItem({ groupIdentifier, namespaceName, operation, + showLocation = true, }: GrafanaRuleListItemProps) { + const returnTo = createReturnTo(); + const { grafana_alert: { uid, title, provenance, is_paused }, annotations = {}, @@ -111,7 +116,7 @@ export function GrafanaRuleListItem({ rulesSource: GrafanaRulesSource, group: groupIdentifier.groupName, namespace: namespaceName, - href: createRelativeUrl(`/alerting/grafana/${uid}/view`), + href: createRelativeUrl(`/alerting/grafana/${uid}/view`, { returnTo }), health: rule?.health, error: rule?.lastError, labels: labels, @@ -119,6 +124,7 @@ export function GrafanaRuleListItem({ isPaused: rule?.isPaused ?? is_paused, application: 'grafana' as const, actions: , + showLocation, }; if (rulerRuleType.grafana.alertingRule(rulerRule)) { 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 55b410cc46c..00a2df7ff8b 100644 --- a/public/app/features/alerting/unified/rule-list/components/AlertRuleListItem.tsx +++ b/public/app/features/alerting/unified/rule-list/components/AlertRuleListItem.tsx @@ -45,6 +45,8 @@ export interface AlertRuleListItemProps { actions?: ReactNode; origin?: RulePluginOrigin; operation?: RuleOperation; + // the grouped view doesn't need to show the location again – it's redundant + showLocation?: boolean; } export const AlertRuleListItem = (props: AlertRuleListItemProps) => { @@ -69,12 +71,13 @@ export const AlertRuleListItem = (props: AlertRuleListItemProps) => { origin, actions = null, operation, + showLocation = true, } = props; const listItemAriaId = useId(); const metadata: ReactNode[] = []; - if (namespace && group) { + if (namespace && group && showLocation) { metadata.push( @@ -167,9 +170,10 @@ export function RecordingRuleListItem({ isPaused, origin, actions, + showLocation = true, }: RecordingRuleListItemProps) { const metadata: ReactNode[] = []; - if (namespace && group) { + if (namespace && group && showLocation) { metadata.push( @@ -206,6 +210,7 @@ interface RuleOperationListItemProps { rulesSource?: RulesSourceIdentifier; application?: RulesSourceApplication; operation: RuleOperation; + showLocation?: boolean; } export function RuleOperationListItem({ @@ -215,11 +220,12 @@ export function RuleOperationListItem({ rulesSource, application, operation, + showLocation = true, }: RuleOperationListItemProps) { const listItemAriaId = useId(); const metadata: ReactNode[] = []; - if (namespace && group) { + if (namespace && group && showLocation) { metadata.push( @@ -256,7 +262,7 @@ function Summary({ content, error }: SummaryProps) { } if (content) { return ( - + {content} );