]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: stay on active tab (accessible via URL) 34889/head
authorVolker Theile <vtheile@suse.com>
Fri, 26 Jun 2020 14:18:53 +0000 (16:18 +0200)
committerVolker Theile <vtheile@suse.com>
Thu, 2 Jul 2020 09:11:57 +0000 (11:11 +0200)
This PR refactors the /monitoring page by introducing a new component which is responsible for rendering the tabs. All tabs have a dedicated route/URL now, no fragments are used anymore, thus they will act like the iSCSI and RBD pages.

Fixes: https://tracker.ceph.com/issues/45375
Signed-off-by: Volker Theile <vtheile@suse.com>
21 files changed:
src/pybind/mgr/dashboard/frontend/src/app/app-routing.module.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/cluster.module.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/active-alert-list/active-alert-list.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/active-alert-list/active-alert-list.component.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/monitoring-list/monitoring-list.component.html [deleted file]
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/monitoring-list/monitoring-list.component.scss [deleted file]
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/monitoring-list/monitoring-list.component.spec.ts [deleted file]
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/monitoring-list/monitoring-list.component.ts [deleted file]
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/prometheus-list-helper.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/prometheus-tabs/prometheus-tabs.component.html [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/prometheus-tabs/prometheus-tabs.component.scss [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/prometheus-tabs/prometheus-tabs.component.spec.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/prometheus-tabs/prometheus-tabs.component.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/rules-list/rules-list.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/rules-list/rules-list.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/rules-list/rules-list.component.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/silence-form/silence-form.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/silence-form/silence-form.component.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/silence-list/silence-list.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/silence-list/silence-list.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/silence-list/silence-list.component.ts

index e4ef9753c7eefa3fe3e04e9d0eb783c9fdafee96..5e686424f2b5428d32baa6b5adcbc5ba37f687e5 100644 (file)
@@ -16,8 +16,10 @@ import { MgrModuleListComponent } from './ceph/cluster/mgr-modules/mgr-module-li
 import { MonitorComponent } from './ceph/cluster/monitor/monitor.component';
 import { OsdFormComponent } from './ceph/cluster/osd/osd-form/osd-form.component';
 import { OsdListComponent } from './ceph/cluster/osd/osd-list/osd-list.component';
-import { MonitoringListComponent } from './ceph/cluster/prometheus/monitoring-list/monitoring-list.component';
+import { ActiveAlertListComponent } from './ceph/cluster/prometheus/active-alert-list/active-alert-list.component';
+import { RulesListComponent } from './ceph/cluster/prometheus/rules-list/rules-list.component';
 import { SilenceFormComponent } from './ceph/cluster/prometheus/silence-form/silence-form.component';
+import { SilenceListComponent } from './ceph/cluster/prometheus/silence-list/silence-list.component';
 import { ServicesComponent } from './ceph/cluster/services/services.component';
 import { TelemetryComponent } from './ceph/cluster/telemetry/telemetry.component';
 import { DashboardComponent } from './ceph/dashboard/dashboard/dashboard.component';
@@ -155,29 +157,46 @@ const routes: Routes = [
         path: 'monitoring',
         data: { breadcrumbs: 'Cluster/Monitoring' },
         children: [
+          { path: '', redirectTo: 'active-alerts', pathMatch: 'full' },
           {
-            path: '',
-            component: MonitoringListComponent
-          },
-          {
-            path: 'silence/' + URLVerbs.CREATE,
-            component: SilenceFormComponent,
-            data: { breadcrumbs: `${ActionLabels.CREATE} Silence` }
+            path: 'active-alerts',
+            data: { breadcrumbs: 'Active Alerts' },
+            component: ActiveAlertListComponent
           },
           {
-            path: `silence/${URLVerbs.CREATE}/:id`,
-            component: SilenceFormComponent,
-            data: { breadcrumbs: ActionLabels.CREATE }
-          },
-          {
-            path: `silence/${URLVerbs.EDIT}/:id`,
-            component: SilenceFormComponent,
-            data: { breadcrumbs: ActionLabels.EDIT }
+            path: 'alerts',
+            data: { breadcrumbs: 'Alerts' },
+            component: RulesListComponent
           },
           {
-            path: `silence/${URLVerbs.RECREATE}/:id`,
-            component: SilenceFormComponent,
-            data: { breadcrumbs: ActionLabels.RECREATE }
+            path: 'silences',
+            data: { breadcrumbs: 'Silences' },
+            children: [
+              {
+                path: '',
+                component: SilenceListComponent
+              },
+              {
+                path: URLVerbs.CREATE,
+                component: SilenceFormComponent,
+                data: { breadcrumbs: `${ActionLabels.CREATE} Silence` }
+              },
+              {
+                path: `${URLVerbs.CREATE}/:id`,
+                component: SilenceFormComponent,
+                data: { breadcrumbs: ActionLabels.CREATE }
+              },
+              {
+                path: `${URLVerbs.EDIT}/:id`,
+                component: SilenceFormComponent,
+                data: { breadcrumbs: ActionLabels.EDIT }
+              },
+              {
+                path: `${URLVerbs.RECREATE}/:id`,
+                component: SilenceFormComponent,
+                data: { breadcrumbs: ActionLabels.RECREATE }
+              }
+            ]
           }
         ]
       },
index 73d5e1c3c83e4ab051670b71fdbff762ade71eb5..5b805d71ec305980b23dad8aa9df06f334f2396f 100644 (file)
@@ -42,7 +42,7 @@ import { OsdRecvSpeedModalComponent } from './osd/osd-recv-speed-modal/osd-recv-
 import { OsdReweightModalComponent } from './osd/osd-reweight-modal/osd-reweight-modal.component';
 import { OsdScrubModalComponent } from './osd/osd-scrub-modal/osd-scrub-modal.component';
 import { ActiveAlertListComponent } from './prometheus/active-alert-list/active-alert-list.component';
-import { MonitoringListComponent } from './prometheus/monitoring-list/monitoring-list.component';
+import { PrometheusTabsComponent } from './prometheus/prometheus-tabs/prometheus-tabs.component';
 import { RulesListComponent } from './prometheus/rules-list/rules-list.component';
 import { SilenceFormComponent } from './prometheus/silence-form/silence-form.component';
 import { SilenceListComponent } from './prometheus/silence-list/silence-list.component';
@@ -88,7 +88,6 @@ import { TelemetryComponent } from './telemetry/telemetry.component';
     LogsComponent,
     OsdRecvSpeedModalComponent,
     OsdPgScrubModalComponent,
-    ActiveAlertListComponent,
     OsdRecvSpeedModalComponent,
     SilenceFormComponent,
     SilenceListComponent,
@@ -103,11 +102,11 @@ import { TelemetryComponent } from './telemetry/telemetry.component';
     OsdCreationPreviewModalComponent,
     RulesListComponent,
     ActiveAlertListComponent,
-    MonitoringListComponent,
     HostFormComponent,
     ServiceDetailsComponent,
     ServiceDaemonListComponent,
-    TelemetryComponent
+    TelemetryComponent,
+    PrometheusTabsComponent
   ]
 })
 export class ClusterModule {}
