]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: Allow closing panel when clicked outside 70734/head
authorAfreen Misbah <afreen@ibm.com>
Thu, 30 Jul 2026 21:14:27 +0000 (02:44 +0530)
committerAfreen Misbah <afreen@ibm.com>
Thu, 30 Jul 2026 21:14:27 +0000 (02:44 +0530)
-  previous panel had this behavior
-  a regression

Signed-off-by: Afreen Misbah <afreen@ibm.com>
src/pybind/mgr/dashboard/frontend/src/app/core/navigation/notification-panel/notification-panel/notification-panel.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/core/navigation/notification-panel/notification-panel/notification-panel.component.ts

index 8108a4512b2fdf568322615ffb35a995268bb921..6c3b46145a238ebd80187de9d61e080680667f70 100644 (file)
@@ -1,17 +1,24 @@
 import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { NO_ERRORS_SCHEMA } from '@angular/core';
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+
 import { NotificationPanelComponent } from './notification-panel.component';
+import { NotificationService } from '~/app/shared/services/notification.service';
+import { SharedModule } from '~/app/shared/shared.module';
 
 describe('NotificationPanelComponent', () => {
   let component: NotificationPanelComponent;
   let fixture: ComponentFixture<NotificationPanelComponent>;
+  let notificationService: NotificationService;
 
   beforeEach(async () => {
     await TestBed.configureTestingModule({
-      declarations: [NotificationPanelComponent]
+      imports: [SharedModule, HttpClientTestingModule],
+      declarations: [NotificationPanelComponent],
+      schemas: [NO_ERRORS_SCHEMA]
     }).compileComponents();
-  });
 
-  beforeEach(() => {
+    notificationService = TestBed.inject(NotificationService);
     fixture = TestBed.createComponent(NotificationPanelComponent);
     component = fixture.componentInstance;
     fixture.detectChanges();
@@ -20,4 +27,43 @@ describe('NotificationPanelComponent', () => {
   it('should create', () => {
     expect(component).toBeTruthy();
   });
+
+  it('should close panel on click outside', () => {
+    spyOn(notificationService, 'setPanelState');
+    const outsideEl = document.createElement('div');
+    document.body.appendChild(outsideEl);
+
+    component.onClickOutside(outsideEl);
+
+    expect(notificationService.setPanelState).toHaveBeenCalledWith(false);
+    outsideEl.remove();
+  });
+
+  it('should not close panel on click inside', () => {
+    spyOn(notificationService, 'setPanelState');
+
+    component.onClickOutside(fixture.nativeElement);
+
+    expect(notificationService.setPanelState).not.toHaveBeenCalled();
+  });
+
+  it('should not close panel when clicking the notification bell icon', () => {
+    spyOn(notificationService, 'setPanelState');
+    const bellEl = document.createElement('div');
+    bellEl.setAttribute('data-testid', 'header-notification-icon');
+    document.body.appendChild(bellEl);
+
+    component.onClickOutside(bellEl);
+
+    expect(notificationService.setPanelState).not.toHaveBeenCalled();
+    bellEl.remove();
+  });
+
+  it('should close panel on Escape key', () => {
+    spyOn(notificationService, 'setPanelState');
+
+    component.onEscape();
+
+    expect(notificationService.setPanelState).toHaveBeenCalledWith(false);
+  });
 });
index 495da61d2adbfef530e5db97a4dbb22170570f93..0c43c9f77ee365a968802551e92a05988ba3428c 100644 (file)
@@ -1,4 +1,7 @@
-import { Component } from '@angular/core';
+import { Component, ElementRef, HostListener, inject } from '@angular/core';
+
+import { NotificationService } from '~/app/shared/services/notification.service';
+
 @Component({
   selector: 'cd-notification-panel',
   templateUrl: './notification-panel.component.html',
@@ -6,5 +9,21 @@ import { Component } from '@angular/core';
   standalone: false
 })
 export class NotificationPanelComponent {
-  constructor() {}
+  private elementRef = inject(ElementRef);
+  private notificationService = inject(NotificationService);
+
+  @HostListener('document:click', ['$event.target'])
+  onClickOutside(target: HTMLElement): void {
+    if (
+      !this.elementRef.nativeElement.contains(target) &&
+      !target.closest('[data-testid="header-notification-icon"]')
+    ) {
+      this.notificationService.setPanelState(false);
+    }
+  }
+
+  @HostListener('document:keydown.escape')
+  onEscape(): void {
+    this.notificationService.setPanelState(false);
+  }
 }