Skip to content

Commit fda9531

Browse files
authored
Merge pull request ceph#57698 from rhcs-dashboard/due-timer-validate
mgr/dashboard: add dueTime to rgw bucket validator Reviewed-by: Pedro Gonzalez Gomez <[email protected]>
2 parents 1f5d6d1 + c053782 commit fda9531

File tree

5 files changed

+38
-24
lines changed

5 files changed

+38
-24
lines changed

src/pybind/mgr/dashboard/frontend/cypress/e2e/rgw/buckets.po.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { PageHelper } from '../page-helper.po';
22

3+
const WAIT_TIMER = 500;
34
const pages = {
45
index: { url: '#/rgw/bucket', id: 'cd-rgw-bucket-list' },
56
create: { url: '#/rgw/bucket/create', id: 'cd-rgw-bucket-form' }
@@ -44,7 +45,7 @@ export class BucketsPageHelper extends PageHelper {
4445
}
4546

4647
// Click the create button and wait for bucket to be made
47-
cy.contains('button', 'Create Bucket').click();
48+
cy.contains('button', 'Create Bucket').wait(WAIT_TIMER).click();
4849

4950
this.getFirstTableCell(name).should('exist');
5051
}
@@ -119,7 +120,7 @@ export class BucketsPageHelper extends PageHelper {
119120

120121
cy.get('label[for=versioning]').click();
121122
cy.get('input[id=versioning]').should('not.be.checked');
122-
cy.contains('button', 'Edit Bucket').click();
123+
cy.contains('button', 'Edit Bucket').wait(WAIT_TIMER).click();
123124

124125
// Check versioning suspended:
125126
this.getExpandCollapseElement(name).click();
@@ -134,7 +135,7 @@ export class BucketsPageHelper extends PageHelper {
134135
// Gives an invalid name (too short), then waits for dashboard to determine validity
135136
cy.get('@nameInputField').type('rq');
136137

137-
cy.contains('button', 'Create Bucket').click(); // To trigger a validation
138+
cy.contains('button', 'Create Bucket').wait(WAIT_TIMER).click(); // To trigger a validation
138139

139140
// Waiting for website to decide if name is valid or not
140141
// Check that name input field was marked invalid in the css
@@ -166,7 +167,7 @@ export class BucketsPageHelper extends PageHelper {
166167

167168
// Clicks the Create Bucket button but the page doesn't move.
168169
// Done by testing for the breadcrumb
169-
cy.contains('button', 'Create Bucket').click(); // Clicks Create Bucket button
170+
cy.contains('button', 'Create Bucket').wait(WAIT_TIMER).click(); // Clicks Create Bucket button
170171
this.expectBreadcrumbText('Create');
171172
// content in fields seems to subsist through tests if not cleared, so it is cleared
172173
cy.get('@nameInputField').clear();

src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-form/rgw-bucket-form.component.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -285,14 +285,22 @@ export class RgwBucketFormComponent extends CdForm implements OnInit, AfterViewC
285285

286286
submit() {
287287
// Exit immediately if the form isn't dirty.
288-
if (this.bucketForm.getValue('encryption_enabled') == null) {
289-
this.bucketForm.get('encryption_enabled').setValue(false);
290-
this.bucketForm.get('encryption_type').setValue(null);
291-
}
292288
if (this.bucketForm.pristine) {
293289
this.goToListView();
294290
return;
295291
}
292+
293+
// Ensure that no validation is pending
294+
if (this.bucketForm.pending) {
295+
this.bucketForm.setErrors({ cdSubmitButton: true });
296+
return;
297+
}
298+
299+
if (this.bucketForm.getValue('encryption_enabled') == null) {
300+
this.bucketForm.get('encryption_enabled').setValue(false);
301+
this.bucketForm.get('encryption_type').setValue(null);
302+
}
303+
296304
const values = this.bucketForm.value;
297305
const xmlStrTags = this.tagsToXML(this.tags);
298306
const bucketPolicy = this.getBucketPolicy();

src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-form/rgw-user-form.component.spec.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { RgwUserCapabilities } from '../models/rgw-user-capabilities';
1818
import { RgwUserCapability } from '../models/rgw-user-capability';
1919
import { RgwUserS3Key } from '../models/rgw-user-s3-key';
2020
import { RgwUserFormComponent } from './rgw-user-form.component';
21+
import { DUE_TIMER } from '~/app/shared/forms/cd-validators';
2122

2223
describe('RgwUserFormComponent', () => {
2324
let component: RgwUserFormComponent;
@@ -162,14 +163,14 @@ describe('RgwUserFormComponent', () => {
162163
it('should validate that username is valid', fakeAsync(() => {
163164
spyOn(rgwUserService, 'get').and.returnValue(throwError('foo'));
164165
formHelper.setValue('user_id', 'ab', true);
165-
tick();
166+
tick(DUE_TIMER);
166167
formHelper.expectValid('user_id');
167168
}));
168169

169170
it('should validate that username is invalid', fakeAsync(() => {
170171
spyOn(rgwUserService, 'get').and.returnValue(observableOf({}));
171172
formHelper.setValue('user_id', 'abc', true);
172-
tick();
173+
tick(DUE_TIMER);
173174
formHelper.expectError('user_id', 'notUnique');
174175
}));
175176
});

src/pybind/mgr/dashboard/frontend/src/app/shared/forms/cd-validators.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { of as observableOf } from 'rxjs';
66

77
import { RgwBucketService } from '~/app/shared/api/rgw-bucket.service';
88
import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
9-
import { CdValidators } from '~/app/shared/forms/cd-validators';
9+
import { CdValidators, DUE_TIMER } from '~/app/shared/forms/cd-validators';
1010
import { FormHelper } from '~/testing/unit-test-helper';
1111

1212
let mockBucketExists = observableOf(true);
@@ -771,7 +771,7 @@ describe('CdValidators', () => {
771771
describe('bucket', () => {
772772
const testValidator = (name: string, valid: boolean, expectedError?: string) => {
773773
formHelper.setValue('x', name, true);
774-
tick();
774+
tick(DUE_TIMER);
775775
if (valid) {
776776
formHelper.expectValid('x');
777777
} else {

src/pybind/mgr/dashboard/frontend/src/app/shared/forms/cd-validators.ts

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ export function isEmptyInputValue(value: any): boolean {
2020

2121
export type existsServiceFn = (value: any, ...args: any[]) => Observable<boolean>;
2222

23+
export const DUE_TIMER = 500;
24+
2325
export class CdValidators {
2426
/**
2527
* Validator that performs email validation. In contrast to the Angular
@@ -347,9 +349,12 @@ export class CdValidators {
347349
* boolean 'true' if the given value exists, otherwise 'false'.
348350
* @param serviceFnThis {any} The object to be used as the 'this' object
349351
* when calling the serviceFn function. Defaults to null.
350-
* @param {number|Date} dueTime The delay time to wait before the
351-
* serviceFn call is executed. This is useful to prevent calls on
352-
* every keystroke. Defaults to 500.
352+
* @param usernameFn {Function} Specifically used in rgw user form to
353+
* validate the tenant$username format
354+
* @param uidField {boolean} Specifically used in rgw user form to
355+
* validate the tenant$username format
356+
* @param extraArgs {...any} Any extra arguments that need to be passed
357+
* to the serviceFn function.
353358
* @return {AsyncValidatorFn} Returns an asynchronous validator function
354359
* that returns an error map with the `notUnique` property if the
355360
* validation check succeeds, otherwise `null`.
@@ -377,7 +382,7 @@ export class CdValidators {
377382
}
378383
}
379384

380-
return observableTimer().pipe(
385+
return observableTimer(DUE_TIMER).pipe(
381386
switchMapTo(serviceFn.call(serviceFnThis, uName, ...extraArgs)),
382387
map((resp: boolean) => {
383388
if (!resp) {
@@ -480,7 +485,7 @@ export class CdValidators {
480485
if (_.isFunction(usernameFn)) {
481486
username = usernameFn();
482487
}
483-
return observableTimer(500).pipe(
488+
return observableTimer(DUE_TIMER).pipe(
484489
switchMapTo(_.invoke(userServiceThis, 'validatePassword', control.value, username)),
485490
map((resp: { valid: boolean; credits: number; valuation: string }) => {
486491
if (_.isFunction(callback)) {
@@ -601,13 +606,12 @@ export class CdValidators {
601606
if (control.pristine || !control.value) {
602607
return observableOf({ required: true });
603608
}
604-
return rgwBucketService
605-
.exists(control.value)
606-
.pipe(
607-
map((existenceResult: boolean) =>
608-
existenceResult === requiredExistenceResult ? null : { bucketNameNotAllowed: true }
609-
)
610-
);
609+
return observableTimer(DUE_TIMER).pipe(
610+
switchMapTo(rgwBucketService.exists(control.value)),
611+
map((existenceResult: boolean) =>
612+
existenceResult === requiredExistenceResult ? null : { bucketNameNotAllowed: true }
613+
)
614+
);
611615
};
612616
}
613617

0 commit comments

Comments
 (0)