]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: Add storage card to overview page
authorAfreen Misbah <afreen@ibm.com>
Sun, 8 Feb 2026 15:40:45 +0000 (21:10 +0530)
committerAfreen Misbah <afreen@ibm.com>
Thu, 12 Feb 2026 09:49:59 +0000 (15:19 +0530)
Fixes https://tracker.ceph.com/issues/73318

Signed-off-by: Afreen Misbah <afreen@ibm.com>
src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-v3.module.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/overview/overview.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/overview/overview.component.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/overview/storage-card/overview-storage-card.component.html [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/ceph/overview/storage-card/overview-storage-card.component.scss [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/ceph/overview/storage-card/overview-storage-card.component.spec.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/ceph/overview/storage-card/overview-storage-card.component.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/shared/components/productive-card/productive-card.component.html
src/pybind/mgr/dashboard/frontend/src/app/shared/components/productive-card/productive-card.component.scss
src/pybind/mgr/dashboard/frontend/src/app/shared/components/productive-card/productive-card.component.ts

index 363c9b68eddcfd655049bab528cbf7f1dd6cce5b..257215413b4fbddfb823be5105266e189aa36c94 100644 (file)
@@ -15,6 +15,7 @@ import { DashboardTimeSelectorComponent } from './dashboard-time-selector/dashbo
 import { DashboardV3Component } from './dashboard/dashboard-v3.component';
 import { PgSummaryPipe } from './pg-summary.pipe';
 import { InlineLoadingModule, ToggletipModule, TagModule } from 'carbon-components-angular';
+import { ProductiveCardComponent } from '~/app/shared/components/productive-card/productive-card.component';
 
 @NgModule({
   imports: [
@@ -30,7 +31,8 @@ import { InlineLoadingModule, ToggletipModule, TagModule } from 'carbon-componen
     BaseChartDirective,
     ToggletipModule,
     InlineLoadingModule,
-    TagModule
+    TagModule,
+    ProductiveCardComponent
   ],
   declarations: [
     DashboardV3Component,
index 70d5d3908a127c436b97217c61a838bca88f5316..30b7fa30cd00f711cb3971cf3ac869e237522505 100644 (file)
        [narrow]="true">
     <div cdsCol
          class="cds-mb-5"
-         [columnNumbers]="{lg: 11}">
-      <cds-tile>Storage card</cds-tile>
-    </div>
-    <div cdsCol
-         class="cds-mb-5"
-         [columnNumbers]="{lg: 5}">
-      <cds-tile>Docs card</cds-tile>
+         [columnNumbers]="{lg: 16}">
+      <cd-overview-storage-card></cd-overview-storage-card>
     </div>
   </div>
   <div cdsRow>
index 4ba2a899556a36f92a2e69703f691c7be0c20ccc..09d97324fd167107076f7eafa5122bfa7636ad84 100644 (file)
@@ -1,9 +1,10 @@
 import { Component } from '@angular/core';
 import { GridModule, TilesModule } from 'carbon-components-angular';
+import { OverviewStorageCardComponent } from './storage-card/overview-storage-card.component';
 
 @Component({
   selector: 'cd-overview',
-  imports: [GridModule, TilesModule],
+  imports: [GridModule, TilesModule, OverviewStorageCardComponent],
   standalone: true,
   templateUrl: './overview.component.html',
   styleUrl: './overview.component.scss'
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/overview/storage-card/overview-storage-card.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/overview/storage-card/overview-storage-card.component.html
new file mode 100644 (file)
index 0000000..556f08e
--- /dev/null
@@ -0,0 +1,43 @@
+<cd-productive-card
+  title="Storage overview"
+  i18n-title>
+  <ng-template #headerAction>
+    <cds-dropdown
+      label="Storage type"
+      class="overview-storage-card-dropdown"
+      i18n-label
+      size="sm"
+      [placeholder]="selectedStorageType"
+      (selected)="onStorageTypeSelect($event)">
+      <cds-dropdown-list [items]="dropdownItems"></cds-dropdown-list>
+    </cds-dropdown>
+  </ng-template>
+  <div class="overview-storage-card-chart-header">
+    <h5>
+      <span
+        class="cds--type-heading-05"
+        i18n>200{{' '}}</span>
+      <span
+        class="cds--type-body-02"
+        i18n>TB of 1300 TB used</span>
+    </h5>
+    <cds-tooltip
+      [autoAlign]="true"
+      class="cds-mt-5 "
+      title=""
+      [caret]="true"
+      description="An info tip about raw capacity"
+      i18n-description>
+      <cds-checkbox
+        [checked]="isRawCapacity"
+        (checkedChange)="toggleRawCapacity($event)"
+        i18n>
+        Raw capacity
+      </cds-checkbox>
+    </cds-tooltip>
+  </div>
+  <ibm-meter-chart
+    [options]="options"
+    [data]="displayData"
+    class="overview-storage-card-chart"></ibm-meter-chart>
+</cd-productive-card>
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/overview/storage-card/overview-storage-card.component.scss b/src/pybind/mgr/dashboard/frontend/src/app/ceph/overview/storage-card/overview-storage-card.component.scss
new file mode 100644 (file)
index 0000000..f1ab45e
--- /dev/null
@@ -0,0 +1,33 @@
+.overview-storage-card {
+  // Hiding the native chart title
+  &-chart {
+    .meter-title {
+      height: 0 !important;
+      display: none !important;
+    }
+
+    .spacer {
+      height: 0 !important;
+      display: none !important;
+    }
+  }
+
+  &-chart-header {
+    display: flex;
+    justify-content: space-between;
+  }
+
+  &-dropdown {
+    display: flex;
+    justify-content: flex-end;
+    align-items: flex-end;
+
+    .cds--label {
+      padding-right: var(--cds-spacing-03);
+    }
+
+    .cds--dropdown {
+      flex: 0 0 35%;
+    }
+  }
+}
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/overview/storage-card/overview-storage-card.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/overview/storage-card/overview-storage-card.component.spec.ts
new file mode 100644 (file)
index 0000000..ebfa6cc
--- /dev/null
@@ -0,0 +1,22 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { OverviewStorageCardComponent } from './overview-storage-card.component';
+
+describe('OverviewStorageCardComponent', () => {
+  let component: OverviewStorageCardComponent;
+  let fixture: ComponentFixture<OverviewStorageCardComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [OverviewStorageCardComponent]
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(OverviewStorageCardComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/overview/storage-card/overview-storage-card.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/overview/storage-card/overview-storage-card.component.ts
new file mode 100644 (file)
index 0000000..1db7cb7
--- /dev/null
@@ -0,0 +1,92 @@
+import { Component, ViewEncapsulation } from '@angular/core';
+import {
+  CheckboxModule,
+  DropdownModule,
+  GridModule,
+  TilesModule,
+  TooltipModule
+} from 'carbon-components-angular';
+import { ProductiveCardComponent } from '~/app/shared/components/productive-card/productive-card.component';
+import { MeterChartComponent, MeterChartOptions } from '@carbon/charts-angular';
+
+const StorageType = {
+  ALL: $localize`All`,
+  BLOCK: $localize`Block`,
+  FILE: $localize`File`,
+  OBJECT: $localize`Object`
+};
+
+@Component({
+  selector: 'cd-overview-storage-card',
+  imports: [
+    GridModule,
+    TilesModule,
+    ProductiveCardComponent,
+    MeterChartComponent,
+    CheckboxModule,
+    DropdownModule,
+    TooltipModule
+  ],
+  standalone: true,
+  templateUrl: './overview-storage-card.component.html',
+  styleUrl: './overview-storage-card.component.scss',
+  encapsulation: ViewEncapsulation.None
+})
+export class OverviewStorageCardComponent {
+  options: MeterChartOptions = {
+    height: '45px',
+    meter: {
+      proportional: {
+        total: 2000,
+        unit: 'GB',
+        breakdownFormatter: (_e) => null,
+        totalFormatter: (_e) => null
+      }
+    },
+    toolbar: {
+      enabled: false
+    },
+    color: {
+      pairing: {
+        option: 2
+      }
+    },
+    canvasZoom: {
+      enabled: false
+    }
+  };
+  allData = [
+    {
+      group: StorageType.BLOCK,
+      value: 202
+    },
+    {
+      group: StorageType.FILE,
+      value: 654
+    },
+    {
+      group: StorageType.OBJECT,
+      value: 120
+    }
+  ];
+  dropdownItems = [
+    { content: StorageType.ALL },
+    { content: StorageType.BLOCK },
+    { content: StorageType.FILE },
+    { content: StorageType.OBJECT }
+  ];
+  isRawCapacity: boolean = true;
+  selectedStorageType: string = StorageType.ALL;
+  displayData = this.allData;
+
+  toggleRawCapacity(isChecked: boolean) {
+    this.isRawCapacity = isChecked;
+  }
+
+  onStorageTypeSelect(selected: { item: { content: string; selected: true } }) {
+    this.selectedStorageType = selected?.item?.content;
+    if (this.selectedStorageType === StorageType.ALL) {
+      this.displayData = this.allData;
+    } else this.displayData = this.allData.filter((d) => d.group === this.selectedStorageType);
+  }
+}
index 67a4cbfaee4e3491e8aa2561863739c1f64b222e..aa328a0ab44e11ea00e2e8d9c0a3d5cb036677da 100644 (file)
@@ -3,27 +3,27 @@
           [cdsLayer]="0">
   <header
     cdsGrid
-    [useCssGrid]="true"
-    [narrow]="true"
     class="productive-card-header">
-    <h2 cdsCol
-        [columnNumbers]="{md: headerActionTemplate ? 12 : 16, lg: headerActionTemplate ? 12 : 16}"
-        class="cds--type-heading-compact-02 productive-card-header-title">
-      {{title}}
-    </h2>
-  @if(headerActionTemplate) {
-  <div cdsCol
-       [columnNumbers]="{md: 4, lg: 4}"
-       class="productive-card-header-actions">
-    <ng-container *ngTemplateOutlet="headerActionTemplate"></ng-container>
-  </div>
-  }
+    <div cdsRow
+         class="productive-card-header-row">
+      <div cdsCol
+           [columnNumbers]="{sm: headerActionTemplate ? 12 : 16, md: headerActionTemplate ? 12 : 16, lg: headerActionTemplate ? 12 : 16}">
+        <h2 class="cds--type-heading-compact-02">{{title}}</h2>
+      </div>
+      @if(!!headerActionTemplate) {
+      <div cdsCol
+           [columnNumbers]="{sm: 4, md: 4, lg: 4}"
+           class="productive-card-header-actions">
+        <ng-container *ngTemplateOutlet="headerActionTemplate"></ng-container>
+      </div>
+      }
+    </div>
   </header>
   <section class="productive-card-section cds--type-body-compact-01"
            [ngClass]="{'productive-card-section--footer': footerTemplate}">
     <ng-content></ng-content>
   </section>
-  @if(footerTemplate) {
+  @if(!!footerTemplate) {
   <footer class="productive-card-footer">
     <ng-container *ngTemplateOutlet="footerTemplate"></ng-container>
   </footer>
index cbfd1402f95afaa499918e51716e944ade5a1ffc..d550c32f7ca57840a89acf49eda3920eb9dd0c7a 100644 (file)
@@ -5,16 +5,15 @@
   padding: 0;
 
   &-header {
-    margin: 0;
-    padding: var(--cds-spacing-05);
+    padding-inline: var(--cds-spacing-05);
+  }
 
-    &-title {
-      margin: 0;
-    }
+  &-header-row {
+    padding: var(--cds-spacing-05);
+  }
 
-    &-actions {
-      margin: 0;
-    }
+  &-header-actions {
+    padding-right: 0;
   }
 
   &-section {
index 7047a1a3c68d6a7cd057abac797f9fc81f7bab57..aba50e37af731cbee06c73f228dd38330adcbbea 100644 (file)
@@ -1,4 +1,6 @@
+import { CommonModule } from '@angular/common';
 import { Component, ContentChild, Input, TemplateRef } from '@angular/core';
+import { GridModule, LayerModule, TilesModule } from 'carbon-components-angular';
 
 /**
  * A generic productive card component.
@@ -13,7 +15,8 @@ import { Component, ContentChild, Input, TemplateRef } from '@angular/core';
  */
 @Component({
   selector: 'cd-productive-card',
-  standalone: false,
+  imports: [GridModule, TilesModule, CommonModule, LayerModule],
+  standalone: true,
   templateUrl: './productive-card.component.html',
   styleUrl: './productive-card.component.scss'
 })