]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: fix the landing page layout issues 53522/head
authorNizamudeen A <nia@redhat.com>
Tue, 19 Sep 2023 06:42:36 +0000 (12:12 +0530)
committerNizamudeen A <nia@redhat.com>
Tue, 3 Oct 2023 06:31:16 +0000 (12:01 +0530)
We were following a row-col grid layout for the landing page.
First row includes Details, Status and Capacity
Second row for Inventory and Cluster Utilization

So if one of the item in the first row increases, it pushes the entire
second row downwards.

To fix this, I made a col-row grid.

First col has Details and Inventory in two rows.
Second col has Status and Capacity as a col and Cluster Utilization as a
single row

Fixes: https://tracker.ceph.com/issues/62961
Signed-off-by: Nizamudeen A <nia@redhat.com>
Co-authored-by: cloudbehl <cloudbehl@gmail.com>
12 files changed:
src/pybind/mgr/dashboard/frontend/cypress/e2e/ui/dashboard-v3.e2e-spec.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-pie/dashboard-pie.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.scss
src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-overview-dashboard/rgw-overview-dashboard.component.html
src/pybind/mgr/dashboard/frontend/src/app/shared/components/card/card.component.html
src/pybind/mgr/dashboard/frontend/src/app/shared/components/card/card.component.scss
src/pybind/mgr/dashboard/frontend/src/app/shared/components/card/card.component.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/enum/health-icon.enum.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/services/prometheus-alert.service.ts

