]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: introduce side panel as a reusable component 63872/head
authorNizamudeen A <nia@redhat.com>
Wed, 11 Jun 2025 07:59:58 +0000 (13:29 +0530)
committerNizamudeen A <nia@redhat.com>
Mon, 16 Jun 2025 10:28:41 +0000 (15:58 +0530)
Fixes: https://tracker.ceph.com/issues/71653
Signed-off-by: Nizamudeen A <nia@redhat.com>
src/pybind/mgr/dashboard/frontend/src/app/shared/components/components.module.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/components/side-panel/side-panel.component.html [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/shared/components/side-panel/side-panel.component.scss [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/shared/components/side-panel/side-panel.component.spec.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/shared/components/side-panel/side-panel.component.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/styles/_carbon-defaults.scss
src/pybind/mgr/dashboard/frontend/src/styles/defaults/_bootstrap-defaults.scss

index a46d9dc151672b1733c5e8ea65fc4b961f0f83a5..fbd9d265d6b4314340ed565a6edf841321642bd3 100644 (file)
@@ -35,7 +35,8 @@ import {
   DropdownModule,
   SelectModule,
   ComboBoxModule,
-  ProgressIndicatorModule
+  ProgressIndicatorModule,
+  PanelModule
 } from 'carbon-components-angular';
 
 import { MotdComponent } from '~/app/shared/components/motd/motd.component';
@@ -80,6 +81,7 @@ import { HelpTextComponent } from './help-text/help-text.component';
 import { FormAdvancedFieldsetComponent } from './form-advanced-fieldset/form-advanced-fieldset.component';
 import { UpgradableComponent } from './upgradable/upgradable.component';
 import { ProgressComponent } from './progress/progress.component';
+import { SidePanelComponent } from './side-panel/side-panel.component';
 
 // Icons
 import InfoIcon from '@carbon/icons/es/information/16';
@@ -122,7 +124,8 @@ import CopyIcon from '@carbon/icons/es/copy/32';
     SelectModule,
     ComboBoxModule,
     ProgressIndicatorModule,
-    BaseChartDirective
+    BaseChartDirective,
+    PanelModule
   ],
   declarations: [
     SparklineComponent,
@@ -164,7 +167,8 @@ import CopyIcon from '@carbon/icons/es/copy/32';
     HelpTextComponent,
     FormAdvancedFieldsetComponent,
     UpgradableComponent,
-    ProgressComponent
+    ProgressComponent,
+    SidePanelComponent
   ],
   providers: [provideCharts(withDefaultRegisterables())],
   exports: [
@@ -203,7 +207,8 @@ import CopyIcon from '@carbon/icons/es/copy/32';
     HelpTextComponent,
     FormAdvancedFieldsetComponent,
     UpgradableComponent,
-    ProgressComponent
+    ProgressComponent,
+    SidePanelComponent
   ]
 })
 export class ComponentsModule {
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/side-panel/side-panel.component.html b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/side-panel/side-panel.component.html
new file mode 100644 (file)
index 0000000..889607e
--- /dev/null
@@ -0,0 +1,26 @@
+<div class="overlay"
+     (click)="close()"
+     *ngIf="expanded && overlay"></div>
+
+<cds-panel [expanded]="expanded"
+           [attr.panel-size]="size">
+  <cds-icon-button
+    kind="ghost"
+    class="float-end"
+    title="Close"
+    (click)="close()">
+    <svg
+      class="cds--btn__icon"
+      cdsIcon="close"></svg>
+  </cds-icon-button>
+
+  <div
+    class="panel-header spacing-03"
+    *ngIf="headerText">
+      {{ headerText }}
+  </div>
+
+  <div class="spacing-03">
+    <ng-content select=".panel-content"></ng-content>
+  </div>
+</cds-panel>
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/side-panel/side-panel.component.scss b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/side-panel/side-panel.component.scss
new file mode 100644 (file)
index 0000000..3b4fc1c
--- /dev/null
@@ -0,0 +1,30 @@
+@use './src/styles/vendor/variables' as vv;
+
+:host ::ng-deep cds-panel {
+  &[panel-size='sm'] .cds--header-panel--expanded {
+    inline-size: 20rem;
+  }
+
+  &[panel-size='md'] .cds--header-panel--expanded {
+    inline-size: 30rem;
+  }
+
+  &[panel-size='lg'] .cds--header-panel--expanded {
+    inline-size: 40rem;
+  }
+
+  .cds--header-panel--expanded {
+    background-color: vv.$white;
+    max-inline-size: 100%;
+  }
+}
+
+.overlay {
+  background-color: vv.$side-panel-overlay-bg;
+  bottom: 0;
+  left: 0;
+  position: fixed;
+  right: 0;
+  top: 0;
+  z-index: 1000;
+}
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/side-panel/side-panel.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/side-panel/side-panel.component.spec.ts
new file mode 100644 (file)
index 0000000..1f7d97f
--- /dev/null
@@ -0,0 +1,61 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SidePanelComponent } from './side-panel.component';
+import { configureTestBed } from '~/testing/unit-test-helper';
+
+describe('SidePanelComponent', () => {
+  let component: SidePanelComponent;
+  let fixture: ComponentFixture<SidePanelComponent>;
+
+  configureTestBed({
+    declarations: [SidePanelComponent]
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(SidePanelComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+
+  it('should show overlay only when expanded is true and slideOver is false', () => {
+    component.expanded = true;
+    component.overlay = true;
+    fixture.detectChanges();
+
+    const overlay = fixture.nativeElement.querySelector('.overlay');
+    expect(overlay).toBeTruthy();
+  });
+
+  it('should call close when overlay is clicked', () => {
+    spyOn(component, 'close');
+    component.expanded = true;
+    component.overlay = true;
+    fixture.detectChanges();
+
+    const overlay = fixture.nativeElement.querySelector('.overlay');
+    overlay.click();
+    expect(component.close).toHaveBeenCalled();
+  });
+
+  it('should call close when close button is clicked', () => {
+    spyOn(component, 'close');
+    component.expanded = true;
+    fixture.detectChanges();
+
+    const button = fixture.nativeElement.querySelector('cds-icon-button');
+    button.click();
+    expect(component.close).toHaveBeenCalled();
+  });
+
+  it('should show header text when headerText is provided', () => {
+    component.headerText = 'Test header text';
+    fixture.detectChanges();
+
+    const header = fixture.nativeElement.querySelector('.panel-header');
+    expect(header.textContent).toContain('Test header text');
+  });
+});
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/side-panel/side-panel.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/side-panel/side-panel.component.ts
new file mode 100644 (file)
index 0000000..7b5a4ef
--- /dev/null
@@ -0,0 +1,19 @@
+import { Component, EventEmitter, Input, Output } from '@angular/core';
+
+@Component({
+  selector: 'cd-side-panel',
+  templateUrl: './side-panel.component.html',
+  styleUrl: './side-panel.component.scss'
+})
+export class SidePanelComponent {
+  @Input() expanded = false;
+  @Input() headerText = '';
+  @Input() overlay = true;
+  @Input() size: 'sm' | 'md' | 'lg' = 'lg';
+
+  @Output() closed = new EventEmitter<void>();
+
+  close() {
+    this.closed.emit();
+  }
+}
index 61ad991178a7a19375b75221ebb2dca469fb5253..8440f0598e171d954cd1d115c965ba362edb729b 100644 (file)
@@ -87,7 +87,8 @@ Overflow menu
 /******************************************
 Forms
 ******************************************/
-.form-header {
+.form-header,
+.panel-header {
   @include type.type-style('heading-04');
   margin-bottom: 40px;
 }
index ed319534085fdf9e845cfae3604ad1172e8b208f..cf5e2797603ef30a9da5b2da22237dfe417f9a85 100644 (file)
@@ -1,4 +1,5 @@
 // Color system
+@use '@carbon/colors';
 
 $white: #fff !default;
 $gray-100: #f8f9fa !default;
@@ -140,6 +141,9 @@ $tooltip-color: $white !default;
 $tooltip-bg: $body-color !default;
 $tooltip-opacity: 1 !default;
 
+// Side panel
+$side-panel-overlay-bg: rgba(colors.$gray-100, 50%) !default;
+
 // Misc
 
 $screen-sm-min: 576px !default;