Alerting: Propagate dashboard uid filter to the backend (#113947)

* Alerting: Propagate dashboard uid filter to the backend

* Fix variable casing

---------

Co-authored-by: Konrad Lalik <konradlalik@gmail.com>
This commit is contained in:
Alexander Akhmetov
2025-11-14 16:25:14 +00:00
committed by GitHub
co-authored by Konrad Lalik
parent fe0486915e
commit e6eb40a679
4 changed files with 16 additions and 7 deletions
@@ -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 }) => {
@@ -48,6 +48,7 @@ interface GrafanaPromApiFilter {
contactPoint?: string;
title?: string;
type?: 'alerting' | 'recording';
dashboardUid?: string;
}
interface GrafanaFetchGroupsOptions extends FetchGroupsOptions {
@@ -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);
});
});
});
@@ -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<RuleWithOrigin> = 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
);
}