index f6433aa3f073b42f6f6592fde92ad8235b68689c..3815011a1859a90ac2cd39643c65498818e42560 100644 (file)
@@ -39,7 +39,7 @@ describe('Dashboard-v3 Main Page', () => {
     it('should verify that cards exist on dashboard in proper order', () => {
       // Ensures that cards are all displayed on the dashboard tab while being in the proper
       // order, checks for card title and position via indexing into a list of all cards.
-      const order = ['Details', 'Status', 'Capacity', 'Inventory', 'Cluster Utilization'];
+      const order = ['Details', 'Inventory', 'Status', 'Capacity', 'Cluster Utilization'];
 
       for (let i = 0; i < order.length; i++) {
         dashboard.card(i).should('contain.text', order[i]);
index ba8176beab3b505aa95e9916011fceb0a22666cc..c013ab5404b4b20b1519dfb6848e41a5de49b12f 100644 (file)
@@ -1,4 +1,4 @@
-<div class="chart-container">
+<div class="chart-container d-flex align-items-center justify-content-center">
   <canvas baseChart
           #chartCanvas
           [datasets]="chartConfig.dataset"
index d91ee51f2ccc6e43579efeee5cf3e788befd09a7..8faa23a5b2d0bc3b9f766b45e3fb60d1434174a6 100644 (file)
-<div class="container-fluid"
+<div class="container-fluid p-4"
      *ngIf="healthData && enabledFeature$ | async as enabledFeature">
-  <div class="row mx-0">
-    <cd-card cardTitle="Details"
-             i18n-title
-             class="col-sm-3 px-3"
-             [ngClass]="{'d-flex': flexHeight}"
-             aria-label="Details card">
-      <dl class="ms-4 me-4">
-        <dt>Cluster ID</dt>
-        <dd>{{ detailsCardData.fsid }}</dd>
-        <dt>Orchestrator</dt>
-        <dd i18n>{{ detailsCardData.orchestrator || 'Orchestrator is not available' }}</dd>
-        <dt>Ceph version</dt>
-        <dd>{{ detailsCardData.cephVersion }}</dd>
-        <dt>Cluster API</dt>
-        <dd>
-          <a routerLink="/api-docs"
-             target="_blank">
-            {{ origin }}/api-docs
-            <i class="fa fa-external-link"></i>
-          </a>
-        </dd>
-        <ng-container>
-          <dt>Telemetry Dashboard
-            <span
-              class="badge"
-              [ngClass]="telemetryEnabled ? 'badge-success' : 'badge-secondary'"
-              [ngbTooltip]="getTelemetryText()" >
-              {{ telemetryEnabled ? 'Active' : 'Inactive' }}
-            </span>
-          </dt>
+
+  <div class="row d-flex flex-row ps-3">
+
+    <!-- First Grid to hold Details and Inventory Card-->
+    <div class="col-sm-3 d-flex flex-column ps-2 pe-4">
+
+      <!-- Details Card-->
+      <cd-card cardTitle="Details"
+               i18n-title
+               class="details"
+               aria-label="Details card">
+        <dl class="ms-4 me-4">
+          <dt>Cluster ID</dt>
+          <dd>{{ detailsCardData.fsid }}</dd>
+          <dt>Orchestrator</dt>
+          <dd i18n>{{ detailsCardData.orchestrator || 'Orchestrator is not available' }}</dd>
+          <dt>Ceph version</dt>
+          <dd>{{ detailsCardData.cephVersion }}</dd>
+          <dt>Cluster API</dt>
           <dd>
-            <a target="_blank"
-               [href]="telemetryURL">
-               {{ telemetryURL }}
+            <a routerLink="/api-docs"
+               target="_blank">
+               {{ origin }}/api-docs
               <i class="fa fa-external-link"></i>
             </a>
           </dd>
-        </ng-container>
-      </dl>
-    </cd-card>
+          <ng-container>
+            <dt>Telemetry Dashboard
+              <span
+                class="badge"
+                [ngClass]="telemetryEnabled ? 'badge-success' : 'badge-secondary'"
+                [ngbTooltip]="getTelemetryText()" >
+                {{ telemetryEnabled ? 'Active' : 'Inactive' }}
+              </span>
+            </dt>
+            <dd>
+              <a target="_blank"
+                 [href]="telemetryURL">
+                 {{ telemetryURL }}
+                <i class="fa fa-external-link"></i>
+              </a>
+            </dd>
+          </ng-container>
+        </dl>
+      </cd-card>
 
-    <cd-card cardTitle="Status"
-             i18n-title
-             class="col-sm-6 px-3 d-flex"
-             aria-label="Status card">
-      <div class="d-flex ms-4 me-4 mb-5 center-content">
-        <ng-template #healthChecks>
-          <ng-container *ngTemplateOutlet="logsLink"></ng-container>
-          <ul>
-            <li *ngFor="let check of healthData.health.checks">
-              <span [ngStyle]="check.severity | healthColor"
-                    [class.health-warn-description]="check.severity === 'HEALTH_WARN'">
-              {{ check.type }}</span>: {{ check.summary.message }}
-            </li>
-          </ul>
-        </ng-template>
-        <i *ngIf="healthData.health?.status"
-           [ngClass]="[healthData.health.status | healthIcon, icons.large2x]"
-           [ngStyle]="healthData.health.status | healthColor"
-           [title]="healthData.health.status"></i>
-        <a class="ms-2 mt-n1 lead text-primary"
-           [ngbPopover]="healthChecks"
-           popoverClass="info-card-popover-cluster-status"
-           [openDelay]="300"
-           [closeDelay]="500"
-           triggers="mouseenter:mouseleave"
-           *ngIf="healthData.health?.checks?.length"
-           i18n>Cluster</a>
-        <span class="ms-2 mt-n1 lead"
-              *ngIf="!healthData.health?.checks?.length"
-              i18n>Cluster</span>
-      </div>
-      <section class="border-top mt-5"
-               *ngIf="isAlertmanagerConfigured && (prometheusAlertService.activeCriticalAlerts || prometheusAlertService.activeWarningAlerts)">
-        <div class="d-flex flex-wrap ms-4 me-4">
-          <span class="pt-2"
-                i18n>Alerts</span>
-          <!-- Potentially make widget component -->
-          <button class="btn btn-outline-danger rounded-pill ms-2"
-                  [ngClass]="{'active': showAlerts && alertType === 'critical'}"
-                  title="Danger"
-                  (click)="toggleAlertsWindow('danger')"
-                  id="dangerAlerts"
-                  i18n-title
-                  *ngIf="prometheusAlertService?.activeCriticalAlerts > 0">
-            <i [ngClass]="[icons.danger]"></i>
-            <span>{{ prometheusAlertService.activeCriticalAlerts }}</span>
-          </button>
+      <!-- Inventory Card-->
+      <cd-card cardTitle="Inventory"
+               i18n-title
+               class="pt-4"
+               aria-label="Inventory card">
+        <hr>
+        <!-- Hosts -->
+        <li class="list-group-item">
+          <cd-card-row [data]="healthData.hosts"
+                       link="/hosts"
+                       title="Host"
+                       summaryType="simplified"
+                       *ngIf="healthData.hosts != null"></cd-card-row>
+        </li>
+        <hr>
+        <!-- Monitors -->
+        <li class="list-group-item">
+          <cd-card-row [data]="healthData.mon_status.monmap.mons.length"
+                       link="/monitor"
+                       title="Monitor"
+                       summaryType="simplified"
+                       *ngIf="healthData.mon_status"></cd-card-row>
+        </li>
+        <hr>
+        <!-- Managers -->
+        <li *ngIf="healthData.mgr_map"
+            class="list-group-item">
+          <cd-card-row [data]="healthData.mgr_map | mgrSummary"
+                       title="Manager"
+                       *ngIf="healthData.mgr_map"></cd-card-row>
+        </li>
+        <hr>
+        <!-- OSDs -->
+        <li class="list-group-item">
+          <cd-card-row [data]="healthData.osd_map | osdSummary"
+                       link="/osd"
+                       title="OSD"
+                       summaryType="osd"
+                       *ngIf="healthData.osd_map"></cd-card-row>
+        </li>
+        <hr>
+        <!-- Pools -->
+        <li *ngIf="healthData.pools"
+            class="list-group-item">
+          <cd-card-row [data]="healthData.pools.length"
+                       link="/pool"
+                       title="Pool"
+                       summaryType="simplified"
+                       *ngIf="healthData.pools"></cd-card-row>
+        </li>
+        <hr>
+        <!-- PG Info -->
+        <li class="list-group-item">
+          <cd-card-row [data]="healthData.pg_info | pgSummary"
+                       title="PG"
+                       *ngIf="healthData.pg_info"></cd-card-row>
+        </li>
+        <hr>
+        <!-- Object gateways -->
+        <li *ngIf="enabledFeature.rgw && healthData.rgw != null"
+            class="list-group-item"
+            id="rgw-item">
+          <cd-card-row [data]="healthData.rgw"
+                       link="/rgw/daemon"
+                       title="Object Gateway"
+                       summaryType="simplified"
+                       *ngIf="healthData.rgw || healthData.rgw === 0 "></cd-card-row>
+        </li>
+        <hr>
+        <!-- Metadata Servers -->
+        <li *ngIf="enabledFeature.cephfs && healthData.fs_map"
+            class="list-group-item"
+            id="mds-item">
+          <cd-card-row [data]="healthData.fs_map | mdsSummary"
+                       title="Metadata Server"
+                       *ngIf="healthData.fs_map"></cd-card-row>
+        </li>
+        <hr>
+        <!-- iSCSI Gateways -->
+        <li *ngIf="enabledFeature.iscsi && healthData.iscsi_daemons != null"
+            class="list-group-item"
+            id="iscsi-item">
+          <cd-card-row [data]="healthData.iscsi_daemons"
+                       link="/iscsi/daemon"
+                       title="iSCSI Gateway"
+                       summaryType="iscsi"
+                       *ngIf="healthData.iscsi_daemons"></cd-card-row>
+        </li>
+      </cd-card>
+    </div>
 
-          <button class="btn btn-outline-warning rounded-pill ms-2"
-                  [ngClass]="{'active': showAlerts && alertType === 'warning'}"
-                  title="Warning"
-                  (click)="toggleAlertsWindow('warning')"
-                  id="warningAlerts"
-                  i18n-title
-                  *ngIf="prometheusAlertService?.activeWarningAlerts > 0">
-            <i [ngClass]="[icons.infoCircle]"></i>
-            <span>{{ prometheusAlertService.activeWarningAlerts }}</span>
-          </button>
+    <!-- Second Grid to hold Status Capacity and Cluster Utilization Cards-->
+    <div class="col-sm-9 ps-0">
+      <div class="row">
+        <!-- This column will hold Status and Capacity cards-->
+        <div class="col-sm-8">
+          <cd-card cardTitle="Status"
+                   i18n-title
+                   aria-label="Status card"
+                   class="status"
+                   [alignItemsCenter]="true"
+                   [cardFooter]="isAlertmanagerConfigured && prometheusAlertService.alerts.length"
+                   [fullHeight]="true">
+            <div class="viewAlert"
+                 *ngIf="prometheusAlertService.alerts.length">
+              <a href="#/monitoring/active-alerts"
+                 i18n>
+                View alerts
+              </a>
+            </div>
+            <div class="d-flex flex-column ms-4 me-4 mt-4 mb-4">
+              <ng-template #healthChecks>
+                <ng-container *ngTemplateOutlet="logsLink"></ng-container>
+                <ul>
+                  <li *ngFor="let check of healthData.health.checks">
+                    <span [ngStyle]="check.severity | healthColor"
+                          [class.health-warn-description]="check.severity === 'HEALTH_WARN'">
+                    {{ check.type }}</span>: {{ check.summary.message }}
+                  </li>
+                </ul>
+              </ng-template>
 
-          <div class="pt-0 position-right">
-            <button class="btn btn-block dropdown-toggle"
-                    data-toggle="collapse"
-                    aria-label="toggle alert window"
-                    [attr.aria-expanded]="showAlerts"
-                    (click)="toggleAlertsWindow('danger', 'true')"></button>
+              <div class="d-flex flex-row">
+                <i *ngIf="healthData.health?.status"
+                   [ngClass]="[healthData.health.status | healthIcon, icons.large2x]"
+                   [ngStyle]="healthData.health.status | healthColor"
+                   [title]="healthData.health.status"></i>
+                <a class="ms-2 mt-n1 lead text-primary"
+                   [ngbPopover]="healthChecks"
+                   popoverClass="info-card-popover-cluster-status"
+                   [openDelay]="300"
+                   [closeDelay]="500"
+                   triggers="mouseenter:mouseleave"
+                   *ngIf="healthData.health?.checks?.length"
+                   i18n>Cluster</a>
+                <span class="ms-2 mt-n1 lead"
+                      *ngIf="!healthData.health?.checks?.length"
+                      i18n>Cluster</span>
+              </div>
+            </div>
+            <section class="footer alerts"
+                     *ngIf="isAlertmanagerConfigured && prometheusAlertService.alerts.length">
+              <div class="d-flex flex-wrap ms-4 me-4 mb-3 mt-3">
+                <span class="pt-2"
+                      i18n>Alerts</span>
 
-          </div>
+                <!-- Potentially make widget component -->
+                <button class="btn btn-outline-danger rounded-pill ms-2"
+                        [ngClass]="{'active': true && alertType === 'critical'}"
+                        title="Danger"
+                        (click)="toggleAlertsWindow('critical')"
+                        id="dangerAlerts"
+                        i18n-title
+                        *ngIf="prometheusAlertService?.activeCriticalAlerts">
+                  <i [ngClass]="[icons.danger]"></i>
+                  <span>{{ prometheusAlertService.activeCriticalAlerts }}</span>
+                </button>
+
+                <button class="btn btn-outline-warning rounded-pill ms-2"
+                        [ngClass]="{'active': true && alertType === 'warning'}"
+                        title="Warning"
+                        (click)="toggleAlertsWindow('warning')"
+                        id="warningAlerts"
+                        i18n-title
+                        *ngIf="prometheusAlertService?.activeWarningAlerts">
+                  <i [ngClass]="[icons.infoCircle]"></i>
+                  <span>{{ prometheusAlertService.activeWarningAlerts }}</span>
+                </button>
+              </div>
+
+              <div class="alerts-section pt-0">
+                <hr class="mt-1 mb-0">
+                <ngx-simplebar [options]="simplebar">
+                  <div class="card-body p-0">
+                    <ng-container *ngTemplateOutlet="alertsCard"></ng-container>
+                  </div>
+                </ngx-simplebar>
+              </div>
+            </section>
+          </cd-card>
         </div>
-        <div class="alerts pt-0"
-             *ngIf="showAlerts">
-          <hr class="mt-4">
-          <ngx-simplebar [options]="simplebar">
-            <div class="card-body ps-0 pe-1 pt-1">
-              <ng-container *ngTemplateOutlet="alertsCard"></ng-container>
-            </div>
-          </ngx-simplebar>
+        <div class="col-sm-4 ps-0">
+          <cd-card cardTitle="Capacity"
+                   i18n-title
+                   [fullHeight]="true"
+                   aria-label="Capacity card">
+            <ng-container class="ms-4 me-4"
+                          *ngIf="capacity && osdSettings">
+              <cd-dashboard-pie [data]="{max: capacity.total_bytes, current: capacity.total_used_raw_bytes}"
+                                [lowThreshold]="osdSettings.nearfull_ratio"
+                                [highThreshold]="osdSettings.full_ratio">
+              </cd-dashboard-pie>
+            </ng-container>
+          </cd-card>
         </div>
-      </section>
-    </cd-card>
-
-    <cd-card cardTitle="Capacity"
-             i18n-title
-             class="col-sm-3 px-3"
-             [ngClass]="{'d-flex': flexHeight}"
-             aria-label="Capacity card">
-      <ng-container class="ms-4 me-4"
-                    *ngIf="capacity && osdSettings">
-        <cd-dashboard-pie [data]="{max: capacity.total_bytes, current: capacity.total_used_raw_bytes}"
-                          [lowThreshold]="osdSettings.nearfull_ratio"
-                          [highThreshold]="osdSettings.full_ratio">
-        </cd-dashboard-pie>
-      </ng-container>
-    </cd-card>
-  </div>
-  <!-- Second row -->
-  <div class="row mx-0">
-    <!-- Inventory Card -->
-    <cd-card cardTitle="Inventory"
-             i18n-title
-             class="col-sm-3 px-3 d-flex"
-             aria-label="Inventory card">
-      <hr>
-      <!-- Hosts -->
-      <li class="list-group-item">
-        <cd-card-row [data]="healthData.hosts"
-                     link="/hosts"
-                     title="Host"
-                     summaryType="simplified"
-                     *ngIf="healthData.hosts != null"></cd-card-row>
-      </li>
-      <hr>
-      <!-- Monitors -->
-      <li class="list-group-item">
-        <cd-card-row [data]="healthData.mon_status.monmap.mons.length"
-                     link="/monitor"
-                     title="Monitor"
-                     summaryType="simplified"
-                     *ngIf="healthData.mon_status"></cd-card-row>
-      </li>
-      <hr>
-      <!-- Managers -->
-      <li *ngIf="healthData.mgr_map"
-          class="list-group-item">
-        <cd-card-row [data]="healthData.mgr_map | mgrSummary"
-                     title="Manager"
-                     *ngIf="healthData.mgr_map"></cd-card-row>
-      </li>
-      <hr>
-      <!-- OSDs -->
-      <li class="list-group-item">
-        <cd-card-row [data]="healthData.osd_map | osdSummary"
-                     link="/osd"
-                     title="OSD"
-                     summaryType="osd"
-                     *ngIf="healthData.osd_map"></cd-card-row>
-      </li>
-      <hr>
-      <!-- Pools -->
-      <li *ngIf="healthData.pools"
-          class="list-group-item">
-        <cd-card-row [data]="healthData.pools.length"
-                     link="/pool"
-                     title="Pool"
-                     summaryType="simplified"
-                     *ngIf="healthData.pools"></cd-card-row>
-      </li>
-      <hr>
-      <!-- PG Info -->
-      <li class="list-group-item">
-        <cd-card-row [data]="healthData.pg_info | pgSummary"
-                     title="PG"
-                     *ngIf="healthData.pg_info"></cd-card-row>
-      </li>
-      <hr>
-      <!-- Object gateways -->
-      <li *ngIf="enabledFeature.rgw && healthData.rgw != null"
-          class="list-group-item"
-          id="rgw-item">
-        <cd-card-row [data]="healthData.rgw"
-                     link="/rgw/daemon"
-                     title="Object Gateway"
-                     summaryType="simplified"
-                     *ngIf="healthData.rgw || healthData.rgw === 0 "></cd-card-row>
-      </li>
-      <hr>
-      <!-- Metadata Servers -->
-      <li *ngIf="enabledFeature.cephfs && healthData.fs_map"
-          class="list-group-item"
-          id="mds-item">
-        <cd-card-row [data]="healthData.fs_map | mdsSummary"
-                     title="Metadata Server"
-                     *ngIf="healthData.fs_map"></cd-card-row>
-      </li>
-      <hr>
-      <!-- iSCSI Gateways -->
-      <li *ngIf="enabledFeature.iscsi && healthData.iscsi_daemons != null"
-          class="list-group-item"
-          id="iscsi-item">
-        <cd-card-row [data]="healthData.iscsi_daemons"
-                     link="/iscsi/daemon"
-                     title="iSCSI Gateway"
-                     summaryType="iscsi"
-                     *ngIf="healthData.iscsi_daemons"></cd-card-row>
-      </li>
-    </cd-card>
 
-    <cd-card cardTitle="Cluster Utilization"
-             i18n-title
-             class="col-sm-9 px-3 d-flex"
-             aria-label="Cluster utilization card">
-      <div class="ms-4 me-4 mt-0">
-        <cd-dashboard-time-selector (selectedTime)="getPrometheusData($event)">
-        </cd-dashboard-time-selector>
-        <ng-container *ngIf="capacity">
-          <cd-dashboard-area-chart chartTitle="Used Capacity (RAW)"
-                                   [maxValue]="capacity.total_bytes"
-                                   dataUnits="B"
-                                   label="Used Capacity"
-                                   [data]="queriesResults.USEDCAPACITY">
-          </cd-dashboard-area-chart>
-        </ng-container>
-        <cd-dashboard-area-chart chartTitle="IOPS"
-                                 dataUnits=""
-                                 decimals="0"
-                                 label="Reads"
-                                 label2="Writes"
-                                 [data]="queriesResults.READIOPS"
-                                 [data2]="queriesResults.WRITEIOPS">
-        </cd-dashboard-area-chart>
-        <cd-dashboard-area-chart chartTitle="OSD Latencies"
-                                 dataUnits="ms"
-                                 decimals="2"
-                                 label="Apply"
-                                 label2="Commit"
-                                 [data]="queriesResults.READLATENCY"
-                                 [data2]="queriesResults.WRITELATENCY">
-        </cd-dashboard-area-chart>
-        <cd-dashboard-area-chart chartTitle="Client Throughput"
-                                 dataUnits="B/s"
-                                 decimals="2"
-                                 label="Reads"
-                                 label2="Writes"
-                                 [data]="queriesResults.READCLIENTTHROUGHPUT"
-                                 [data2]="queriesResults.WRITECLIENTTHROUGHPUT">
-        </cd-dashboard-area-chart>
-        <cd-dashboard-area-chart chartTitle="Recovery Throughput"
-                                 dataUnits="B/s"
-                                 decimals="2"
-                                 label="Recovery Throughput"
-                                 [data]="queriesResults.RECOVERYBYTES">
-        </cd-dashboard-area-chart>
+      <!-- This column will hold Cluster Utlization card -->
+        <div class="col-sm-12 d-flex flex-column pt-4">
+          <cd-card cardTitle="Cluster Utilization"
+                   i18n-title
+                   aria-label="Cluster utilization card">
+            <div class="ms-4 me-4 mt-0">
+              <cd-dashboard-time-selector (selectedTime)="getPrometheusData($event)">
+              </cd-dashboard-time-selector>
+              <ng-container *ngIf="capacity">
+                <cd-dashboard-area-chart chartTitle="Used Capacity (RAW)"
+                                         [maxValue]="capacity.total_bytes"
+                                         dataUnits="B"
+                                         label="Used Capacity"
+                                         [data]="queriesResults.USEDCAPACITY">
+                </cd-dashboard-area-chart>
+              </ng-container>
+              <cd-dashboard-area-chart chartTitle="IOPS"
+                                       dataUnits=""
+                                       decimals="0"
+                                       label="Reads"
+                                       label2="Writes"
+                                       [data]="queriesResults.READIOPS"
+                                       [data2]="queriesResults.WRITEIOPS">
+              </cd-dashboard-area-chart>
+              <cd-dashboard-area-chart chartTitle="OSD Latencies"
+                                       dataUnits="ms"
+                                       decimals="2"
+                                       label="Apply"
+                                       label2="Commit"
+                                       [data]="queriesResults.READLATENCY"
+                                       [data2]="queriesResults.WRITELATENCY">
+              </cd-dashboard-area-chart>
+              <cd-dashboard-area-chart chartTitle="Client Throughput"
+                                       dataUnits="B/s"
+                                       decimals="2"
+                                       label="Reads"
+                                       label2="Writes"
+                                       [data]="queriesResults.READCLIENTTHROUGHPUT"
+                                       [data2]="queriesResults.WRITECLIENTTHROUGHPUT">
+              </cd-dashboard-area-chart>
+              <cd-dashboard-area-chart chartTitle="Recovery Throughput"
+                                       dataUnits="B/s"
+                                       decimals="2"
+                                       label="Recovery Throughput"
+                                       [data]="queriesResults.RECOVERYBYTES">
+              </cd-dashboard-area-chart>
+            </div>
+          </cd-card>
+        </div>
       </div>
-    </cd-card>
+    </div>
   </div>
 </div>
 
 <ng-template #alertsCard>
-  <ng-container *ngFor="let alert of alerts; let i = index">
-    <div [ngClass]="borderClass"
-         *ngIf="alertType === alert.labels.severity">
+  <ng-container *ngFor="let alert of prometheusAlertService.alerts; let i = index;  trackBy: trackByFn">
+    <div [ngClass]="['border-'+alertClass[alert.labels.severity]]"
+         *ngIf="alert.labels.severity === alertType || !alertType">
       <div class="card tc_alerts border-0 pt-3">
-        <div class="row no-gutters">
+        <div class="row no-gutters ps-2">
           <div class="col-sm-1 text-center">
-            <span [ngClass]="[icons.stack, icons.large, textClass]">
+            <span [ngClass]="[icons.stack, icons.large, 'text-'+alertClass[alert.labels.severity]]">
               <i [ngClass]="[icons.circle, icons.stack2x]"></i>
               <i [ngClass]="[icons.stack1x, icons.inverse, icons.warning]"></i>
             </span>
           </div>
-          <div class="col-md-11">
-            <div class="card-body ps-0 pe-1 pt-1">
+          <div class="col-md-11 ps-0">
+            <div class="card-body ps-0 pe-1 pb-1 pt-0">
               <h6 class="card-title bold">{{ alert.labels.alertname }}</h6>
-              <p class="card-text me-3"
-                 [innerHtml]="alert.annotations.summary"></p>
+              <p class="card-text me-3 mb-0 text-truncate"
+                 [innerHtml]="alert.annotations.description"
+                 [ngbTooltip]="alert.annotations.description"></p>
               <p class="card-text text-muted me-3">
                 <small class="date"
                        [title]="alert.startsAt | cdDate"
           </div>
         </div>
       </div>
-      <hr>
+      <hr class="mt-0 mb-0">
     </div>
   </ng-container>
 </ng-template>
index 140f5f78fa4ad842ce31feef75cf27e1d5d658a4..5d558324319de4f1059a27259bd871ef1e399bd0 100644 (file)
@@ -1,67 +1,38 @@
-.alerts {
-  height: 17rem;
+.details {
+  font-size: larger;
 
-  div {
-    padding-top: 0;
+  dt {
+    margin-bottom: 0.3rem;
   }
-}
-
-div {
-  padding-top: 20px;
-}
-
-ngx-simplebar {
-  height: 18rem;
-}
-
-hr {
-  margin-bottom: 2px;
-  margin-top: 2px;
-}
-
-.position-right {
-  margin-left: auto;
-  order: 2;
-}
 
-.center-content {
-  align-items: center;
-  margin-top: 30px;
-  position: relative;
+  dd {
+    margin-bottom: 0.8rem;
+  }
 }
 
-button.dropdown-toggle {
-  position: relative;
-
-  &::after {
-    border: 0;
-    content: '\f054';
-    font-family: 'ForkAwesome';
-    font-size: 1rem;
+.status {
+  .viewAlert {
     position: absolute;
-    right: 20px;
-    transition: transform 0.3s ease-in-out;
+    right: 2rem;
+    top: 2rem;
   }
+}
 
-  &[aria-expanded='true']::after {
-    transform: rotate(90deg);
+.alerts {
+  ngx-simplebar {
+    height: 13.5rem;
+    overflow-x: hidden;
   }
 
-  &:focus {
-    box-shadow: none;
+  .text-truncate {
+    -webkit-box-orient: vertical; /* stylelint-disable-line property-no-vendor-prefix */
+    display: -webkit-box; /* stylelint-disable-line value-no-vendor-prefix */
+    -webkit-line-clamp: 2;
+    white-space: normal;
   }
 }
 
 .list-group-item {
   border: 0;
-}
-
-dt {
-  font-size: larger;
-  margin-bottom: 0.3rem;
-}
-
-dd {
-  font-size: larger;
-  margin-bottom: 0.8rem;
+  font-size: 14px;
 }
index c274a2f5406772c1eeb4688abaa1b6eaafc76aa2..60a30456ef711d6f3f301e31014c3b4b7e2ab5db 100644 (file)
@@ -22,6 +22,7 @@ import { DashboardPieComponent } from '../dashboard-pie/dashboard-pie.component'
 import { PgSummaryPipe } from '../pg-summary.pipe';
 import { DashboardV3Component } from './dashboard-v3.component';
 import { OrchestratorService } from '~/app/shared/api/orchestrator.service';
+import { AlertClass } from '~/app/shared/enum/health-icon.enum';
 
 export class SummaryServiceMock {
   summaryDataSource = new BehaviorSubject({
@@ -171,6 +172,8 @@ describe('Dashbord Component', () => {
     spyOn(TestBed.inject(PrometheusService), 'ifAlertmanagerConfigured').and.callFake((fn) => fn());
     getAlertsSpy = spyOn(TestBed.inject(PrometheusService), 'getAlerts');
     getAlertsSpy.and.returnValue(of(alertsPayload));
+    component.prometheusAlertService.alerts = alertsPayload;
+    component.isAlertmanagerConfigured = true;
   });
 
   it('should create', () => {
@@ -240,7 +243,7 @@ describe('Dashbord Component', () => {
 
   it('should show the critical alerts window and its content', () => {
     const payload = _.cloneDeep(alertsPayload[0]);
-    component.toggleAlertsWindow('danger');
+    component.toggleAlertsWindow(AlertClass[0]);
     fixture.detectChanges();
 
     const cardTitle = fixture.debugElement.query(By.css('.tc_alerts h6.card-title'));
@@ -251,7 +254,7 @@ describe('Dashbord Component', () => {
 
   it('should show the warning alerts window and its content', () => {
     const payload = _.cloneDeep(alertsPayload[2]);
-    component.toggleAlertsWindow('warning');
+    component.toggleAlertsWindow(AlertClass.warning);
     fixture.detectChanges();
 
     const cardTitle = fixture.debugElement.query(By.css('.tc_alerts h6.card-title'));
@@ -261,8 +264,7 @@ describe('Dashbord Component', () => {
   });
 
   it('should only show the pills when the alerts are not empty', () => {
-    spyOn(TestBed.inject(PrometheusAlertService), 'activeCriticalAlerts').and.returnValue(0);
-    spyOn(TestBed.inject(PrometheusAlertService), 'activeWarningAlerts').and.returnValue(0);
+    spyOn(TestBed.inject(PrometheusAlertService), 'alerts').and.returnValue(0);
     fixture.detectChanges();
 
     const warningAlerts = fixture.debugElement.query(By.css('button[id=warningAlerts]'));
index cf2cb0b19740164c6862f4d20bceb32cbcf0bef3..7ec0cd4495be846e7f6be1360840c0bdc869bcca 100644 (file)
@@ -23,6 +23,7 @@ import { PrometheusListHelper } from '~/app/shared/helpers/prometheus-list-helpe
 import { PrometheusAlertService } from '~/app/shared/services/prometheus-alert.service';
 import { OrchestratorService } from '~/app/shared/api/orchestrator.service';
 import { MgrModuleService } from '~/app/shared/api/mgr-module.service';
+import { AlertClass } from '~/app/shared/enum/health-icon.enum';
 
 @Component({
   selector: 'cd-dashboard-v3',
@@ -43,15 +44,13 @@ export class DashboardV3Component extends PrometheusListHelper implements OnInit
   prometheusAlerts$: Observable<AlertmanagerAlert[]>;
 
   icons = Icons;
-  showAlerts = false;
   flexHeight = true;
   simplebar = {
-    autoHide: false
+    autoHide: true
   };
-  textClass: string;
   borderClass: string;
   alertType: string;
-  alerts: AlertmanagerAlert[];
+  alertClass = AlertClass;
   healthData: any;
   categoryPgAmount: Record<string, number> = {};
   totalPgs = 0;
@@ -115,23 +114,8 @@ export class DashboardV3Component extends PrometheusListHelper implements OnInit
     });
   }
 
-  toggleAlertsWindow(type: string, isToggleButton: boolean = false) {
-    this.triggerPrometheusAlerts();
-    if (isToggleButton) {
-      this.showAlerts = !this.showAlerts;
-      this.flexHeight = !this.flexHeight;
-    } else if (
-      !this.showAlerts ||
-      (this.alertType === type && type !== 'danger') ||
-      (this.alertType !== 'warning' && type === 'danger')
-    ) {
-      this.showAlerts = !this.showAlerts;
-      this.flexHeight = !this.flexHeight;
-    }
-
-    type === 'danger' ? (this.alertType = 'critical') : (this.alertType = type);
-    this.textClass = `text-${type}`;
-    this.borderClass = `border-${type}`;
+  toggleAlertsWindow(type: AlertClass) {
+    this.alertType === type ? (this.alertType = null) : (this.alertType = type);
   }
 
   getDetailsCardData() {
@@ -160,14 +144,6 @@ export class DashboardV3Component extends PrometheusListHelper implements OnInit
     });
   }
 
-  triggerPrometheusAlerts() {
-    this.prometheusService.ifAlertmanagerConfigured(() => {
-      this.prometheusService.getAlerts().subscribe((alerts) => {
-        this.alerts = alerts;
-      });
-    });
-  }
-
   public getPrometheusData(selectedTime: any) {
     this.queriesResults = this.prometheusService.getPrometheusQueriesData(
       selectedTime,
@@ -181,4 +157,8 @@ export class DashboardV3Component extends PrometheusListHelper implements OnInit
       this.telemetryEnabled = resp?.enabled;
     });
   }
+
+  trackByFn(index: any) {
+    return index;
+  }
 }
index e4cb2c1f8f53922ad893acc853b607fcf0e0b956..42bb0627776ee70c577446ccc3cdc9e4fe7364fe 100644 (file)
                 <cd-card *ngFor="let zone of replicaZonesInfo; trackBy: trackByFn"
                          cardTitle="{{zone.name}}"
                          cardType="zone"
-                         shadow="true"
+                         shadowClass="shadow"
                          i18n-title
                          class="col-sm-9 col-lg-6 align-replica-zones d-flex pt-4"
                          aria-label="Source Zones Card">
                              [cardTitle]="title"
                              i18n-title
                              cardType="syncCards"
-                             removeBorder="true"
+                             bgColor="bg-color"
+                             borderClass="border-0"
                              class="col-sm-9 col-lg-6"
                              [ngClass]="{ 'border-left': title === 'Data Sync' }"
                              aria-label="Charts Card">
index ba258a285ed950cd5cffa7d886097a2655088d08..deb408525de85457a9ae560173e1394ef3198477 100644 (file)
@@ -1,5 +1,5 @@
 <div class="card flex-fill"
-     [ngClass]="{'border-0': removeBorder, 'bg-color': cardType === 'Sync Status Card', 'shadow': shadow, 'shadow-sm': !shadow && cardType !== 'syncCards'}">
+     [ngClass]="{'border-0': removeBorder, 'bg-color': cardType === 'Sync Status Card', 'shadow': shadow, 'shadow-sm': !shadow && cardType !== 'syncCards', 'h-100': fullHeight}">
   <h4 class="card-title mt-4 ms-4 mb-0"
       *ngIf="cardType !== 'zone'">
     <span *ngIf="cardType === ''">{{ cardTitle }}</span>
       class="text-center card-title">
       {{ cardTitle }}
   </h5>
-  <div class="card-body ps-0 pe-0">
+  <div class="card-body ps-0 pe-0"
+       [ngClass]="{'d-flex align-items-center': alignItemsCenter}">
     <ng-content></ng-content>
   </div>
+  <div class="card-footer p-0 bg-white"
+       *ngIf="cardFooter">
+    <ng-content select=".footer"></ng-content>
+  </div>
 </div>
index fdf19a00ec6aa3e4ac5c39c13cccc4fa232b09b5..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
@@ -1,5 +0,0 @@
-.card-body {
-  display: flex;
-  flex-direction: column;
-  justify-content: space-evenly;
-}
index 9123b48fb3791eb933889f72d78f0276e3961f18..55f1ba6ae93626b02214604afaac6d985faf72eb 100644 (file)
@@ -17,4 +17,10 @@ export class CardComponent {
   removeBorder = false;
   @Input()
   shadow = false;
+  @Input()
+  cardFooter = false;
+  @Input()
+  fullHeight = false;
+  @Input()
+  alignItemsCenter = false;
 }
index 7330a250bde6017975ec5da2d31a898b09fa29b3..f741c396705a0173a23c3cb3ac581829afe98ef1 100644 (file)
@@ -3,3 +3,9 @@ export enum HealthIcon {
   HEALTH_WARN = 'fa fa-exclamation-triangle',
   HEALTH_OK = 'fa fa-check-circle'
 }
+
+export enum AlertClass {
+  critical = 'danger',
+  warning = 'warning',
+  info = 'info'
+}
index f26b80629b9206f61496dc4bcf513ef6eaa90e94..be6c27da6e2a77603531ca644eb4e486324cbe2e 100644 (file)
@@ -64,23 +64,25 @@ export class PrometheusAlertService {
       this.notifyOnAlertChanges(alerts, this.alerts);
     }
     this.activeAlerts = _.reduce<AlertmanagerAlert, number>(
-      this.alerts,
+      alerts,
       (result, alert) => (alert.status.state === 'active' ? ++result : result),
       0
     );
     this.activeCriticalAlerts = _.reduce<AlertmanagerAlert, number>(
-      this.alerts,
+      alerts,
       (result, alert) =>
         alert.status.state === 'active' && alert.labels.severity === 'critical' ? ++result : result,
       0
     );
     this.activeWarningAlerts = _.reduce<AlertmanagerAlert, number>(
-      this.alerts,
+      alerts,
       (result, alert) =>
         alert.status.state === 'active' && alert.labels.severity === 'warning' ? ++result : result,
       0
     );
-    this.alerts = alerts;
+    this.alerts = alerts.reverse().sort((a, b) => {
+      return a.labels.severity.localeCompare(b.labels.severity);
+    });
     this.canAlertsBeNotified = true;
   }