From 7f3a982d6f95d10a0d82ea2f462fc5259785813d Mon Sep 17 00:00:00 2001 From: Volker Theile Date: Wed, 5 Sep 2018 14:03:26 +0200 Subject: [PATCH] mgr/dashboard: Unable to edit user when making an accidental change to the password field Fixes: https://tracker.ceph.com/issues/35685 Signed-off-by: Volker Theile --- .../app/shared/forms/cd-validators.spec.ts | 32 +++++++++++++------ .../src/app/shared/forms/cd-validators.ts | 30 ++++++++++++----- 2 files changed, 45 insertions(+), 17 deletions(-) diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/forms/cd-validators.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/forms/cd-validators.spec.ts index 857800d9559..9cad1c0e691 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/forms/cd-validators.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/forms/cd-validators.spec.ts @@ -174,18 +174,19 @@ describe('CdValidators', () => { describe('match', () => { let form: FormGroup; + let x: FormControl; + let y: FormControl; beforeEach(() => { + x = new FormControl('aaa'); + y = new FormControl('aaa'); form = new FormGroup({ - x: new FormControl(), - y: new FormControl() + x: x, + y: y }); }); it('should error when values are different', () => { - const x = form.get('x'); - const y = form.get('y'); - x.setValue('aaa'); y.setValue('aab'); CdValidators.match('x', 'y')(form); expect(x.hasError('match')).toBeFalsy(); @@ -193,14 +194,27 @@ describe('CdValidators', () => { }); it('should not error when values are equal', () => { - const x = form.get('x'); - const y = form.get('y'); - x.setValue('aaa'); - y.setValue('aaa'); CdValidators.match('x', 'y')(form); expect(x.hasError('match')).toBeFalsy(); expect(y.hasError('match')).toBeFalsy(); }); + + it('should unset error when values are equal', () => { + y.setErrors({ match: true }); + CdValidators.match('x', 'y')(form); + expect(x.hasError('match')).toBeFalsy(); + expect(y.hasError('match')).toBeFalsy(); + expect(y.valid).toBeTruthy(); + }); + + it('should keep other existing errors', () => { + y.setErrors({ match: true, notUnique: true }); + CdValidators.match('x', 'y')(form); + expect(x.hasError('match')).toBeFalsy(); + expect(y.hasError('match')).toBeFalsy(); + expect(y.hasError('notUnique')).toBeTruthy(); + expect(y.valid).toBeFalsy(); + }); }); describe('unique', () => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/forms/cd-validators.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/forms/cd-validators.ts index f1480409cfb..ac1fe187f76 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/forms/cd-validators.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/forms/cd-validators.ts @@ -108,16 +108,30 @@ export class CdValidators { } /** - * Validate if control1 and control2 have the same value. - * Error will be added to control2. - * - * @param {string} control1 - * @param {string} control2 + * Validator that requires that both specified controls have the same value. + * Error will be added to the `path2` control. + * @param {string} path1 A dot-delimited string that define the path to the control. + * @param {string} path2 A dot-delimited string that define the path to the control. + * @return {ValidatorFn} Returns a validator function that always returns `null`. + * If the validation fails an error map with the `match` property will be set + * on the `path2` control. */ - static match(control1: string, control2: string): ValidatorFn { + static match(path1: string, path2: string): ValidatorFn { return (control: AbstractControl): { [key: string]: any } => { - if (control.get(control1).value !== control.get(control2).value) { - control.get(control2).setErrors({ ['match']: true }); + const ctrl1 = control.get(path1); + const ctrl2 = control.get(path2); + if (ctrl1.value !== ctrl2.value) { + ctrl2.setErrors({ match: true }); + } else { + const hasError = ctrl2.hasError('match'); + if (hasError) { + // Remove the 'match' error. If no more errors exists, then set + // the error value to 'null', otherwise the field is still marked + // as invalid. + const errors = ctrl2.errors; + _.unset(errors, 'match'); + ctrl2.setErrors(_.isEmpty(_.keys(errors)) ? null : errors); + } } return null; };