also the rename and rollback option in the snapshot list is enabled even if there isn't anything in the list
also disabled the Mirror Image Snapshot option in the Create RBD
Snapshot form (only shown for images configured with Snapshot mirroring)
with the helpe
Fixes: https://tracker.ceph.com/issues/61296
Signed-off-by: Nizamudeen A <nia@redhat.com>
autofocus>
<span class="invalid-feedback"
*ngIf="snapshotForm.showError('snapshotName', formDir, 'required')"
- i18n>This field is required.</span><br><br>
+ i18n>This field is required.</span>
<span *ngIf="((mirroring === 'snapshot') ? true : null) && (snapshotForm.getValue('mirrorImageSnapshot') === true) ? true: null"
i18n>Snapshot mode is enabled on image <b>{{ imageName }}</b>: snapshot names are auto generated</span>
</div>
</div>
- <div *ngIf="(mirroring === 'snapshot') ? true : null">
- <div class="form-group row">
+ <ng-container *ngIf="(mirroring === 'snapshot') ? true : null">
+ <div class="form-group row"
+ *ngIf="peerConfigured$ | async as peerConfigured">
<div class="cd-col-form-offset">
<div class="custom-control custom-checkbox">
<input type="checkbox"
formControlName="mirrorImageSnapshot"
name="mirrorImageSnapshot"
id="mirrorImageSnapshot"
+ [attr.disabled]="!(peerConfigured.length > 0) ? true : null"
(change)="onMirrorCheckBoxChange()">
<label for="mirrorImageSnapshot"
class="custom-control-label"
i18n>Mirror Image Snapshot</label>
+ <cd-helper i18n
+ *ngIf="!peerConfigured.length > 0">The peer must be registered to do this action.</cd-helper>
</div>
</div>
</div>
- </div>
+ </ng-container>
</div>
<div class="modal-footer">
<cd-form-button-panel (submitActionEvent)="submit()"
import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
import { configureTestBed } from '~/testing/unit-test-helper';
import { RbdSnapshotFormModalComponent } from './rbd-snapshot-form-modal.component';
+import { RbdMirroringService } from '~/app/shared/api/rbd-mirroring.service';
+import { of } from 'rxjs';
describe('RbdSnapshotFormModalComponent', () => {
let component: RbdSnapshotFormModalComponent;
let fixture: ComponentFixture<RbdSnapshotFormModalComponent>;
+ let rbdMirrorService: RbdMirroringService;
configureTestBed({
imports: [
beforeEach(() => {
fixture = TestBed.createComponent(RbdSnapshotFormModalComponent);
component = fixture.componentInstance;
+ rbdMirrorService = TestBed.inject(RbdMirroringService);
});
it('should create', () => {
const button = fixture.debugElement.nativeElement.querySelector('cd-submit-button');
expect(button.textContent).toBe('Rename RBD Snapshot');
});
+
+ it('should enable the mirror image snapshot creation when peer is configured', () => {
+ spyOn(rbdMirrorService, 'getPeerForPool').and.returnValue(of(['test_peer']));
+ component.mirroring = 'snapshot';
+ component.ngOnInit();
+ fixture.detectChanges();
+ const radio = fixture.debugElement.nativeElement.querySelector('#mirrorImageSnapshot');
+ expect(radio.disabled).toBe(false);
+ });
+
+ it('should disable the mirror image snapshot creation when peer is not configured', () => {
+ spyOn(rbdMirrorService, 'getPeerForPool').and.returnValue(of([]));
+ component.mirroring = 'snapshot';
+ component.ngOnInit();
+ fixture.detectChanges();
+ const radio = fixture.debugElement.nativeElement.querySelector('#mirrorImageSnapshot');
+ expect(radio.disabled).toBe(true);
+ });
});
-import { Component } from '@angular/core';
+import { Component, OnInit } from '@angular/core';
import { FormControl, Validators } from '@angular/forms';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
-import { Subject } from 'rxjs';
+import { Observable, Subject } from 'rxjs';
+import { RbdMirroringService } from '~/app/shared/api/rbd-mirroring.service';
import { RbdService } from '~/app/shared/api/rbd.service';
import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
templateUrl: './rbd-snapshot-form-modal.component.html',
styleUrls: ['./rbd-snapshot-form-modal.component.scss']
})
-export class RbdSnapshotFormModalComponent {
+export class RbdSnapshotFormModalComponent implements OnInit {
poolName: string;
namespace: string;
imageName: string;
public onSubmit: Subject<string> = new Subject();
+ peerConfigured$: Observable<any>;
+
constructor(
public activeModal: NgbActiveModal,
private rbdService: RbdService,
private taskManagerService: TaskManagerService,
private notificationService: NotificationService,
- private actionLabels: ActionLabelsI18n
+ private actionLabels: ActionLabelsI18n,
+ private rbdMirrorService: RbdMirroringService
) {
this.action = this.actionLabels.CREATE;
this.resource = $localize`RBD Snapshot`;
});
}
+ ngOnInit(): void {
+ this.peerConfigured$ = this.rbdMirrorService.getPeerForPool(this.poolName);
+ }
+
setSnapName(snapName: string) {
this.snapName = snapName;
- if (this.mirroring !== 'snapshot') {
- this.snapshotForm.get('snapshotName').setValue(snapName);
- } else {
- this.snapshotForm.get('snapshotName').clearValidators();
- }
+ this.snapshotForm.get('snapshotName').setValue(snapName);
}
onMirrorCheckBoxChange() {
if (this.snapshotForm.getValue('mirrorImageSnapshot') === true) {
this.snapshotForm.get('snapshotName').setValue('');
+ this.snapshotForm.get('snapshotName').clearValidators();
+ } else {
+ this.snapshotForm.get('snapshotName').setValue(this.snapName);
+ this.snapshotForm.get('snapshotName').setValidators([Validators.required]);
}
}
permission: 'update',
icon: Icons.edit,
name: actionLabels.RENAME,
- disable: (selection: CdTableSelection) => this.disableForMirrorSnapshot(selection)
+ disable: (selection: CdTableSelection) =>
+ this.disableForMirrorSnapshot(selection) || !selection.hasSingleSelection
};
this.protect = {
permission: 'update',
permission: 'update',
icon: Icons.undo,
name: actionLabels.ROLLBACK,
- disable: (selection: CdTableSelection) => this.disableForMirrorSnapshot(selection)
+ disable: (selection: CdTableSelection) =>
+ this.disableForMirrorSnapshot(selection) || !selection.hasSingleSelection
};
this.deleteSnap = {
permission: 'delete',
import { MockComponent } from 'ng-mocks';
import { ToastrModule } from 'ngx-toastr';
import { Subject, throwError as observableThrowError } from 'rxjs';
-import { RbdMirroringService } from '~/app/shared/api/rbd-mirroring.service';
import { RbdService } from '~/app/shared/api/rbd.service';
import { ComponentsModule } from '~/app/shared/components/components.module';
describe('api delete request', () => {
let called: boolean;
let rbdService: RbdService;
- let rbdMirroringService: RbdMirroringService;
let notificationService: NotificationService;
let authStorageService: AuthStorageService;
const modalService = TestBed.inject(ModalService);
const actionLabelsI18n = TestBed.inject(ActionLabelsI18n);
called = false;
- rbdMirroringService = new RbdMirroringService(null, null);
rbdService = new RbdService(null, null);
notificationService = new NotificationService(null, null, null);
authStorageService = new AuthStorageService();
null,
null,
rbdService,
- rbdMirroringService,
null,
notificationService,
null,
null,
null,
null,
- TestBed.inject(ActionLabelsI18n)
+ TestBed.inject(ActionLabelsI18n),
+ null
);
ref.componentInstance.onSubmit = new Subject();
return ref;
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
import moment from 'moment';
import { of } from 'rxjs';
-import { RbdMirroringService } from '~/app/shared/api/rbd-mirroring.service';
import { RbdService } from '~/app/shared/api/rbd.service';
import { CdHelperClass } from '~/app/shared/classes/cd-helper.class';
modalRef: NgbModalRef;
- peerConfigured = false;
-
builders = {
'rbd/snap/create': (metadata: any) => {
const model = new RbdSnapshotModel();
private dimlessBinaryPipe: DimlessBinaryPipe,
private cdDatePipe: CdDatePipe,
private rbdService: RbdService,
- private rbdMirrorService: RbdMirroringService,
private taskManagerService: TaskManagerService,
private notificationService: NotificationService,
private summaryService: SummaryService,
}
];
- this.rbdMirrorService.getPeerForPool(this.poolName).subscribe((resp: any) => {
- if (resp.length > 0) {
- this.peerConfigured = true;
- }
- });
-
this.imageSpec = new ImageSpec(this.poolName, this.namespace, this.rbdName);
this.rbdTableActions = new RbdSnapshotActionsModel(
this.actionLabels,
this.featuresName,
this.rbdService
);
- this.rbdTableActions.create.disable = () =>
- !this.primary || (!this.peerConfigured && this.mirroring === 'snapshot');
this.rbdTableActions.create.click = () => this.openCreateSnapshotModal();
this.rbdTableActions.rename.click = () => this.openEditSnapshotModal();
this.rbdTableActions.protect.click = () => this.toggleProtection();