index e9ad6760a897731aacdf8470466aa0e1e127bc0f..8f9605b5bb2857f89894331ff5b215a3decf8555 100644 (file)
@@ -1,4 +1,15 @@
-<cd-table [data]="prometheusAlertService.alerts"
+<cd-prometheus-tabs></cd-prometheus-tabs>
+
+<cd-alert-panel *ngIf="!isAlertmanagerConfigured"
+                type="info"
+                i18n>To see all active Prometheus alerts, please
+  provide the URL to the API of Prometheus' Alertmanager as described
+  in the <a href="{{docsUrl}}"
+            target="_blank">documentation</a>.
+</cd-alert-panel>
+
+<cd-table *ngIf="isAlertmanagerConfigured"
+          [data]="prometheusAlertService.alerts"
           [columns]="columns"
           identifier="fingerprint"
           [forceIdentifier]="true"
index 7f08731d1eb1f1308af7ebf5cf7c58e55bcf0e7f..bcd1f006aa0b61358c7a0914ce07e79cafe0241d 100644 (file)
@@ -1,8 +1,8 @@
-import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
+import { Component, Inject, OnInit, TemplateRef, ViewChild } from '@angular/core';
 
 import { I18n } from '@ngx-translate/i18n-polyfill';
 
-import { ListWithDetails } from '../../../../shared/classes/list-with-details.class';
+import { PrometheusService } from '../../../../shared/api/prometheus.service';
 import { CellTemplate } from '../../../../shared/enum/cell-template.enum';
 import { Icons } from '../../../../shared/enum/icons.enum';
 import { CdTableAction } from '../../../../shared/models/cd-table-action';
