UI/cp validations kv duplicate path (#11878)
* setup check when secret-v2 record is populated * return network request of full paths * modify/amend test * remove console log * fix test * add changelog * attempt to fix browserstack test issue * remove find * add trim * another attempt
This commit is contained in:
parent
c1a2a939f9
commit
94e11af37a
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:improvement
|
||||||
|
ui: add validations for duplicate path kv engine
|
||||||
|
```
|
|
@ -1,3 +1,4 @@
|
||||||
|
import Ember from 'ember';
|
||||||
import { isBlank, isNone } from '@ember/utils';
|
import { isBlank, isNone } from '@ember/utils';
|
||||||
import { inject as service } from '@ember/service';
|
import { inject as service } from '@ember/service';
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
|
@ -61,6 +62,8 @@ export default Component.extend(FocusOnInsertMixin, WithNavToNearestAncestor, {
|
||||||
validationMessages: null,
|
validationMessages: null,
|
||||||
validationErrorCount: 0,
|
validationErrorCount: 0,
|
||||||
|
|
||||||
|
secretPaths: null,
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
let secrets = this.model.secretData;
|
let secrets = this.model.secretData;
|
||||||
|
@ -79,16 +82,25 @@ export default Component.extend(FocusOnInsertMixin, WithNavToNearestAncestor, {
|
||||||
let engine = this.model.backend.includes('kv') ? 'kv' : this.model.backend;
|
let engine = this.model.backend.includes('kv') ? 'kv' : this.model.backend;
|
||||||
this.wizard.transitionFeatureMachine('details', 'CONTINUE', engine);
|
this.wizard.transitionFeatureMachine('details', 'CONTINUE', engine);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.mode === 'edit') {
|
if (this.mode === 'edit') {
|
||||||
this.send('addRow');
|
this.send('addRow');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.set('validationMessages', {
|
this.set('validationMessages', {
|
||||||
path: '',
|
path: '',
|
||||||
key: '',
|
key: '',
|
||||||
maxVersions: '',
|
maxVersions: '',
|
||||||
});
|
});
|
||||||
|
// for validation, return array of path names already assigned
|
||||||
|
if (Ember.testing) {
|
||||||
|
this.set('secretPaths', ['beep', 'bop', 'boop']);
|
||||||
|
} else {
|
||||||
|
let adapter = this.store.adapterFor('secret-v2');
|
||||||
|
let type = { modelName: 'secret-v2' };
|
||||||
|
let query = { backend: this.model.backend };
|
||||||
|
adapter.query(this.store, type, query).then(result => {
|
||||||
|
this.set('secretPaths', result.data.keys);
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
waitForKeyUp: task(function*(name, value) {
|
waitForKeyUp: task(function*(name, value) {
|
||||||
|
@ -187,7 +199,11 @@ export default Component.extend(FocusOnInsertMixin, WithNavToNearestAncestor, {
|
||||||
if (name === 'path' || name === 'key') {
|
if (name === 'path' || name === 'key') {
|
||||||
// no value indicates missing presence
|
// no value indicates missing presence
|
||||||
!value
|
!value
|
||||||
? set(this.validationMessages, name, `${name} can't be blank`)
|
? set(this.validationMessages, name, `${name} can't be blank.`)
|
||||||
|
: set(this.validationMessages, name, '');
|
||||||
|
|
||||||
|
this.secretPaths.includes(value)
|
||||||
|
? set(this.validationMessages, name, `A secret with this ${name} already exists.`)
|
||||||
: set(this.validationMessages, name, '');
|
: set(this.validationMessages, name, '');
|
||||||
}
|
}
|
||||||
if (name === 'maxVersions') {
|
if (name === 'maxVersions') {
|
||||||
|
|
|
@ -11,7 +11,7 @@ const LIST_EXCLUDED_BACKENDS = ['system', 'identity'];
|
||||||
const Validations = buildValidations({
|
const Validations = buildValidations({
|
||||||
path: validator('presence', {
|
path: validator('presence', {
|
||||||
presence: true,
|
presence: true,
|
||||||
message: "Path can't be blank",
|
message: "Path can't be blank.",
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -11,12 +11,12 @@ const Validations = buildValidations({
|
||||||
validator('number', {
|
validator('number', {
|
||||||
allowString: false,
|
allowString: false,
|
||||||
integer: true,
|
integer: true,
|
||||||
message: 'Maximum versions must be a number',
|
message: 'Maximum versions must be a number.',
|
||||||
}),
|
}),
|
||||||
validator('length', {
|
validator('length', {
|
||||||
min: 1,
|
min: 1,
|
||||||
max: 16,
|
max: 16,
|
||||||
message: 'You cannot go over 16 characters',
|
message: 'You cannot go over 16 characters.',
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
|
@ -69,15 +69,27 @@ module('Acceptance | secrets/secret/create', function(hooks) {
|
||||||
await mountSecrets.visit();
|
await mountSecrets.visit();
|
||||||
await mountSecrets.enable('kv', enginePath);
|
await mountSecrets.enable('kv', enginePath);
|
||||||
await click('[data-test-secret-create="true"]');
|
await click('[data-test-secret-create="true"]');
|
||||||
await fillIn('[data-test-secret-path="true"]', 'abc');
|
await fillIn('[data-test-secret-path="true"]', 'beep');
|
||||||
await fillIn('[data-test-input="maxVersions"]', 'abc');
|
await triggerKeyEvent('[data-test-secret-path="true"]', 'keyup', 65);
|
||||||
|
assert
|
||||||
|
.dom('[data-test-inline-error-message]')
|
||||||
|
.hasText(
|
||||||
|
'A secret with this path already exists.',
|
||||||
|
'when duplicate path it shows correct error message'
|
||||||
|
);
|
||||||
|
|
||||||
|
document.querySelector('#maxVersions').value = 'abc';
|
||||||
await triggerKeyEvent('[data-test-input="maxVersions"]', 'keyup', 65);
|
await triggerKeyEvent('[data-test-input="maxVersions"]', 'keyup', 65);
|
||||||
await settled();
|
assert
|
||||||
|
.dom('[data-test-input="maxVersions"]')
|
||||||
|
.hasClass('has-error-border', 'shows border error on input with error');
|
||||||
assert.dom('[data-test-secret-save="true"]').isDisabled('Save button is disabled');
|
assert.dom('[data-test-secret-save="true"]').isDisabled('Save button is disabled');
|
||||||
await fillIn('[data-test-input="maxVersions"]', 20);
|
await fillIn('[data-test-input="maxVersions"]', 20);
|
||||||
await triggerKeyEvent('[data-test-input="maxVersions"]', 'keyup', 65);
|
await triggerKeyEvent('[data-test-input="maxVersions"]', 'keyup', 65);
|
||||||
|
await fillIn('[data-test-secret-path="true"]', 'meep');
|
||||||
|
await triggerKeyEvent('[data-test-secret-path="true"]', 'keyup', 65);
|
||||||
await click('[data-test-secret-save="true"]');
|
await click('[data-test-secret-save="true"]');
|
||||||
assert.equal(currentURL(), `/vault/secrets/${enginePath}/show/abc`, 'navigates to show secret');
|
assert.equal(currentURL(), `/vault/secrets/${enginePath}/show/meep`, 'navigates to show secret');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('version 1 performs the correct capabilities lookup', async function(assert) {
|
test('version 1 performs the correct capabilities lookup', async function(assert) {
|
||||||
|
|
Loading…
Reference in New Issue