Skip to content

Commit 4ebcd01

Browse files
authored
Merge pull request ceph#59820 from rhcs-dashboard/rgw-multisite-sync-policy-improvements
mgr/dashboard: multisite sync policy improvements Reviewed-by: afreen23 <NOT@FOUND> Reviewed-by: Nizamudeen A <[email protected]>
2 parents 6623566 + af437b4 commit 4ebcd01

File tree

7 files changed

+247
-102
lines changed

7 files changed

+247
-102
lines changed

src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-sync-flow-modal/rgw-multisite-sync-flow-modal.component.html

Lines changed: 90 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -2,109 +2,84 @@
22
<ng-container i18n="form title"
33
class="modal-title">{{ action | titlecase }} {{ groupType | upperFirst }} Flow</ng-container>
44

5-
<ng-container class="modal-content">
6-
<form name="flowForm"
7-
#frm="ngForm"
8-
[formGroup]="currentFormGroupContext"
9-
novalidate>
10-
<div class="modal-body">
5+
<ng-container class="modal-content">
6+
<form name="flowForm"
7+
#frm="ngForm"
8+
[formGroup]="currentFormGroupContext"
9+
novalidate>
10+
<div class="modal-body">
11+
<div class="form-group row">
12+
<label class="cd-col-form-label required"
13+
for="flow_id"
14+
i18n>Name</label>
15+
<div class="cd-col-form-input">
16+
<input class="form-control"
17+
type="text"
18+
placeholder="Flow Name..."
19+
id="flow_id"
20+
name="flow_id"
21+
formControlName="flow_id"/>
22+
</div>
23+
</div>
24+
<div class="form-group row">
25+
<label class="cd-col-form-label"
26+
for="bucket"
27+
i18n>Bucket Name</label>
28+
<div class="cd-col-form-input">
29+
<input id="bucket"
30+
name="bucket"
31+
class="form-control"
32+
type="text"
33+
i18n-placeholder
34+
placeholder="Bucket Name..."
35+
formControlName="bucket_name"/>
36+
<span class="invalid-feedback"
37+
*ngIf="currentFormGroupContext.showError('bucket_name', frm, 'bucketNameNotAllowed')"
38+
i18n>The bucket with chosen name does not exist.</span>
39+
</div>
40+
</div>
41+
<ng-container *ngIf="groupType == flowType.symmetrical; else directionalFlow">
1142
<div class="form-group row">
1243
<label class="cd-col-form-label required"
13-
for="flow_id"
14-
i18n>Name</label>
44+
for="zones">
45+
<ng-container i18n>Zones</ng-container>
46+
<cd-helper>
47+
<span i18n>Flow need to be associated with atleast one zone</span>
48+
</cd-helper>
49+
</label>
1550
<div class="cd-col-form-input">
16-
<input class="form-control"
17-
type="text"
18-
placeholder="Flow Name..."
19-
id="flow_id"
20-
name="flow_id"
21-
formControlName="flow_id"/>
51+
<ng-container *ngTemplateOutlet="zoneMultiSelect;context: { name: 'zones', zone: zones }"></ng-container>
2252
</div>
2353
</div>
54+
</ng-container>
55+
<ng-template #directionalFlow>
2456
<div class="form-group row">
25-
<label class="cd-col-form-label"
26-
for="bucket"
27-
i18n>Bucket Name</label>
57+
<label class="cd-col-form-label required"
58+
for="source_zone"
59+
i18n>Source Zone
60+
</label>
2861
<div class="cd-col-form-input">
29-
<input id="bucket"
30-
name="bucket"
31-
class="form-control"
32-
type="text"
33-
i18n-placeholder
34-
placeholder="Bucket Name..."
35-
formControlName="bucket_name"/>
36-
<span class="invalid-feedback"
37-
*ngIf="currentFormGroupContext.showError('bucket_name', frm, 'bucketNameNotAllowed')"
38-
i18n>The bucket with chosen name does not exist.</span>
62+
<ng-container *ngTemplateOutlet="sourceAndDestZone;context: { name: 'source_zone', zones: zones }"></ng-container>
3963
</div>
4064
</div>
41-
<ng-container *ngIf="groupType == flowType.symmetrical; else directionalFlow">
42-
<div class="form-group row">
43-
<label class="cd-col-form-label required"
44-
for="zones">
45-
<ng-container i18n>Zones</ng-container>
46-
<cd-helper>
47-
<span i18n>Flow need to be associated with atleast one zone</span>
48-
</cd-helper>
49-
</label>
50-
<div class="cd-col-form-input">
51-
<ng-container *ngTemplateOutlet="zoneMultiSelect;context: { name: 'zones', zone: zones }"></ng-container>
52-
</div>
53-
</div>
54-
</ng-container>
55-
<ng-template #directionalFlow>
56-
<div class="form-group row">
57-
<label class="cd-col-form-label required"
58-
for="source_zone"
59-
i18n>Source Zone
60-
</label>
61-
<div class="cd-col-form-input">
62-
<select id="sourceZone"
63-
name="sourceZone"
64-
class="form-select"
65-
formControlName="source_zone"
66-
[autofocus]="editing">
67-
<option i18n
68-
*ngIf="zones.data.available.length == 0"
69-
[ngValue]="null">Loading...</option>
70-
<option i18n
71-
*ngIf="zones.data.available.length > 0"
72-
[ngValue]="null">-- Select source zone --</option>
73-
<option *ngFor="let sourceZone of zones.data.available"
74-
[value]="sourceZone.name">{{ sourceZone.name }}</option>
75-
</select>
76-
<span class="invalid-feedback"
77-
*ngIf="currentFormGroupContext.showError('source_zone', frm, 'required')"
78-
i18n>This field is required.</span>
79-
</div>
80-
</div>
81-
<div class="form-group row">
82-
<label class="cd-col-form-label required"
83-
for="destination_zone"
84-
i18n>Destination Zone</label>
85-
<div class="cd-col-form-input">
86-
<input id="destination_zone"
87-
name="destination_zone"
88-
class="form-control"
89-
type="text"
90-
i18n-placeholder
91-
placeholder="Destination Zone..."
92-
formControlName="destination_zone"/>
93-
<span class="invalid-feedback"
94-
*ngIf="currentFormGroupContext.showError('destination_zone', frm, 'required')"
95-
i18n>This field is required.</span>
96-
</div>
65+
<div class="form-group row">
66+
<label class="cd-col-form-label required"
67+
for="destination_zone"
68+
i18n>Destination Zone</label>
69+
<div class="cd-col-form-input">
70+
<ng-container *ngTemplateOutlet="sourceAndDestZone;context: { name: 'destination_zone', zones: zones }"></ng-container>
9771
</div>
98-
</ng-template>
99-
</div>
100-
<div class="modal-footer">
101-
<cd-form-button-panel (submitActionEvent)="submit()"
102-
[form]="currentFormGroupContext"
103-
[submitText]="(action | titlecase) + ' ' + (groupType | upperFirst) + ' ' + 'Flow'"></cd-form-button-panel>
104-
</div>
105-
</form>
106-
</ng-container>
107-
</cd-modal>
72+
</div>
73+
</ng-template>
74+
</div>
75+
<div class="modal-footer">
76+
<cd-form-button-panel (submitActionEvent)="submit()"
77+
[form]="currentFormGroupContext"
78+
[submitText]="(action | titlecase) + ' ' + (groupType | upperFirst) + ' ' + 'Flow'"></cd-form-button-panel>
79+
</div>
80+
</form>
81+
</ng-container>
82+
</cd-modal>
10883