@@ -10,11 +10,14 @@ import { CdTableColumn } from '../../../../shared/models/cd-table-column';
 import { CdTableSelection } from '../../../../shared/models/cd-table-selection';
 import { Permission } from '../../../../shared/models/permissions';
 import { CdDatePipe } from '../../../../shared/pipes/cd-date.pipe';
+import { CephReleaseNamePipe } from '../../../../shared/pipes/ceph-release-name.pipe';
 import { AuthStorageService } from '../../../../shared/services/auth-storage.service';
 import { PrometheusAlertService } from '../../../../shared/services/prometheus-alert.service';
+import { SummaryService } from '../../../../shared/services/summary.service';
 import { URLBuilderService } from '../../../../shared/services/url-builder.service';
+import { PrometheusListHelper } from '../prometheus-list-helper';
 
-const BASE_URL = 'silence'; // as only silence actions can be used
+const BASE_URL = 'silences'; // as only silence actions can be used
 
 @Component({
   selector: 'cd-active-alert-list',
@@ -22,7 +25,7 @@ const BASE_URL = 'silence'; // as only silence actions can be used
   templateUrl: './active-alert-list.component.html',
   styleUrls: ['./active-alert-list.component.scss']
 })
-export class ActiveAlertListComponent extends ListWithDetails implements OnInit {
+export class ActiveAlertListComponent extends PrometheusListHelper implements OnInit {
   @ViewChild('externalLinkTpl', { static: true })
   externalLinkTpl: TemplateRef<any>;
   columns: CdTableColumn[];
@@ -42,9 +45,12 @@ export class ActiveAlertListComponent extends ListWithDetails implements OnInit
     public prometheusAlertService: PrometheusAlertService,
     private urlBuilder: URLBuilderService,
     private i18n: I18n,
-    private cdDatePipe: CdDatePipe
+    private cdDatePipe: CdDatePipe,
+    @Inject(PrometheusService) prometheusService: PrometheusService,
+    @Inject(SummaryService) summaryService: SummaryService,
+    @Inject(CephReleaseNamePipe) cephReleaseNamePipe: CephReleaseNamePipe
   ) {
-    super();
+    super(prometheusService, summaryService, cephReleaseNamePipe);
     this.permission = this.authStorageService.getPermissions().prometheus;
     this.tableActions = [
       {
@@ -61,6 +67,7 @@ export class ActiveAlertListComponent extends ListWithDetails implements OnInit
   }
 
   ngOnInit() {
+    super.ngOnInit();
     this.columns = [
       {
         name: this.i18n('Name'),
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/monitoring-list/monitoring-list.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/monitoring-list/monitoring-list.component.html
deleted file mode 100644 (file)
index d63d70d..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-<ul ngbNav
-    #nav="ngbNav"
-    [activeId]="route.snapshot.fragment"
-    (navChange)="setFragment($event.nextId)"
-    class="nav-tabs">
-  <li ngbNavItem="active-alerts">
-    <a ngbNavLink
-       i18n>Active Alerts</a>
-    <ng-template ngbNavContent>
-      <cd-active-alert-list *ngIf="isAlertmanagerConfigured"></cd-active-alert-list>
-      <cd-alert-panel type="info"
-                      i18n
-                      *ngIf="!isAlertmanagerConfigured">To see all active Prometheus alerts, please
-        provide the URL to the API of Prometheus' Alertmanager as described in the
-      <a href="{{docsUrl}}"
-         target="_blank">documentation</a>.</cd-alert-panel>
-    </ng-template>
-  </li>
-  <li ngbNavItem="all-alerts">
-    <a ngbNavLink
-       i18n>All Alerts</a>
-    <ng-template ngbNavContent>
-      <cd-rules-list *ngIf="isPrometheusConfigured"
-                     [data]="prometheusAlertService.rules"></cd-rules-list>
-      <cd-alert-panel type="info"
-                      *ngIf="!isPrometheusConfigured">To see all configured Prometheus alerts,
-        please provide the URL to
-        the API of Prometheus as described in the
-      <a href="{{docsUrl}}"
-         target="_blank">documentation</a>.</cd-alert-panel>
-    </ng-template>
-  </li>
-  <li ngbNavItem="silences">
-    <a ngbNavLink
-       i18n>Silences</a>
-    <ng-template ngbNavContent>
-      <cd-silences-list *ngIf="isAlertmanagerConfigured"></cd-silences-list>
-      <cd-alert-panel *ngIf="!isAlertmanagerConfigured"
-                      type="info"
-                      i18n>To enable Silences, please provide the URL to the API of the Prometheus' Alertmanager as
-        described in the
-      <a href="{{docsUrl}}"
-         target="_blank">documentation</a>.</cd-alert-panel>
-    </ng-template>
-  </li>
-</ul>
-
-<div [ngbNavOutlet]="nav"></div>
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/monitoring-list/monitoring-list.component.scss b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/monitoring-list/monitoring-list.component.scss
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/monitoring-list/monitoring-list.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/monitoring-list/monitoring-list.component.spec.ts
deleted file mode 100644 (file)
index 6e0c85f..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-import { HttpClientTestingModule } from '@angular/common/http/testing';
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { ToastrModule } from 'ngx-toastr';
-
-import { i18nProviders } from '../../../../../testing/unit-test-helper';
-import { AuthModule } from '../../../../core/auth/auth.module';
-import { CoreModule } from '../../../../core/core.module';
-import { CephfsModule } from '../../../cephfs/cephfs.module';
-import { DashboardModule } from '../../../dashboard/dashboard.module';
-import { NfsModule } from '../../../nfs/nfs.module';
-import { ClusterModule } from '../../cluster.module';
-import { MonitoringListComponent } from './monitoring-list.component';
-
-describe('MonitoringListComponent', () => {
-  let component: MonitoringListComponent;
-  let fixture: ComponentFixture<MonitoringListComponent>;
-
-  beforeEach(async(() => {
-    TestBed.configureTestingModule({
-      imports: [
-        ClusterModule,
-        DashboardModule,
-        CephfsModule,
-        AuthModule,
-        NfsModule,
-        CoreModule,
-        ToastrModule.forRoot(),
-        HttpClientTestingModule
-      ],
-      declarations: [],
-      providers: [i18nProviders]
-    }).compileComponents();
-  }));
-
-  beforeEach(() => {
-    fixture = TestBed.createComponent(MonitoringListComponent);
-    component = fixture.componentInstance;
-    fixture.detectChanges();
-  });
-
-  it('should create', () => {
-    expect(component).toBeTruthy();
-  });
-});
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/monitoring-list/monitoring-list.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/monitoring-list/monitoring-list.component.ts
deleted file mode 100644 (file)
index 03325f5..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-import { Component, OnInit } from '@angular/core';
-import { ActivatedRoute, Router } from '@angular/router';
-
-import { PrometheusService } from '../../../../shared/api/prometheus.service';
-import { CephReleaseNamePipe } from '../../../../shared/pipes/ceph-release-name.pipe';
-import { PrometheusAlertService } from '../../../../shared/services/prometheus-alert.service';
-import { SummaryService } from '../../../../shared/services/summary.service';
-
-@Component({
-  selector: 'cd-monitoring-list',
-  templateUrl: './monitoring-list.component.html',
-  styleUrls: ['./monitoring-list.component.scss']
-})
-export class MonitoringListComponent implements OnInit {
-  constructor(
-    public prometheusAlertService: PrometheusAlertService,
-    private prometheusService: PrometheusService,
-    public route: ActivatedRoute,
-    private router: Router,
-    private summaryService: SummaryService,
-    private cephReleaseNamePipe: CephReleaseNamePipe
-  ) {}
-  isPrometheusConfigured = false;
-  isAlertmanagerConfigured = false;
-
-  docsUrl = '';
-
-  ngOnInit() {
-    this.prometheusService.ifAlertmanagerConfigured(() => {
-      this.isAlertmanagerConfigured = true;
-    });
-    this.prometheusService.ifPrometheusConfigured(() => {
-      this.isPrometheusConfigured = true;
-    });
-
-    this.summaryService.subscribeOnce((summary) => {
-      const releaseName = this.cephReleaseNamePipe.transform(summary.version);
-      this.docsUrl = `https://docs.ceph.com/docs/${releaseName}/mgr/dashboard/#enabling-prometheus-alerting`;
-    });
-  }
-
-  setFragment(element: string) {
-    this.router.navigate([], { fragment: element });
-  }
-}
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/prometheus-list-helper.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/prometheus-list-helper.ts
new file mode 100644 (file)
index 0000000..aac25a3
--- /dev/null
@@ -0,0 +1,33 @@
+import { OnInit } from '@angular/core';
+
+import { PrometheusService } from '../../../shared/api/prometheus.service';
+import { ListWithDetails } from '../../../shared/classes/list-with-details.class';
+import { CephReleaseNamePipe } from '../../../shared/pipes/ceph-release-name.pipe';
+import { SummaryService } from '../../../shared/services/summary.service';
+
+export class PrometheusListHelper extends ListWithDetails implements OnInit {
+  public isPrometheusConfigured = false;
+  public isAlertmanagerConfigured = false;
+  public docsUrl = '';
+
+  constructor(
+    protected prometheusService: PrometheusService,
+    protected summaryService: SummaryService,
+    protected cephReleaseNamePipe: CephReleaseNamePipe
+  ) {
+    super();
+  }
+
+  ngOnInit() {
+    this.prometheusService.ifAlertmanagerConfigured(() => {
+      this.isAlertmanagerConfigured = true;
+    });
+    this.prometheusService.ifPrometheusConfigured(() => {
+      this.isPrometheusConfigured = true;
+    });
+    this.summaryService.subscribeOnce((summary) => {
+      const releaseName = this.cephReleaseNamePipe.transform(summary.version);
+      this.docsUrl = `https://docs.ceph.com/docs/${releaseName}/mgr/dashboard/#enabling-prometheus-alerting`;
+    });
+  }
+}
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/prometheus-tabs/prometheus-tabs.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/prometheus-tabs/prometheus-tabs.component.html
new file mode 100644 (file)
index 0000000..fd3967c
--- /dev/null
@@ -0,0 +1,18 @@
+<ul ngbNav
+    #nav="ngbNav"
+    [activeId]="router.url"
+    (navChange)="router.navigate([$event.nextId])"
+    class="nav-tabs">
+  <li ngbNavItem="/monitoring/active-alerts">
+    <a ngbNavLink
+       i18n>Active Alerts</a>
+  </li>
+  <li ngbNavItem="/monitoring/alerts">
+    <a ngbNavLink
+       i18n>Alerts</a>
+  </li>
+  <li ngbNavItem="/monitoring/silences">
+    <a ngbNavLink
+       i18n>Silences</a>
+  </li>
+</ul>
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/prometheus-tabs/prometheus-tabs.component.scss b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/prometheus-tabs/prometheus-tabs.component.scss
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/prometheus-tabs/prometheus-tabs.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/prometheus-tabs/prometheus-tabs.component.spec.ts
new file mode 100644 (file)
index 0000000..3176703
--- /dev/null
@@ -0,0 +1,27 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { RouterTestingModule } from '@angular/router/testing';
+
+import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap';
+
+import { configureTestBed } from '../../../../../testing/unit-test-helper';
+import { PrometheusTabsComponent } from './prometheus-tabs.component';
+
+describe('PrometheusTabsComponent', () => {
+  let component: PrometheusTabsComponent;
+  let fixture: ComponentFixture<PrometheusTabsComponent>;
+
+  configureTestBed({
+    imports: [RouterTestingModule, NgbNavModule],
+    declarations: [PrometheusTabsComponent]
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(PrometheusTabsComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/prometheus-tabs/prometheus-tabs.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/prometheus-tabs/prometheus-tabs.component.ts
new file mode 100644 (file)
index 0000000..4011770
--- /dev/null
@@ -0,0 +1,11 @@
+import { Component } from '@angular/core';
+import { Router } from '@angular/router';
+
+@Component({
+  selector: 'cd-prometheus-tabs',
+  templateUrl: './prometheus-tabs.component.html',
+  styleUrls: ['./prometheus-tabs.component.scss']
+})
+export class PrometheusTabsComponent {
+  constructor(public router: Router) {}
+}
index ba9e7e63cfbd119a3c547e139f4a684b5e06be54..8600c3df2ec9131a6db1b846c344022431f378ec 100644 (file)
@@ -1,4 +1,15 @@
-<cd-table [data]="data"
+<cd-prometheus-tabs></cd-prometheus-tabs>
+
+<cd-alert-panel *ngIf="!isPrometheusConfigured"
+                type="info"
+                i18n>To see all configured Prometheus alerts, please
+  provide the URL to the API of Prometheus as described in
+  the <a href="{{docsUrl}}"
+         target="_blank">documentation</a>.
+</cd-alert-panel>
+
+<cd-table *ngIf="isPrometheusConfigured"
+          [data]="prometheusAlertService.rules"
           [columns]="columns"
           [hasDetails]="true"
           (updateSelection)="setExpandedRow($event)"
index 7959717d80c859b09108839bb69e5c3966e14450..1c1c53486aab163018922e1abaede18c3dd7924b 100644 (file)
@@ -1,11 +1,15 @@
 import { HttpClientTestingModule } from '@angular/common/http/testing';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { RouterTestingModule } from '@angular/router/testing';
+
+import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap';
+import { ToastrModule } from 'ngx-toastr';
 
 import { configureTestBed, i18nProviders } from '../../../../../testing/unit-test-helper';
 import { PrometheusService } from '../../../../shared/api/prometheus.service';
 import { SettingsService } from '../../../../shared/api/settings.service';
 import { SharedModule } from '../../../../shared/shared.module';
+import { PrometheusTabsComponent } from '../prometheus-tabs/prometheus-tabs.component';
 import { RulesListComponent } from './rules-list.component';
 
 describe('RulesListComponent', () => {
@@ -13,8 +17,14 @@ describe('RulesListComponent', () => {
   let fixture: ComponentFixture<RulesListComponent>;
 
   configureTestBed({
-    declarations: [RulesListComponent],
-    imports: [HttpClientTestingModule, SharedModule, BrowserAnimationsModule],
+    declarations: [RulesListComponent, PrometheusTabsComponent],
+    imports: [
+      HttpClientTestingModule,
+      SharedModule,
+      NgbNavModule,
+      RouterTestingModule,
+      ToastrModule.forRoot()
+    ],
     providers: [PrometheusService, SettingsService, i18nProviders]
   });
 
index ee5f3a0e49bd9c5bd1d539f25e96b45560ad5d9b..809d7703df8e8e4aa4c38e6c391dace26dbf0080 100644 (file)
@@ -1,20 +1,22 @@
-import { Component, Input, OnInit } from '@angular/core';
+import { Component, Inject, OnInit } from '@angular/core';
 
 import { I18n } from '@ngx-translate/i18n-polyfill';
 
-import { ListWithDetails } from '../../../../shared/classes/list-with-details.class';
+import { PrometheusService } from '../../../../shared/api/prometheus.service';
 import { CdTableColumn } from '../../../../shared/models/cd-table-column';
 import { PrometheusRule } from '../../../../shared/models/prometheus-alerts';
+import { CephReleaseNamePipe } from '../../../../shared/pipes/ceph-release-name.pipe';
 import { DurationPipe } from '../../../../shared/pipes/duration.pipe';
+import { PrometheusAlertService } from '../../../../shared/services/prometheus-alert.service';
+import { SummaryService } from '../../../../shared/services/summary.service';
+import { PrometheusListHelper } from '../prometheus-list-helper';
 
 @Component({
   selector: 'cd-rules-list',
   templateUrl: './rules-list.component.html',
   styleUrls: ['./rules-list.component.scss']
 })
-export class RulesListComponent extends ListWithDetails implements OnInit {
-  @Input()
-  data: any;
+export class RulesListComponent extends PrometheusListHelper implements OnInit {
   columns: CdTableColumn[];
   expandedRow: PrometheusRule;
 
@@ -25,11 +27,18 @@ export class RulesListComponent extends ListWithDetails implements OnInit {
    */
   hideKeys = ['alerts', 'type'];
 
-  constructor(private i18n: I18n) {
-    super();
+  constructor(
+    private i18n: I18n,
+    public prometheusAlertService: PrometheusAlertService,
+    @Inject(PrometheusService) prometheusService: PrometheusService,
+    @Inject(SummaryService) summaryService: SummaryService,
+    @Inject(CephReleaseNamePipe) cephReleaseNamePipe: CephReleaseNamePipe
+  ) {
+    super(prometheusService, summaryService, cephReleaseNamePipe);
   }
 
   ngOnInit() {
+    super.ngOnInit();
     this.columns = [
       { prop: 'name', name: this.i18n('Name') },
       { prop: 'labels.severity', name: this.i18n('Severity') },
index 513d5b1fbc1b8469444d19df6a9e25c8068f1022..365fcf1f74a4a8fb5d35231997964c4172ebfb58 100644 (file)
@@ -84,10 +84,10 @@ describe('SilenceFormComponent', () => {
 
   const changeAction = (action: string) => {
     const modes = {
-      add: '/monitoring/silence/add',
-      alertAdd: '/monitoring/silence/add/someAlert',
-      recreate: '/monitoring/silence/recreate/someExpiredId',
-      edit: '/monitoring/silence/edit/someNotExpiredId'
+      add: '/monitoring/silences/add',
+      alertAdd: '/monitoring/silences/add/someAlert',
+      recreate: '/monitoring/silences/recreate/someExpiredId',
+      edit: '/monitoring/silences/edit/someNotExpiredId'
     };
     Object.defineProperty(router, 'url', { value: modes[action] });
     callInit();
index a2714537db25a168f796fe3093f409ac4d2ef1a4..bcbb8517016148d29f34dc2a9748b63ee2e0be95 100644 (file)
@@ -96,8 +96,8 @@ export class SilenceFormComponent {
   }
 
   private chooseMode() {
-    this.edit = this.router.url.startsWith('/monitoring/silence/edit');
-    this.recreate = this.router.url.startsWith('/monitoring/silence/recreate');
+    this.edit = this.router.url.startsWith('/monitoring/silences/edit');
+    this.recreate = this.router.url.startsWith('/monitoring/silences/recreate');
     if (this.edit) {
       this.action = this.actionLabels.EDIT;
     } else if (this.recreate) {
@@ -298,7 +298,7 @@ export class SilenceFormComponent {
     }
     this.prometheusService.setSilence(this.getSubmitData()).subscribe(
       (resp) => {
-        this.router.navigate(['/monitoring'], { fragment: 'silences' });
+        this.router.navigate(['/monitoring/silences']);
         this.notificationService.show(
           NotificationType.success,
           this.getNotificationTile(resp.body['silenceId']),
index 5a25ec686c1ee3b1ca76463c69fe9dc53bf2f0c3..364796d876190271e9c792eaf04c18217b110a1a 100644 (file)
@@ -1,4 +1,15 @@
-<cd-table [data]="silences"
+<cd-prometheus-tabs></cd-prometheus-tabs>
+
+<cd-alert-panel *ngIf="!isAlertmanagerConfigured"
+                type="info"
+                i18n>To enable Silences, please provide the URL to the
+  API of the Prometheus' Alertmanager as described in
+  the <a href="{{docsUrl}}"
+         target="_blank">documentation</a>.
+</cd-alert-panel>
+
+<cd-table *ngIf="isAlertmanagerConfigured"
+          [data]="silences"
           [columns]="columns"
           [forceIdentifier]="true"
           [customCss]="customCss"
index 859b94b5d3e6307f2c4f3293f6c98271822f342c..c428f7ca4b4701a3906fac158b248b34cd318102 100644 (file)
@@ -3,6 +3,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
 import { RouterTestingModule } from '@angular/router/testing';
 
+import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap';
 import { ToastrModule } from 'ngx-toastr';
 import { of } from 'rxjs';
 
@@ -18,6 +19,7 @@ import { NotificationType } from '../../../../shared/enum/notification-type.enum
 import { ModalService } from '../../../../shared/services/modal.service';
 import { NotificationService } from '../../../../shared/services/notification.service';
 import { SharedModule } from '../../../../shared/shared.module';
+import { PrometheusTabsComponent } from '../prometheus-tabs/prometheus-tabs.component';
 import { SilenceListComponent } from './silence-list.component';
 
 describe('SilenceListComponent', () => {
@@ -31,9 +33,10 @@ describe('SilenceListComponent', () => {
       SharedModule,
       ToastrModule.forRoot(),
       RouterTestingModule,
-      HttpClientTestingModule
+      HttpClientTestingModule,
+      NgbNavModule
     ],
-    declarations: [SilenceListComponent],
+    declarations: [SilenceListComponent, PrometheusTabsComponent],
     providers: [i18nProviders]
   });
 
index 64bb72b8df0e2d145b80072e9e630071d5415923..daba3e2a8d61c30109807201835f951e8a03281c 100644 (file)
@@ -1,4 +1,4 @@
-import { Component } from '@angular/core';
+import { Component, Inject } from '@angular/core';
 
 import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
 import { I18n } from '@ngx-translate/i18n-polyfill';
@@ -6,7 +6,6 @@ import { SortDirection, SortPropDir } from '@swimlane/ngx-datatable';
 import { Observable, Subscriber } from 'rxjs';
 
 import { PrometheusService } from '../../../../shared/api/prometheus.service';
-import { ListWithDetails } from '../../../../shared/classes/list-with-details.class';
 import { CriticalConfirmationModalComponent } from '../../../../shared/components/critical-confirmation-modal/critical-confirmation-modal.component';
 import {
   ActionLabelsI18n,
@@ -21,12 +20,15 @@ import { CdTableColumn } from '../../../../shared/models/cd-table-column';
 import { CdTableSelection } from '../../../../shared/models/cd-table-selection';
 import { Permission } from '../../../../shared/models/permissions';
 import { CdDatePipe } from '../../../../shared/pipes/cd-date.pipe';
+import { CephReleaseNamePipe } from '../../../../shared/pipes/ceph-release-name.pipe';
 import { AuthStorageService } from '../../../../shared/services/auth-storage.service';
 import { ModalService } from '../../../../shared/services/modal.service';
 import { NotificationService } from '../../../../shared/services/notification.service';
+import { SummaryService } from '../../../../shared/services/summary.service';
 import { URLBuilderService } from '../../../../shared/services/url-builder.service';
+import { PrometheusListHelper } from '../prometheus-list-helper';
 
-const BASE_URL = 'monitoring/silence';
+const BASE_URL = 'monitoring/silences';
 
 @Component({
   providers: [{ provide: URLBuilderService, useValue: new URLBuilderService(BASE_URL) }],
@@ -34,7 +36,7 @@ const BASE_URL = 'monitoring/silence';
   templateUrl: './silence-list.component.html',
   styleUrls: ['./silence-list.component.scss']
 })
-export class SilenceListComponent extends ListWithDetails {
+export class SilenceListComponent extends PrometheusListHelper {
   silences: AlertmanagerSilence[] = [];
   columns: CdTableColumn[];
   tableActions: CdTableAction[];
@@ -52,14 +54,16 @@ export class SilenceListComponent extends ListWithDetails {
     private authStorageService: AuthStorageService,
     private i18n: I18n,
     private cdDatePipe: CdDatePipe,
-    private prometheusService: PrometheusService,
     private modalService: ModalService,
     private notificationService: NotificationService,
     private urlBuilder: URLBuilderService,
     private actionLabels: ActionLabelsI18n,
-    private succeededLabels: SucceededActionLabelsI18n
+    private succeededLabels: SucceededActionLabelsI18n,
+    @Inject(PrometheusService) prometheusService: PrometheusService,
+    @Inject(SummaryService) summaryService: SummaryService,
+    @Inject(CephReleaseNamePipe) cephReleaseNamePipe: CephReleaseNamePipe
   ) {
-    super();
+    super(prometheusService, summaryService, cephReleaseNamePipe);
     this.permission = this.authStorageService.getPermissions().prometheus;
     const selectionExpired = (selection: CdTableSelection) =>
       selection.first() && selection.first().status && selection.first().status.state === 'expired';
@@ -68,7 +72,6 @@ export class SilenceListComponent extends ListWithDetails {
         permission: 'create',
         icon: Icons.add,
         routerLink: () => this.urlBuilder.getCreate(),
-        preserveFragment: true,
         canBePrimary: (selection: CdTableSelection) => !selection.hasSingleSelection,
         name: this.actionLabels.CREATE
       },
@@ -83,7 +86,6 @@ export class SilenceListComponent extends ListWithDetails {
           !selectionExpired(selection),
         icon: Icons.copy,
         routerLink: () => this.urlBuilder.getRecreate(this.selection.first().id),
-        preserveFragment: true,
         name: this.actionLabels.RECREATE
       },
       {
@@ -97,7 +99,6 @@ export class SilenceListComponent extends ListWithDetails {
           (selection.first().cdExecuting && !selectionExpired(selection)) ||
           selectionExpired(selection),
         routerLink: () => this.urlBuilder.getEdit(this.selection.first().id),
-        preserveFragment: true,
         name: this.actionLabels.EDIT
       },
       {