2 ChangeDetectionStrategy,
9 } from '@angular/core';
11 import { Mutex } from 'async-mutex';
12 import _ from 'lodash';
13 import moment from 'moment';
14 import { Subscription } from 'rxjs';
16 import { PrometheusService } from '~/app/shared/api/prometheus.service';
17 import { SucceededActionLabelsI18n } from '~/app/shared/constants/app.constants';
18 import { Icons } from '~/app/shared/enum/icons.enum';
19 import { NotificationType } from '~/app/shared/enum/notification-type.enum';
22 AlertmanagerSilenceMatcher
23 } from '~/app/shared/models/alertmanager-silence';
24 import { CdNotification } from '~/app/shared/models/cd-notification';
25 import { ExecutingTask } from '~/app/shared/models/executing-task';
26 import { FinishedTask } from '~/app/shared/models/finished-task';
27 import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
28 import { NotificationService } from '~/app/shared/services/notification.service';
29 import { PrometheusAlertService } from '~/app/shared/services/prometheus-alert.service';
30 import { PrometheusNotificationService } from '~/app/shared/services/prometheus-notification.service';
31 import { SummaryService } from '~/app/shared/services/summary.service';
32 import { TaskMessageService } from '~/app/shared/services/task-message.service';
35 selector: 'cd-notifications-sidebar',
36 templateUrl: './notifications-sidebar.component.html',
37 styleUrls: ['./notifications-sidebar.component.scss'],
38 changeDetection: ChangeDetectionStrategy.OnPush
40 export class NotificationsSidebarComponent implements OnInit, OnDestroy {
41 @HostBinding('class.active') isSidebarOpened = false;
43 notifications: CdNotification[];
44 private interval: number;
45 private timeout: number;
47 executingTasks: ExecutingTask[] = [];
49 private subs = new Subscription();
62 public notificationService: NotificationService,
63 private summaryService: SummaryService,
64 private taskMessageService: TaskMessageService,
65 private prometheusNotificationService: PrometheusNotificationService,
66 private succeededLabels: SucceededActionLabelsI18n,
67 private authStorageService: AuthStorageService,
68 private prometheusAlertService: PrometheusAlertService,
69 private prometheusService: PrometheusService,
70 private ngZone: NgZone,
71 private cdRef: ChangeDetectorRef
73 this.notifications = [];
77 window.clearInterval(this.interval);
78 window.clearTimeout(this.timeout);
79 this.subs.unsubscribe();
83 this.last_task = window.localStorage.getItem('last_task');
85 const permissions = this.authStorageService.getPermissions();
86 if (permissions.prometheus.read && permissions.configOpt.read) {
87 this.triggerPrometheusAlerts();
88 this.ngZone.runOutsideAngular(() => {
89 this.interval = window.setInterval(() => {
90 this.ngZone.run(() => {
91 this.triggerPrometheusAlerts();
98 this.notificationService.data$.subscribe((notifications: CdNotification[]) => {
99 this.notifications = _.orderBy(notifications, ['timestamp'], ['desc']);
100 this.cdRef.detectChanges();
105 this.notificationService.sidebarSubject.subscribe((forceClose) => {
107 this.isSidebarOpened = false;
109 this.isSidebarOpened = !this.isSidebarOpened;
112 window.clearTimeout(this.timeout);
113 this.timeout = window.setTimeout(() => {
114 this.cdRef.detectChanges();
120 this.summaryService.subscribe((summary) => {
121 this._handleTasks(summary.executing_tasks);
123 this.mutex.acquire().then((release) => {
125 summary.finished_tasks,
126 (task: FinishedTask) => !this.last_task || moment(task.end_time).isAfter(this.last_task)
127 ).forEach((task) => {
128 const config = this.notificationService.finishedTaskToNotification(task, task.success);
129 const notification = new CdNotification(config);
130 notification.timestamp = task.end_time;
131 notification.duration = task.duration;
133 if (!this.last_task || moment(task.end_time).isAfter(this.last_task)) {
134 this.last_task = task.end_time;
135 window.localStorage.setItem('last_task', this.last_task);
138 this.notificationService.save(notification);
141 this.cdRef.detectChanges();
149 _handleTasks(executingTasks: ExecutingTask[]) {
150 for (const executingTask of executingTasks) {
151 executingTask.description = this.taskMessageService.getRunningTitle(executingTask);
153 this.executingTasks = executingTasks;
156 private triggerPrometheusAlerts() {
157 this.prometheusAlertService.refresh(true);
158 this.prometheusNotificationService.refresh();
162 this.notificationService.removeAll();
165 remove(index: number) {
166 this.notificationService.remove(index);
170 this.isSidebarOpened = false;
173 trackByFn(index: number) {
177 silence(data: CdNotification) {
178 const datetimeFormat = 'YYYY-MM-DD HH:mm';
179 const resource = $localize`silence`;
180 const matcher: AlertmanagerSilenceMatcher = {
182 value: data['title'].split(' ')[0],
185 const silencePayload: AlertmanagerSilence = {
187 startsAt: moment(moment().format(datetimeFormat)).toISOString(),
188 endsAt: moment(moment().add(2, 'hours').format(datetimeFormat)).toISOString(),
189 createdBy: this.authStorageService.getUsername(),
190 comment: 'Silence created from the alert notification'
194 data.alertSilenced = true;
195 msg = msg.concat(` ${matcher.name} - ${matcher.value},`);
196 const title = `${this.succeededLabels.CREATED} ${resource} for ${msg.slice(0, -1)}`;
197 this.prometheusService.setSilence(silencePayload).subscribe((resp) => {
199 data.silenceId = resp.body['silenceId'];
201 this.notificationService.show(
202 NotificationType.success,
211 expire(data: CdNotification) {
212 data.alertSilenced = false;
213 this.prometheusService.expireSilence(data.silenceId).subscribe(
215 this.notificationService.show(
216 NotificationType.success,
217 `${this.succeededLabels.EXPIRED} ${data.silenceId}`,
224 resp['application'] = 'Prometheus';