10984
<ng-template #zoneMultiSelect
11085
let-name="name"
@@ -128,3 +103,25 @@
128103
i18n>{{name?.split('_').join(' ')}} selection is required!
129104
</span>
130105
</ng-template>
106+
107+
<ng-template #sourceAndDestZone
108+
let-name="name"
109+
let-zones="zones">
110+
<select [id]="name"
111+
[name]="name"
112+
class="form-select"
113+
(change)="onChangeZoneDropdown(name, $event)"
114+
[autofocus]="editing">
115+
<option i18n
116+
*ngIf="zones.data.available.length == 0"
117+
[ngValue]="null">Loading...</option>
118+
<option i18n
119+
*ngIf="zones.data.available.length > 0"
120+
[ngValue]="null">-- Select {{name.split('_').join(' ')}} --</option>
121+
<option *ngFor="let destinationZone of zones.data.available"
122+
[value]="destinationZone.name">{{ destinationZone.name }}</option>
123+
</select>
124+
<span class="invalid-feedback"
125+
*ngIf="currentFormGroupContext.showError(name, frm, 'required')"
126+
i18n>This field is required.</span>
127+
</ng-template>

src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-sync-flow-modal/rgw-multisite-sync-flow-modal.component.spec.ts

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,22 @@ import { PipesModule } from '~/app/shared/pipes/pipes.module';
66
import { HttpClientTestingModule } from '@angular/common/http/testing';
77
import { ReactiveFormsModule } from '@angular/forms';
88
import { CommonModule } from '@angular/common';
9+
import { RgwMultisiteService } from '~/app/shared/api/rgw-multisite.service';
10+
import { of } from 'rxjs';
911

