From d4f3fba56e66a9316f2641f2f21196367c571db1 Mon Sep 17 00:00:00 2001 From: claire bontempo <68122737+hellobontempo@users.noreply.github.com> Date: Wed, 25 May 2022 11:22:36 -0700 Subject: [PATCH] UI/Fix form validation issues (#15560) * clean up validators * fix getter overriding user input * add changelog * remove asString option * move invalid check up * remove asString everywhere * revert input value defaults * undo form disabling if validation errors * address comments * remove or * add validation message to form, create pseudo loading icon * whole alert disappears with refresh * glimmerize alert-inline * add tests * rename variables for consistency * spread attributes to glimmerized component * address comments * add validation test --- changelog/15560.txt | 3 + ui/app/components/mount-backend-form.js | 23 ++++-- ui/app/decorators/model-validations.js | 12 ++- ui/app/models/secret-engine.js | 2 +- ui/app/models/secret-v2.js | 2 +- .../components/mount-backend-form.hbs | 7 +- ui/app/utils/validators.js | 22 +++--- ui/lib/core/addon/components/alert-inline.hbs | 19 +++++ ui/lib/core/addon/components/alert-inline.js | 65 ++++++++++------ ui/lib/core/addon/components/form-field.js | 2 +- .../templates/components/alert-inline.hbs | 8 -- .../components/alert-inline-test.js | 77 +++++++++++++++++-- .../unit/decorators/model-validations-test.js | 29 +++++++ ui/tests/unit/utils/validators-test.js | 44 ++++++++--- 14 files changed, 245 insertions(+), 70 deletions(-) create mode 100644 changelog/15560.txt create mode 100644 ui/lib/core/addon/components/alert-inline.hbs delete mode 100644 ui/lib/core/addon/templates/components/alert-inline.hbs diff --git a/changelog/15560.txt b/changelog/15560.txt new file mode 100644 index 000000000..387d2a848 --- /dev/null +++ b/changelog/15560.txt @@ -0,0 +1,3 @@ +```release-note:bug +ui: fix form validations ignoring default values and disabling submit button +``` diff --git a/ui/app/components/mount-backend-form.js b/ui/app/components/mount-backend-form.js index b23a7ffc5..263981141 100644 --- a/ui/app/components/mount-backend-form.js +++ b/ui/app/components/mount-backend-form.js @@ -47,7 +47,7 @@ export default Component.extend({ // validation related properties modelValidations: null, - isFormInvalid: false, + invalidFormAlert: null, mountIssue: false, @@ -88,10 +88,24 @@ export default Component.extend({ } }, + checkModelValidity(model) { + const { isValid, state, invalidFormMessage } = model.validate(); + this.setProperties({ + modelValidations: state, + invalidFormAlert: invalidFormMessage, + }); + + return isValid; + }, + mountBackend: task( waitFor(function* () { const mountModel = this.mountModel; const { type, path } = mountModel; + // only submit form if validations pass + if (!this.checkModelValidity(mountModel)) { + return; + } let capabilities = null; try { capabilities = yield this.store.findRecord('capabilities', `${path}/config`); @@ -120,7 +134,6 @@ export default Component.extend({ } catch (err) { if (err.httpStatus === 403) { this.mountIssue = true; - this.set('isFormInvalid', this.mountIssue); this.flashMessages.danger( 'You do not have access to the sys/mounts endpoint. The secret engine was not mounted.' ); @@ -163,12 +176,8 @@ export default Component.extend({ actions: { onKeyUp(name, value) { this.mountModel.set(name, value); - const { isValid, state } = this.mountModel.validate(); - this.setProperties({ - modelValidations: state, - isFormInvalid: !isValid, - }); }, + onTypeChange(path, value) { if (path === 'type') { this.wizard.set('componentState', value); diff --git a/ui/app/decorators/model-validations.js b/ui/app/decorators/model-validations.js index fae6e8f70..8520811da 100644 --- a/ui/app/decorators/model-validations.js +++ b/ui/app/decorators/model-validations.js @@ -69,6 +69,7 @@ export function withModelValidations(validations) { validate() { let isValid = true; const state = {}; + let errorCount = 0; for (const key in this._validations) { const rules = this._validations[key]; @@ -110,9 +111,18 @@ export function withModelValidations(validations) { } } } + errorCount += state[key].errors.length; state[key].isValid = !state[key].errors.length; } - return { isValid, state }; + + return { isValid, state, invalidFormMessage: this.generateErrorCountMessage(errorCount) }; + } + + generateErrorCountMessage(errorCount) { + if (errorCount < 1) return null; + // returns count specific message: 'There is an error/are N errors with this form.' + let isPlural = errorCount > 1 ? `are ${errorCount} errors` : false; + return `There ${isPlural ? isPlural : 'is an error'} with this form.`; } }; }; diff --git a/ui/app/models/secret-engine.js b/ui/app/models/secret-engine.js index a51983fd8..2fb064c37 100644 --- a/ui/app/models/secret-engine.js +++ b/ui/app/models/secret-engine.js @@ -12,7 +12,7 @@ const LIST_EXCLUDED_BACKENDS = ['system', 'identity']; const validations = { path: [{ type: 'presence', message: "Path can't be blank." }], maxVersions: [ - { type: 'number', options: { asString: true }, message: 'Maximum versions must be a number.' }, + { type: 'number', message: 'Maximum versions must be a number.' }, { type: 'length', options: { min: 1, max: 16 }, message: 'You cannot go over 16 characters.' }, ], }; diff --git a/ui/app/models/secret-v2.js b/ui/app/models/secret-v2.js index 1f95d6e3d..c4945fcce 100644 --- a/ui/app/models/secret-v2.js +++ b/ui/app/models/secret-v2.js @@ -8,7 +8,7 @@ import { withModelValidations } from 'vault/decorators/model-validations'; const validations = { maxVersions: [ - { type: 'number', options: { asString: true }, message: 'Maximum versions must be a number.' }, + { type: 'number', message: 'Maximum versions must be a number.' }, { type: 'length', options: { min: 1, max: 16 }, message: 'You cannot go over 16 characters.' }, ], }; diff --git a/ui/app/templates/components/mount-backend-form.hbs b/ui/app/templates/components/mount-backend-form.hbs index 10f2a8a47..4bc343cb7 100644 --- a/ui/app/templates/components/mount-backend-form.hbs +++ b/ui/app/templates/components/mount-backend-form.hbs @@ -67,7 +67,7 @@ type="submit" data-test-mount-submit="true" class="button is-primary {{if this.mountBackend.isRunning 'loading'}}" - disabled={{or this.mountBackend.isRunning this.isFormInvalid}} + disabled={{this.mountBackend.isRunning}} > {{#if (eq this.mountType "auth")}} Enable Method @@ -81,6 +81,11 @@ Back + {{#if this.invalidFormAlert}} +
+ +
+ {{/if}} {{else}}