Alerting: Pass exact matchers to the backend in the state history UI (#109292)

This commit is contained in:
Alexander Akhmetov
2025-08-08 16:03:27 +02:00
committed by GitHub
parent f836ea2ada
commit 73f24d3116
4 changed files with 69 additions and 7 deletions
@@ -4,11 +4,29 @@ import { alertingApi } from './alertingApi';
export const stateHistoryApi = alertingApi.injectEndpoints({
endpoints: (build) => ({
getRuleHistory: build.query<DataFrameJSON, { ruleUid?: string; from?: number; to?: number; limit?: number }>({
query: ({ ruleUid, from, to, limit = 100 }) => ({
url: '/api/v1/rules/history',
params: { ruleUID: ruleUid, from, to, limit },
}),
getRuleHistory: build.query<
DataFrameJSON,
{ ruleUid?: string; from?: number; to?: number; limit?: number; labels?: Record<string, string> }
>({
query: ({ ruleUid, from, to, limit = 100, labels }) => {
const params: Record<string, string | number | undefined> = {
ruleUID: ruleUid,
from,
to,
limit,
};
if (labels) {
Object.entries(labels).forEach(([key, value]) => {
params[`labels_${key}`] = value;
});
}
return {
url: '/api/v1/rules/history',
params,
};
},
}),
}),
});
@@ -29,6 +29,7 @@ import { AITriageButtonComponent } from '../../../enterprise-components/AI/AIGen
import { usePagination } from '../../../hooks/usePagination';
import { combineMatcherStrings } from '../../../utils/alertmanager';
import { GRAFANA_RULES_SOURCE_NAME } from '../../../utils/datasource';
import { parsePromQLStyleMatcherLooseSafe } from '../../../utils/matchers';
import { createRelativeUrl } from '../../../utils/url';
import { AlertLabels } from '../../AlertLabels';
import { CollapseToggle } from '../../CollapseToggle';
@@ -65,6 +66,17 @@ export const HistoryEventsList = ({
const from = timeRange?.from.unix();
const to = timeRange?.to.unix();
const labelMatchers = parsePromQLStyleMatcherLooseSafe(valueInLabelFilter.toString());
// Prepare labels for filtering on the backend side.
// Backend supports only exact matchers.
const labelFilters: Record<string, string> = {};
labelMatchers.forEach((matcher) => {
if (!matcher.isRegex && matcher.isEqual) {
labelFilters[matcher.name] = matcher.value;
}
});
const {
data: stateHistory,
isLoading,
@@ -74,6 +86,7 @@ export const HistoryEventsList = ({
from: from,
to: to,
limit: LIMIT_EVENTS,
labels: Object.keys(labelFilters).length > 0 ? labelFilters : undefined,
});
const { historyRecords: historyRecordsNotSorted } = useRuleHistoryRecords(stateHistory, {
@@ -102,7 +115,7 @@ export const HistoryEventsList = ({
>
{t(
'alerting.central-alert-history.too-many-events.text',
'The selected time period has too many events to display. Diplaying the latest 5000 events. Try using a shorter time period.'
'The selected time period has too many events to display. Displaying the latest 5000 events. Try using a shorter time period.'
)}
</Alert>
)}
@@ -4,6 +4,7 @@ import { byLabelText, byTestId } from 'testing-library-selector';
import { getDefaultTimeRange } from '@grafana/data';
import { setupMswServer } from '../../../mockApi';
import { captureRequests } from '../../../mocks/server/events';
import { StateFilterValues } from './CentralAlertHistoryScene';
import { HistoryEventsList } from './EventListSceneObject';
@@ -148,4 +149,34 @@ describe('HistoryEventsList', () => {
});
expect(ui.rowHeader.query()).not.toBeInTheDocument();
});
describe('backend filtering', () => {
it('should send only exact match filters to the backend', async () => {
const capture = captureRequests((req) => req.url.includes('/api/v1/rules/history'));
render(
<HistoryEventsList
valueInLabelFilter={'alertname=alert1, grafana_folder=~".*folder.*", severity!=high, team="alerting"'}
valueInStateToFilter={StateFilterValues.all}
valueInStateFromFilter={StateFilterValues.all}
addFilter={jest.fn()}
timeRange={getDefaultTimeRange()}
/>
);
await waitFor(() => {
expect(ui.loadingBar.query()).not.toBeInTheDocument();
});
const requests = await capture;
expect(requests).toHaveLength(1);
const url = new URL(requests[0].url);
expect(url.searchParams.get('labels_alertname')).toBe('alert1');
expect(url.searchParams.get('labels_team')).toBe('alerting');
expect(url.searchParams.get('labels_grafana_folder')).toBeNull();
expect(url.searchParams.get('labels_severity')).toBeNull();
});
});
});
+1 -1
View File
@@ -788,7 +788,7 @@
},
"filterBy": "Filter by:",
"too-many-events": {
"text": "The selected time period has too many events to display. Diplaying the latest 5000 events. Try using a shorter time period.",
"text": "The selected time period has too many events to display. Displaying the latest 5000 events. Try using a shorter time period.",
"title": "Unable to display all events"
}
},