1012
enum FlowType {
1113
symmetrical = 'symmetrical',
1214
directional = 'directional'
1315
}
16+
17+
class MultisiteServiceMock {
18+
createEditSyncFlow = jest.fn().mockReturnValue(of(null));
19+
}
20+
1421
describe('RgwMultisiteSyncFlowModalComponent', () => {
1522
let component: RgwMultisiteSyncFlowModalComponent;
1623
let fixture: ComponentFixture<RgwMultisiteSyncFlowModalComponent>;
24+
let multisiteServiceMock: MultisiteServiceMock;
1725

1826
beforeEach(async () => {
1927
await TestBed.configureTestingModule({
@@ -25,10 +33,11 @@ describe('RgwMultisiteSyncFlowModalComponent', () => {
2533
ReactiveFormsModule,
2634
CommonModule
2735
],
28-
providers: [NgbActiveModal]
36+
providers: [NgbActiveModal, { provide: RgwMultisiteService, useClass: MultisiteServiceMock }]
2937
}).compileComponents();
3038

3139
fixture = TestBed.createComponent(RgwMultisiteSyncFlowModalComponent);
40+
multisiteServiceMock = (TestBed.inject(RgwMultisiteService) as unknown) as MultisiteServiceMock;
3241
component = fixture.componentInstance;
3342
component.groupType = FlowType.symmetrical;
3443
fixture.detectChanges();
@@ -37,4 +46,56 @@ describe('RgwMultisiteSyncFlowModalComponent', () => {
3746
it('should create', () => {
3847
expect(component).toBeTruthy();
3948
});
49+
50+
it('should assign zone value', () => {
51+
let zonesAdded: string[] = [];
52+
let selectedZone = ['zone2-zg1-realm1'];
53+
const spy = jest.spyOn(component, 'assignZoneValue').mockReturnValue(selectedZone);
54+
const res = component.assignZoneValue(zonesAdded, selectedZone);
55+
expect(spy).toHaveBeenCalled();
56+
expect(spy).toHaveBeenCalledWith(zonesAdded, selectedZone);
57+
expect(res).toEqual(selectedZone);
58+
});
59+
60+
it('should call createEditSyncFlow for creating/editing symmetrical sync flow', () => {
61+
component.editing = false;
62+
component.currentFormGroupContext.patchValue({
63+
flow_id: 'symmetrical',
64+
group_id: 'new',
65+
zones: { added: ['zone1-zg1-realm1'], removed: [] }
66+
});
67+
component.zones.data.selected = ['zone1-zg1-realm1'];
68+
const spy = jest.spyOn(component, 'submit');
69+
const putDataSpy = jest
70+
.spyOn(multisiteServiceMock, 'createEditSyncFlow')
71+
.mockReturnValue(of(null));
72+
component.submit();
73+
expect(spy).toHaveBeenCalled();
74+
expect(putDataSpy).toHaveBeenCalled();
75+
expect(putDataSpy).toHaveBeenCalledWith(component.currentFormGroupContext.getRawValue());
76+
});
77+
78+
it('should call createEditSyncFlow for creating/editing directional sync flow', () => {
79+
component.editing = false;
80+
component.groupType = FlowType.directional;
81+
component.ngOnInit();
82+
fixture.detectChanges();
83+
component.currentFormGroupContext.patchValue({
84+
flow_id: 'directional',
85+
group_id: 'new',
86+
source_zone: { added: ['zone1-zg1-realm1'], removed: [] },
87+
destination_zone: { added: ['zone2-zg1-realm1'], removed: [] }
88+
});
89+
const spy = jest.spyOn(component, 'submit');
90+
const putDataSpy = jest
91+
.spyOn(multisiteServiceMock, 'createEditSyncFlow')
92+
.mockReturnValue(of(null));
93+
component.submit();
94+
expect(spy).toHaveBeenCalled();
95+
expect(putDataSpy).toHaveBeenCalled();
96+
expect(putDataSpy).toHaveBeenCalledWith({
97+
...component.currentFormGroupContext.getRawValue(),
98+
zones: { added: [], removed: [] }
99+
});
100+
});
40101
});

src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-sync-flow-modal/rgw-multisite-sync-flow-modal.component.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,6 @@ export class RgwMultisiteSyncFlowModalComponent implements OnInit {
3535
flowType = FlowType;
3636
icons = Icons;
3737
zones = new ZoneData(false, 'Filter Zones');
38-
sourceZone: string;
39-
destinationZone: string;
4038

4139
constructor(
4240
public activeModal: NgbActiveModal,
@@ -122,6 +120,11 @@ export class RgwMultisiteSyncFlowModalComponent implements OnInit {
122120
});
123121
}
124122

123+
onChangeZoneDropdown(zoneType: string, event: Event) {
124+
const selectedVal = (event.target as HTMLSelectElement).value;
125+
this.currentFormGroupContext.get(zoneType).setValue(selectedVal);
126+
}
127+
125128
commonFormControls(flowType: FlowType) {
126129
return {
127130
bucket_name: new UntypedFormControl(this.groupExpandedRow?.bucket),

0 commit comments

Comments
 (0)