Merge pull request #65459 from rhcs-dashboard/72944-hide-suppresed-alerts-on-dashboard

mgr/dashboard : Hide suppressed  alert on landing page

Reviewed-by: Afreen Misbah <afreen@ibm.com>
Reviewed-by: Nizamudeen A <nia@redhat.com>
This commit is contained in:
afreen23 2025-09-30 15:13:13 +05:30 committed by GitHub
commit 7d5298b71a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 56 additions and 19 deletions

View File

@ -11,6 +11,7 @@
<cd-table
[data]="prometheusAlertService.alerts"
[columns]="columns"
[extraFilterableColumns]="filters"
identifier="fingerprint"
[forceIdentifier]="true"
[customCss]="customCss"

View File

@ -8,6 +8,7 @@ import { CdTableAction } from '~/app/shared/models/cd-table-action';
import { CdTableColumn } from '~/app/shared/models/cd-table-column';
import { CdTableSelection } from '~/app/shared/models/cd-table-selection';
import { Permission } from '~/app/shared/models/permissions';
import { AlertState } from '~/app/shared/models/prometheus-alerts';
import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
import { PrometheusAlertService } from '~/app/shared/services/prometheus-alert.service';
import { URLBuilderService } from '~/app/shared/services/url-builder.service';
@ -32,6 +33,21 @@ export class ActiveAlertListComponent extends PrometheusListHelper implements On
expandedInnerRow: any;
multilineTextKeys = ['description', 'impact', 'fix'];
filters: CdTableColumn[] = [
{
name: $localize`State`,
prop: 'status.state',
filterOptions: [$localize`All`, $localize`Active`, $localize`Suppressed`],
filterInitValue: $localize`Active`,
filterPredicate: (row, value) => {
if (value === 'Active') return row.status?.state === AlertState.ACTIVE;
else if (value === 'Suppressed') return row.status?.state === AlertState.SUPPRESSED;
if (value === 'All') return true;
return false;
}
}
];
constructor(
// NotificationsComponent will refresh all alerts every 5s (No need to do it here as well)
private authStorageService: AuthStorageService,

View File

@ -102,7 +102,7 @@ describe('SilenceFormComponent', () => {
prometheus = new PrometheusHelper();
prometheusService = TestBed.inject(PrometheusService);
spyOn(prometheusService, 'getGroupedAlerts').and.callFake(() => {
spyOn(prometheusService, 'getAlerts').and.callFake(() => {
const name = _.split(router.url, '/').pop();
return of([prometheus.createAlert(name)]);
});
@ -285,7 +285,7 @@ describe('SilenceFormComponent', () => {
params = { id: 'alert0' };
expectMode('alertAdd', false, false, 'Create');
expect(prometheusService.getSilences).not.toHaveBeenCalled();
expect(prometheusService.getGroupedAlerts).toHaveBeenCalled();
expect(prometheusService.getAlerts).toHaveBeenCalled();
expect(component.matchers).toEqual([createMatcher('alertname', 'alert0', false)]);
expect(component.matcherMatch).toEqual({
cssClass: 'has-success',

View File

@ -19,7 +19,7 @@ import {
AlertmanagerSilenceMatcherMatch
} from '~/app/shared/models/alertmanager-silence';
import { Permission } from '~/app/shared/models/permissions';
import { GroupAlertmanagerAlert, PrometheusRule } from '~/app/shared/models/prometheus-alerts';
import { AlertmanagerAlert, PrometheusRule } from '~/app/shared/models/prometheus-alerts';
import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
import { ModalService } from '~/app/shared/services/modal.service';
import { NotificationService } from '~/app/shared/services/notification.service';
@ -225,7 +225,7 @@ export class SilenceFormComponent {
}
});
} else {
this.prometheusService.getGroupedAlerts().subscribe((alerts) => {
this.prometheusService.getAlerts().subscribe((alerts) => {
const alert = _.find(alerts, ['fingerprint', params.id]);
if (!_.isUndefined(alert)) {
this.fillFormByAlert(alert);
@ -258,7 +258,7 @@ export class SilenceFormComponent {
this.form.updateValueAndValidity();
}
private fillFormByAlert(alert: GroupAlertmanagerAlert) {
private fillFormByAlert(alert: AlertmanagerAlert) {
const labels = alert.labels;
this.setMatcher({
name: 'alertname',

View File

@ -288,8 +288,8 @@
<ng-container *ngFor="let alert of prometheusAlertService.alerts; let i = index; trackBy: trackByFn">
<div [ngClass]="['border-'+alertClass[alert.labels.severity]]"
*ngIf="alert.status.state === 'active' &&
alert.labels.severity === alertType ||
!alertType">
(alert.labels.severity === alertType ||
!alertType)">
<div class="card tc_alerts border-0 pt-3">
<div class="row no-gutters ps-2">
<div class="col-sm-1 text-center">
@ -309,6 +309,7 @@
[title]="alert.startsAt | cdDate"
i18n>Active since: {{ alert.startsAt | relativeDate }}</small>
<small class="alert_count"
*ngIf="alert.alert_count > 1"
[title]="alert.alert_count"
i18n>Total occurrences: {{ alert.alert_count }}</small>
</p>

View File

@ -1,3 +1,5 @@
type AlertState = 'active' | 'suppressed' | 'resolved' | 'unprocessed';
export class PrometheusAlertLabels {
alertname: string;
instance: string;
@ -48,7 +50,7 @@ export class PrometheusRule {
export class AlertmanagerAlert extends CommonAlertmanagerAlert {
status: {
state: 'unprocessed' | 'active' | 'suppressed';
state: AlertState;
silencedBy: null | string[];
inhibitedBy: null | string[];
};
@ -84,10 +86,17 @@ export class AlertmanagerNotification {
}
export class PrometheusCustomAlert {
status: 'resolved' | 'unprocessed' | 'active' | 'suppressed';
status: AlertState;
name: string;
url: string;
description: string;
fingerprint?: string | boolean;
severity?: string;
}
export const AlertState = {
ACTIVE: 'active' as AlertState,
SUPPRESSED: 'suppressed' as AlertState,
RESOLVED: 'resolved' as AlertState,
UNPROCCESSED: 'unprocessed' as AlertState
};

View File

@ -7,7 +7,8 @@ import {
AlertmanagerAlert,
PrometheusCustomAlert,
PrometheusRule,
GroupAlertmanagerAlert
GroupAlertmanagerAlert,
AlertState
} from '../models/prometheus-alerts';
import { PrometheusAlertFormatter } from './prometheus-alert-formatter';
import { BehaviorSubject } from 'rxjs';
@ -64,10 +65,15 @@ export class PrometheusAlertService {
private handleAlerts(alertGroups: GroupAlertmanagerAlert[]) {
const alerts: AlertmanagerAlert[] = alertGroups
.map((g) => {
if (!g.alerts.length) return null;
if (g.alerts.length === 1) return { ...g.alerts[0], alert_count: 1 };
return { ...g.alerts[0], alert_count: g.alerts.length, subalerts: g.alerts };
.map((group) => {
if (!group.alerts.length) return null;
if (group.alerts.length === 1) return { ...group.alerts[0], alert_count: 1 };
const hasActive = group.alerts.some(
(alert: AlertmanagerAlert) => alert.status.state === AlertState.ACTIVE
);
const parent = { ...group.alerts[0] };
if (hasActive) parent.status.state = AlertState.ACTIVE;
return { ...parent, alert_count: group.alerts.length, subalerts: group.alerts };
})
.filter(Boolean) as AlertmanagerAlert[];
@ -78,19 +84,23 @@ export class PrometheusAlertService {
}
this.activeAlerts = _.reduce<AlertmanagerAlert, number>(
alerts,
(result, alert) => (alert.status.state === 'active' ? ++result : result),
(result, alert) => (alert.status.state === AlertState.ACTIVE ? ++result : result),
0
);
this.activeCriticalAlerts = _.reduce<AlertmanagerAlert, number>(
alerts,
(result, alert) =>
alert.status.state === 'active' && alert.labels.severity === 'critical' ? ++result : result,
alert.status.state === AlertState.ACTIVE && alert.labels.severity === 'critical'
? ++result
: result,
0
);
this.activeWarningAlerts = _.reduce<AlertmanagerAlert, number>(
alerts,
(result, alert) =>
alert.status.state === 'active' && alert.labels.severity === 'warning' ? ++result : result,
alert.status.state === AlertState.ACTIVE && alert.labels.severity === 'warning'
? ++result
: result,
0
);
this.alerts = alerts
@ -105,7 +115,7 @@ export class PrometheusAlertService {
this.alertFormatter.convertToCustomAlerts(oldAlerts)
);
const suppressedFiltered = _.filter(changedAlerts, (alert) => {
return alert.status !== 'suppressed';
return alert.status !== AlertState.SUPPRESSED;
});
const notifications = suppressedFiltered.map((alert) =>
this.alertFormatter.convertAlertToNotification(alert)
@ -121,7 +131,7 @@ export class PrometheusAlertService {
private getVanishedAlerts(alerts: PrometheusCustomAlert[], oldAlerts: PrometheusCustomAlert[]) {
return _.differenceWith(oldAlerts, alerts, (a, b) => a.fingerprint === b.fingerprint).map(
(alert) => {
alert.status = 'resolved';
alert.status = AlertState.RESOLVED;
return alert;
}
);