diff --git a/public/app/features/alerting/unified/api/prometheusApi.ts b/public/app/features/alerting/unified/api/prometheusApi.ts index d4a23770b01..a64f87296f2 100644 --- a/public/app/features/alerting/unified/api/prometheusApi.ts +++ b/public/app/features/alerting/unified/api/prometheusApi.ts @@ -95,6 +95,7 @@ export const prometheusApi = alertingApi.injectEndpoints({ limitAlerts, groupNextToken, title, + dashboardUid, }) => ({ url: `api/prometheus/grafana/api/v1/rules`, params: { @@ -109,6 +110,7 @@ export const prometheusApi = alertingApi.injectEndpoints({ group_limit: groupLimit?.toFixed(0), group_next_token: groupNextToken, 'search.rule_name': title, + dashboard_uid: dashboardUid, }, }), providesTags: (_result, _error, { folderUid, groupName, ruleName }) => { diff --git a/public/app/features/alerting/unified/rule-list/hooks/prometheusGroupsGenerator.ts b/public/app/features/alerting/unified/rule-list/hooks/prometheusGroupsGenerator.ts index cdd4bb2544e..e7a357c8498 100644 --- a/public/app/features/alerting/unified/rule-list/hooks/prometheusGroupsGenerator.ts +++ b/public/app/features/alerting/unified/rule-list/hooks/prometheusGroupsGenerator.ts @@ -48,6 +48,7 @@ interface GrafanaPromApiFilter { contactPoint?: string; title?: string; type?: 'alerting' | 'recording'; + dashboardUid?: string; } interface GrafanaFetchGroupsOptions extends FetchGroupsOptions { diff --git a/public/app/features/alerting/unified/rule-list/hooks/useFilteredRulesIterator.test.ts b/public/app/features/alerting/unified/rule-list/hooks/useFilteredRulesIterator.test.ts index 298ec747f56..9f597922867 100644 --- a/public/app/features/alerting/unified/rule-list/hooks/useFilteredRulesIterator.test.ts +++ b/public/app/features/alerting/unified/rule-list/hooks/useFilteredRulesIterator.test.ts @@ -22,17 +22,17 @@ describe('hasClientSideFilters', () => { config.featureToggles.alertingUIUseBackendFilters = true; }); - it('should return false for backend-supported filters (title and type)', () => { + it('should return false for backend-supported filters', () => { expect(hasClientSideFilters(getFilter({ freeFormWords: ['cpu'] }))).toBe(false); expect(hasClientSideFilters(getFilter({ ruleName: 'test' }))).toBe(false); expect(hasClientSideFilters(getFilter({ ruleType: PromRuleType.Alerting }))).toBe(false); + expect(hasClientSideFilters(getFilter({ dashboardUid: 'test-dashboard' }))).toBe(false); }); it('should return true for client-side only filters', () => { expect(hasClientSideFilters(getFilter({ namespace: 'test' }))).toBe(true); expect(hasClientSideFilters(getFilter({ dataSourceNames: ['prometheus'] }))).toBe(true); expect(hasClientSideFilters(getFilter({ labels: ['severity=critical'] }))).toBe(true); - expect(hasClientSideFilters(getFilter({ dashboardUid: 'test-dashboard' }))).toBe(true); expect(hasClientSideFilters(getFilter({ ruleSource: RuleSource.DataSource }))).toBe(true); }); @@ -46,10 +46,11 @@ describe('hasClientSideFilters', () => { config.featureToggles.alertingUIUseBackendFilters = false; }); - it('should return true for title and type filters (client-side fallback)', () => { + it('should return true for backend-supported filters when backend filtering is disabled', () => { expect(hasClientSideFilters(getFilter({ freeFormWords: ['cpu'] }))).toBe(true); expect(hasClientSideFilters(getFilter({ ruleName: 'test' }))).toBe(true); expect(hasClientSideFilters(getFilter({ ruleType: PromRuleType.Alerting }))).toBe(true); + expect(hasClientSideFilters(getFilter({ dashboardUid: 'test-dashboard' }))).toBe(true); }); it('should return true for client-side only filters', () => { @@ -70,11 +71,12 @@ describe('hasClientSideFilters', () => { config.featureToggles.alertingUIUseBackendFilters = undefined; }); - it('should return true for title and type filters (backward compatibility)', () => { + it('should default to client-side filtering for backward compatibility', () => { // Default behavior should be client-side filtering expect(hasClientSideFilters(getFilter({ freeFormWords: ['cpu'] }))).toBe(true); expect(hasClientSideFilters(getFilter({ ruleName: 'test' }))).toBe(true); expect(hasClientSideFilters(getFilter({ ruleType: PromRuleType.Alerting }))).toBe(true); + expect(hasClientSideFilters(getFilter({ dashboardUid: 'test-dashboard' }))).toBe(true); }); }); }); diff --git a/public/app/features/alerting/unified/rule-list/hooks/useFilteredRulesIterator.ts b/public/app/features/alerting/unified/rule-list/hooks/useFilteredRulesIterator.ts index 3e225ed9b7a..d2a577a1d23 100644 --- a/public/app/features/alerting/unified/rule-list/hooks/useFilteredRulesIterator.ts +++ b/public/app/features/alerting/unified/rule-list/hooks/useFilteredRulesIterator.ts @@ -84,6 +84,7 @@ export function useFilteredRulesIteratorProvider() { const titleSearch = useBackendFilters ? buildTitleSearch(filterState) : undefined; const ruleType = useBackendFilters ? filterState.ruleType : undefined; + const dashboardUid = useBackendFilters ? filterState.dashboardUid : undefined; const grafanaRulesGenerator: AsyncIterableX = from( grafanaGroupsGenerator(groupLimit, { @@ -92,6 +93,7 @@ export function useFilteredRulesIteratorProvider() { state: filterState.ruleState ? [filterState.ruleState] : [], title: titleSearch, type: ruleType, + dashboardUid, }) ).pipe( withAbort(abortController.signal), @@ -160,14 +162,16 @@ export function hasClientSideFilters(filterState: RulesFilter): boolean { const useBackendFilters = shouldUseBackendFilters(); return ( - // When backend filters are disabled, title search and type filter need client-side filtering + // When backend filters are disabled, title search, type filter, and dashboard filter need client-side filtering (!useBackendFilters && - (filterState.freeFormWords.length > 0 || Boolean(filterState.ruleName) || Boolean(filterState.ruleType))) || + (filterState.freeFormWords.length > 0 || + Boolean(filterState.ruleName) || + Boolean(filterState.ruleType) || + Boolean(filterState.dashboardUid))) || // Client-side only filters: Boolean(filterState.namespace) || filterState.dataSourceNames.length > 0 || filterState.labels.length > 0 || - Boolean(filterState.dashboardUid) || filterState.ruleSource === RuleSource.DataSource ); }