mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-30 18:17:55 +00:00
UI: Namespace validation update (#22820)
This commit is contained in:
@@ -5,19 +5,23 @@
|
|||||||
|
|
||||||
import Model, { attr } from '@ember-data/model';
|
import Model, { attr } from '@ember-data/model';
|
||||||
import { withExpandedAttributes } from 'vault/decorators/model-expanded-attributes';
|
import { withExpandedAttributes } from 'vault/decorators/model-expanded-attributes';
|
||||||
|
import { withModelValidations } from 'vault/decorators/model-validations';
|
||||||
|
|
||||||
@withExpandedAttributes()
|
@withExpandedAttributes()
|
||||||
|
@withModelValidations({
|
||||||
|
path: [
|
||||||
|
{ type: 'presence', message: `Path can't be blank.` },
|
||||||
|
{ type: 'endsInSlash', message: `Path can't end in forward slash '/'.` },
|
||||||
|
{
|
||||||
|
type: 'containsWhiteSpace',
|
||||||
|
message: "Path can't contain whitespace.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
export default class NamespaceModel extends Model {
|
export default class NamespaceModel extends Model {
|
||||||
@attr('string', {
|
@attr('string')
|
||||||
validationAttr: 'pathIsValid',
|
|
||||||
invalidMessage: 'You have entered and invalid path please only include letters, numbers, -, ., and _.',
|
|
||||||
})
|
|
||||||
path;
|
path;
|
||||||
|
|
||||||
get pathIsValid() {
|
|
||||||
return this.path && this.path.match(/^[\w\d-.]+$/g);
|
|
||||||
}
|
|
||||||
|
|
||||||
get fields() {
|
get fields() {
|
||||||
return ['path'].map((f) => this.allByKey[f]);
|
return ['path'].map((f) => this.allByKey[f]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ export default Component.extend({
|
|||||||
layout,
|
layout,
|
||||||
flashMessages: service(),
|
flashMessages: service(),
|
||||||
|
|
||||||
|
// internal validations
|
||||||
|
invalidFormAlert: '',
|
||||||
|
modelValidations: null,
|
||||||
// public API
|
// public API
|
||||||
model: null,
|
model: null,
|
||||||
successMessage: 'Saved!',
|
successMessage: 'Saved!',
|
||||||
@@ -38,10 +41,25 @@ export default Component.extend({
|
|||||||
// is the case, set this value to true
|
// is the case, set this value to true
|
||||||
callOnSaveAfterRender: false,
|
callOnSaveAfterRender: false,
|
||||||
|
|
||||||
|
checkModelValidity(model) {
|
||||||
|
if (model.validate) {
|
||||||
|
const { isValid, state, invalidFormMessage } = model.validate();
|
||||||
|
this.set('modelValidations', state);
|
||||||
|
this.set('invalidFormAlert', invalidFormMessage);
|
||||||
|
return isValid;
|
||||||
|
}
|
||||||
|
// no validations on model; return true
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
save: task(
|
save: task(
|
||||||
waitFor(function* (model, options = { method: 'save' }) {
|
waitFor(function* (model, options = { method: 'save' }) {
|
||||||
const { method } = options;
|
const { method } = options;
|
||||||
const messageKey = method === 'save' ? 'successMessage' : 'deleteSuccessMessage';
|
const messageKey = method === 'save' ? 'successMessage' : 'deleteSuccessMessage';
|
||||||
|
if (method === 'save' && !this.checkModelValidity(model)) {
|
||||||
|
// if saving and model invalid, don't continue
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
yield model[method]();
|
yield model[method]();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@@ -281,12 +281,6 @@
|
|||||||
class="input {{if this.validationError 'has-error-border'}}"
|
class="input {{if this.validationError 'has-error-border'}}"
|
||||||
maxLength={{@attr.options.characterLimit}}
|
maxLength={{@attr.options.characterLimit}}
|
||||||
/>
|
/>
|
||||||
{{! TODO: explore removing in favor of new model validations pattern since it is only used on the namespace model }}
|
|
||||||
{{#if @attr.options.validationAttr}}
|
|
||||||
{{#if (and (get @model this.valuePath) (not (get @model @attr.options.validationAttr)))}}
|
|
||||||
<AlertInline @type="danger" @message={{@attr.options.invalidMessage}} />
|
|
||||||
{{/if}}
|
|
||||||
{{/if}}
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
{{else if (or (eq @attr.type "boolean") (eq @attr.options.editType "boolean"))}}
|
{{else if (or (eq @attr.type "boolean") (eq @attr.options.editType "boolean"))}}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
SPDX-License-Identifier: BUSL-1.1
|
SPDX-License-Identifier: BUSL-1.1
|
||||||
~}}
|
~}}
|
||||||
|
|
||||||
<div class="field is-grouped is-grouped-split is-fullwidth box is-bottomless {{if (eq @includeBox false) 'is-shadowless'}}">
|
<div class="field is-fullwidth box is-bottomless {{if (eq @includeBox false) 'is-shadowless'}}">
|
||||||
<div class="field is-grouped">
|
<div class="field is-grouped">
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<button
|
<button
|
||||||
@@ -24,10 +24,11 @@
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if @onCancel}}
|
{{#if @onCancel}}
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<button type="button" class="button" onclick={{action this.onCancel}} data-test-cancel-button>
|
<button type="button" class="button" onclick={{action @onCancel}} data-test-cancel-button>
|
||||||
{{or @cancelButtonText "Cancel"}}
|
{{or @cancelButtonText "Cancel"}}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
{{yield to="error"}}
|
||||||
</div>
|
</div>
|
||||||
@@ -3,18 +3,19 @@
|
|||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Component from '@ember/component';
|
import Component from '@glimmer/component';
|
||||||
import { computed } from '@ember/object';
|
|
||||||
import layout from '../templates/components/form-save-buttons';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @module FormSaveButtons
|
* @module FormSaveButtons
|
||||||
* `FormSaveButtons` displays a button save and a cancel button at the bottom of a form.
|
* `FormSaveButtons` displays a button save and a cancel button at the bottom of a form.
|
||||||
|
* To show an overall inline error message, use the :error yielded block like shown below.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* ```js
|
* ```js
|
||||||
* <FormSaveButtons @saveButtonText="Save" @isSaving={{isSaving}} @cancelLinkParams={{array
|
* <FormSaveButtons @saveButtonText="Save" @isSaving={{isSaving}} @cancelLinkParams={{array
|
||||||
* "foo.route"}} />
|
* "foo.route"}}>
|
||||||
|
* <:error>This is an error</:error>
|
||||||
|
* </FormSaveButtons>
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* @param [saveButtonText="Save" {String}] - The text that will be rendered on the Save button.
|
* @param [saveButtonText="Save" {String}] - The text that will be rendered on the Save button.
|
||||||
@@ -26,13 +27,11 @@ import layout from '../templates/components/form-save-buttons';
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default Component.extend({
|
export default class FormSaveButtons extends Component {
|
||||||
layout,
|
get cancelLink() {
|
||||||
tagName: '',
|
const { cancelLinkParams } = this.args;
|
||||||
|
if (!Array.isArray(cancelLinkParams) || !cancelLinkParams.length) return null;
|
||||||
cancelLink: computed('cancelLinkParams.[]', function () {
|
const [route, ...models] = cancelLinkParams;
|
||||||
if (!Array.isArray(this.cancelLinkParams) || !this.cancelLinkParams.length) return;
|
|
||||||
const [route, ...models] = this.cancelLinkParams;
|
|
||||||
return { route, models };
|
return { route, models };
|
||||||
}),
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@@ -9,17 +9,29 @@
|
|||||||
<NamespaceReminder @mode="save" />
|
<NamespaceReminder @mode="save" />
|
||||||
{{#if (or this.model.fields this.model.attrs)}}
|
{{#if (or this.model.fields this.model.attrs)}}
|
||||||
{{#each (or this.model.fields this.model.attrs) as |attr|}}
|
{{#each (or this.model.fields this.model.attrs) as |attr|}}
|
||||||
<FormField data-test-field @attr={{attr}} @model={{this.model}} @mode={{@mode}} />
|
<FormField
|
||||||
|
data-test-field
|
||||||
|
@attr={{attr}}
|
||||||
|
@model={{this.model}}
|
||||||
|
@mode={{@mode}}
|
||||||
|
@modelValidations={{this.modelValidations}}
|
||||||
|
/>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
{{else if this.model.fieldGroups}}
|
{{else if this.model.fieldGroups}}
|
||||||
<FormFieldGroups @model={{this.model}} @mode={{@mode}} />
|
<FormFieldGroups @model={{this.model}} @mode={{@mode}} @modelValidations={{this.modelValidations}} />
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
<FormSaveButtons
|
<FormSaveButtons
|
||||||
@isSaving={{this.save.isRunning}}
|
@isSaving={{this.save.isRunning}}
|
||||||
@saveButtonText={{this.saveButtonText}}
|
@saveButtonText={{this.saveButtonText}}
|
||||||
@canceLinkParams={{@canceLinkParams}}
|
@cancelLinkParams={{@cancelLinkParams}}
|
||||||
@includeBox={{this.includeBox}}
|
@includeBox={{this.includeBox}}
|
||||||
@onCancel={{@onCancel}}
|
@onCancel={{@onCancel}}
|
||||||
/>
|
>
|
||||||
|
<:error>
|
||||||
|
{{#if this.invalidFormAlert}}
|
||||||
|
<AlertInline @type="danger" @paddingTop={{true}} @message={{this.invalidFormAlert}} @mimicRefresh={{true}} />
|
||||||
|
{{/if}}
|
||||||
|
</:error>
|
||||||
|
</FormSaveButtons>
|
||||||
</form>
|
</form>
|
||||||
Reference in New Issue
Block a user