From: Sagar Gopale Date: Wed, 1 Apr 2026 11:01:52 +0000 (+0530) Subject: mgr/dashboard: fix delete subsystem issue X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=0ec21732353f93171c7721d514eb79e75d73edbd;p=ceph.git mgr/dashboard: fix delete subsystem issue Fixes: https://tracker.ceph.com/issues/75847 Signed-off-by: Sagar Gopale --- diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-subsystems/nvmeof-subsystems.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-subsystems/nvmeof-subsystems.component.html index fee4d1c0770b..e5ab87192df5 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-subsystems/nvmeof-subsystems.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-subsystems/nvmeof-subsystems.component.html @@ -91,4 +91,6 @@ + + diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-subsystems/nvmeof-subsystems.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-subsystems/nvmeof-subsystems.component.ts index 39b9c1b3b13a..71c954d34ae0 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-subsystems/nvmeof-subsystems.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-subsystems/nvmeof-subsystems.component.ts @@ -175,7 +175,8 @@ export class NvmeofSubsystemsComponent extends ListWithDetails implements OnInit itemNames: [subsystem.nqn], actionDescription: 'delete', bodyContext: { - deletionMessage: $localize`Deleting ${subsystem.nqn} will remove all associated configurations and resources. Dependent services may stop working. This action cannot be undone.` + deletionMessage: $localize`Deleting ${subsystem.nqn} will remove all associated configurations and resources. Dependent services may stop working. This action cannot be undone.`, + forceDeleteAcknowledgementMessage: $localize`I understand this may remove resources still attached to this subsystem.` }, submitActionObservable: () => this.taskWrapper.wrapTaskAroundCall({ diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/nvmeof.service.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/nvmeof.service.spec.ts index 4e670f455b7f..70c3da05eb4a 100755 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/nvmeof.service.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/nvmeof.service.spec.ts @@ -174,9 +174,13 @@ describe('NvmeofService', () => { it('should call deleteSubsystem', () => { service.deleteSubsystem(mockNQN, mockGroupName).subscribe(); - const req = httpTesting.expectOne( - `${API_PATH}/subsystem/${mockNQN}?gw_group=${mockGroupName}` - ); + const req = httpTesting.expectOne((request) => { + return ( + request.url === `${API_PATH}/subsystem/${mockNQN}` && + request.params.get('gw_group') === mockGroupName && + request.params.get('force') === 'true' + ); + }); expect(req.request.method).toBe('DELETE'); }); it('should call isSubsystemPresent', () => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/nvmeof.service.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/nvmeof.service.ts index 1cfdf54e656a..5d4573ab40f9 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/nvmeof.service.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/nvmeof.service.ts @@ -191,8 +191,12 @@ export class NvmeofService { } deleteSubsystem(subsystemNQN: string, group: string) { - return this.http.delete(`${API_PATH}/subsystem/${subsystemNQN}?gw_group=${group}`, { - observe: 'response' + return this.http.delete(`${API_PATH}/subsystem/${subsystemNQN}`, { + observe: 'response', + params: { + gw_group: group, + force: 'true' + } }); } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/delete-confirmation-modal/delete-confirmation-modal.component.html b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/delete-confirmation-modal/delete-confirmation-modal.component.html index 0682cac60bed..9a7c5b024680 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/delete-confirmation-modal/delete-confirmation-modal.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/delete-confirmation-modal/delete-confirmation-modal.component.html @@ -82,6 +82,16 @@ Enter the correct resource name. + @if (bodyContext?.forceDeleteAcknowledgementMessage) { +
+ + {{ bodyContext.forceDeleteAcknowledgementMessage }} + +
+ } @@ -92,7 +102,7 @@ [form]="deletionForm" [submitText]="(actionDescription | titlecase) + ' ' + itemDescription" [modalForm]="true" - [disabled]="(submitDisabled$ | async) || deletionForm.disabled || (impact === impactEnum.high ? !deletionForm.controls.confirmInput.value : !deletionForm.controls.confirmation.value)" + [disabled]="(submitDisabled$ | async) || deletionForm.disabled || (impact === impactEnum.high ? (!deletionForm.controls.confirmInput.value || !forceDeleteAckSatisfied) : !deletionForm.controls.confirmation.value)" [submitBtnType]="(actionDescription === 'delete' || actionDescription === 'remove') ? 'danger' : 'primary'"> diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/delete-confirmation-modal/delete-confirmation-modal.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/delete-confirmation-modal/delete-confirmation-modal.component.ts index 4b34d02a10ff..806ec57a826f 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/delete-confirmation-modal/delete-confirmation-modal.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/delete-confirmation-modal/delete-confirmation-modal.component.ts @@ -51,7 +51,7 @@ export class DeleteConfirmationModalComponent extends BaseModal implements OnIni } ngOnInit() { - const controls = { + const controls: Record = { impact: new UntypedFormControl(this.impact), confirmation: new UntypedFormControl(false, { validators: [ @@ -73,6 +73,13 @@ export class DeleteConfirmationModalComponent extends BaseModal implements OnIni }) }; + if ( + this.impact === this.impactEnum.high && + this.bodyContext?.forceDeleteAcknowledgementMessage + ) { + controls.forceDeleteAck = new UntypedFormControl(false, [Validators.requiredTrue]); + } + if (this.childFormGroup) { controls['child'] = this.childFormGroup; } @@ -96,6 +103,16 @@ export class DeleteConfirmationModalComponent extends BaseModal implements OnIni } } + get forceDeleteAckSatisfied(): boolean { + if ( + !(this.impact === this.impactEnum.high && this.bodyContext?.forceDeleteAcknowledgementMessage) + ) { + return true; + } + const c = this.deletionForm?.get('forceDeleteAck'); + return c ? !!c.value : true; + } + matchResourceName(control: AbstractControl): ValidationErrors | null { if (!control.value) { return null; diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/models/delete-confirmation.model.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/models/delete-confirmation.model.ts index 101a4bd049a6..7f4af3123ff9 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/models/delete-confirmation.model.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/models/delete-confirmation.model.ts @@ -4,4 +4,6 @@ export interface DeleteConfirmationBodyContext { inputLabel?: string; inputPlaceholder?: string; deletionMessage?: string; + /** When set on a high-impact delete, user must check an extra acknowledgement before submit. */ + forceDeleteAcknowledgementMessage?: string; }