From a6db1b8243cb4a13c95fb9c87ba589afef45a6a8 Mon Sep 17 00:00:00 2001 From: Sagar Gopale Date: Fri, 2 Jan 2026 11:17:53 +0530 Subject: [PATCH] mgr/dashboard: carbonize-osd-flags-modal Fixes: https://tracker.ceph.com/issues/74298 Signed-off-by: Sagar Gopale --- .../osd-flags-indiv-modal.component.html | 97 +++++++++++-------- .../osd-flags-indiv-modal.component.spec.ts | 24 ++--- .../osd-flags-indiv-modal.component.ts | 15 +-- .../osd/osd-list/osd-list.component.ts | 2 +- .../src/styles/ceph-custom/_spacings.scss | 16 ++- 5 files changed, 89 insertions(+), 65 deletions(-) diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-flags-indiv-modal/osd-flags-indiv-modal.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-flags-indiv-modal/osd-flags-indiv-modal.component.html index a91be0ea580f..d9fb2321f284 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-flags-indiv-modal/osd-flags-indiv-modal.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-flags-indiv-modal/osd-flags-indiv-modal.component.html @@ -1,48 +1,67 @@ - - Individual OSD Flags + + +

Individual OSD flags

+
- +
-
+ + + + + @if (permissions.osd.update) { + {{ actionLabels.UPDATE }} + } + + diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-flags-indiv-modal/osd-flags-indiv-modal.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-flags-indiv-modal/osd-flags-indiv-modal.component.spec.ts index 93c9e9adcbbf..78096e6bdbdc 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-flags-indiv-modal/osd-flags-indiv-modal.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-flags-indiv-modal/osd-flags-indiv-modal.component.spec.ts @@ -3,7 +3,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ReactiveFormsModule } from '@angular/forms'; import { RouterTestingModule } from '@angular/router/testing'; -import { NgbActiveModal, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'; +import { ModalService, TooltipModule } from 'carbon-components-angular'; import { ToastrModule } from 'ngx-toastr'; import { of as observableOf } from 'rxjs'; @@ -27,11 +27,11 @@ describe('OsdFlagsIndivModalComponent', () => { ReactiveFormsModule, SharedModule, ToastrModule.forRoot(), - NgbTooltipModule, + TooltipModule, RouterTestingModule ], declarations: [OsdFlagsIndivModalComponent], - providers: [NgbActiveModal] + providers: [ModalService] }); beforeEach(() => { @@ -137,7 +137,6 @@ describe('OsdFlagsIndivModalComponent', () => { describe('submitAction', () => { let notificationType: NotificationType; let notificationService: NotificationService; - let bsModalRef: NgbActiveModal; let flags: object; beforeEach(() => { @@ -145,8 +144,7 @@ describe('OsdFlagsIndivModalComponent', () => { spyOn(notificationService, 'show').and.callFake((type) => { notificationType = type; }); - bsModalRef = TestBed.inject(NgbActiveModal); - spyOn(bsModalRef, 'close').and.callThrough(); + spyOn(component, 'closeModal'); flags = { nodown: false, noin: false, @@ -165,7 +163,7 @@ describe('OsdFlagsIndivModalComponent', () => { req.flush({ flags, ids: [0] }); expect(req.request.body).toEqual({ flags, ids: [0] }); expect(notificationType).toBe(NotificationType.success); - expect(component.activeModal.close).toHaveBeenCalledTimes(1); + expect(component.closeModal).toHaveBeenCalledTimes(1); }); it('should submit multiple flags', () => { @@ -180,7 +178,7 @@ describe('OsdFlagsIndivModalComponent', () => { req.flush({ flags, ids: [0] }); expect(req.request.body).toEqual({ flags, ids: [0] }); expect(notificationType).toBe(NotificationType.success); - expect(component.activeModal.close).toHaveBeenCalledTimes(1); + expect(component.closeModal).toHaveBeenCalledTimes(1); }); it('should hide modal if request fails', () => { @@ -189,7 +187,7 @@ describe('OsdFlagsIndivModalComponent', () => { const req = httpTesting.expectOne('api/osd/flags/individual'); req.flush([], { status: 500, statusText: 'failure' }); expect(notificationService.show).toHaveBeenCalledTimes(0); - expect(component.activeModal.close).toHaveBeenCalledTimes(1); + expect(component.closeModal).toHaveBeenCalledTimes(1); }); }); }); @@ -269,7 +267,6 @@ describe('OsdFlagsIndivModalComponent', () => { describe('submitAction', () => { let notificationType: NotificationType; let notificationService: NotificationService; - let bsModalRef: NgbActiveModal; let flags: object; beforeEach(() => { @@ -277,8 +274,7 @@ describe('OsdFlagsIndivModalComponent', () => { spyOn(notificationService, 'show').and.callFake((type) => { notificationType = type; }); - bsModalRef = TestBed.inject(NgbActiveModal); - spyOn(bsModalRef, 'close').and.callThrough(); + spyOn(component, 'closeModal'); flags = { nodown: false, noin: false, @@ -299,7 +295,7 @@ describe('OsdFlagsIndivModalComponent', () => { req.flush({ flags, ids: submittedIds }); expect(req.request.body).toEqual({ flags, ids: submittedIds }); expect(notificationType).toBe(NotificationType.success); - expect(component.activeModal.close).toHaveBeenCalledTimes(1); + expect(component.closeModal).toHaveBeenCalledTimes(1); }); it('should submit multiple flags for multiple OSDs', () => { @@ -316,7 +312,7 @@ describe('OsdFlagsIndivModalComponent', () => { req.flush({ flags, ids: submittedIds }); expect(req.request.body).toEqual({ flags, ids: submittedIds }); expect(notificationType).toBe(NotificationType.success); - expect(component.activeModal.close).toHaveBeenCalledTimes(1); + expect(component.closeModal).toHaveBeenCalledTimes(1); }); }); }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-flags-indiv-modal/osd-flags-indiv-modal.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-flags-indiv-modal/osd-flags-indiv-modal.component.ts index 63e1bc838969..819a5c614412 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-flags-indiv-modal/osd-flags-indiv-modal.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-flags-indiv-modal/osd-flags-indiv-modal.component.ts @@ -1,7 +1,7 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, Inject, OnInit, Optional } from '@angular/core'; import { UntypedFormGroup } from '@angular/forms'; -import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { CdForm } from '~/app/shared/forms/cd-form'; import _ from 'lodash'; import { OsdService } from '~/app/shared/api/osd.service'; @@ -18,9 +18,8 @@ import { NotificationService } from '~/app/shared/services/notification.service' styleUrls: ['./osd-flags-indiv-modal.component.scss'], standalone: false }) -export class OsdFlagsIndivModalComponent implements OnInit { +export class OsdFlagsIndivModalComponent extends CdForm implements OnInit { permissions: Permissions; - selected: object[]; initialSelection: Flag[] = []; osdFlagsForm = new UntypedFormGroup({}); flags: Flag[] = [ @@ -60,13 +59,15 @@ export class OsdFlagsIndivModalComponent implements OnInit { clusterWideTooltip: string = $localize`The flag has been enabled for the entire cluster.`; constructor( - public activeModal: NgbActiveModal, + @Optional() @Inject('selected') public selected: object[] = [], public actionLabels: ActionLabelsI18n, private authStorageService: AuthStorageService, private osdService: OsdService, private notificationService: NotificationService ) { + super(); this.permissions = this.authStorageService.getPermissions(); + this.selected = this.selected || []; } ngOnInit() { @@ -125,10 +126,10 @@ export class OsdFlagsIndivModalComponent implements OnInit { this.osdService.updateIndividualFlags(activeFlags, selectedIds).subscribe( () => { this.notificationService.show(NotificationType.success, $localize`Updated OSD Flags`); - this.activeModal.close(); + this.closeModal(); }, () => { - this.activeModal.close(); + this.closeModal(); } ); } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-list/osd-list.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-list/osd-list.component.ts index b16e7fea10d8..2ff19e44fe9f 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-list/osd-list.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-list/osd-list.component.ts @@ -502,7 +502,7 @@ export class OsdListComponent extends ListWithDetails implements OnInit { const initialState = { selected: this.getSelectedOsds() }; - this.bsModalRef = this.modalService.show(OsdFlagsIndivModalComponent, initialState); + this.bsModalRef = this.cdsModalService.show(OsdFlagsIndivModalComponent, initialState); } showConfirmationModal(markAction: string, onSubmit: (id: number) => Observable) { diff --git a/src/pybind/mgr/dashboard/frontend/src/styles/ceph-custom/_spacings.scss b/src/pybind/mgr/dashboard/frontend/src/styles/ceph-custom/_spacings.scss index cb29ca8e494c..7d3d0ff98212 100644 --- a/src/pybind/mgr/dashboard/frontend/src/styles/ceph-custom/_spacings.scss +++ b/src/pybind/mgr/dashboard/frontend/src/styles/ceph-custom/_spacings.scss @@ -26,6 +26,10 @@ margin: 0; } +.cds-m-1 { + margin: layout.$spacing-01; +} + .cds-mb-0 { margin-bottom: 0; } @@ -54,14 +58,18 @@ margin-bottom: layout.$spacing-06; } -.cds-mt-3 { - margin-top: layout.$spacing-03; -} - .cds-mt-1 { margin-top: layout.$spacing-01; } +.cds-mt-2 { + margin-top: layout.$spacing-02; +} + +.cds-mt-3 { + margin-top: layout.$spacing-03; +} + .cds-mt-4 { margin-top: layout.$spacing-04; } -- 2.47.3