Backport of UI: Enable KV create secret with control group
Co-authored-by: Chelsea Shaw <82459713+hashishaw@users.noreply.github.com>
This commit is contained in:
parent
3359f987ac
commit
1dec6a7930
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:improvement
|
||||||
|
ui: enables create and update KV secret workflow when control group present
|
||||||
|
```
|
|
@ -17,6 +17,7 @@
|
||||||
* @isV2=true
|
* @isV2=true
|
||||||
* @secretData={{@secretData}}
|
* @secretData={{@secretData}}
|
||||||
* @canCreateSecretMetadata=false
|
* @canCreateSecretMetadata=false
|
||||||
|
* @buttonDisabled={{this.saving}}
|
||||||
* />
|
* />
|
||||||
* ```
|
* ```
|
||||||
* @param {string} mode - create, edit, show determines what view to display
|
* @param {string} mode - create, edit, show determines what view to display
|
||||||
|
@ -26,6 +27,7 @@
|
||||||
* @param {boolean} isV2 - whether or not KV1 or KV2
|
* @param {boolean} isV2 - whether or not KV1 or KV2
|
||||||
* @param {object} secretData - class that is created in secret-edit
|
* @param {object} secretData - class that is created in secret-edit
|
||||||
* @param {boolean} canUpdateSecretMetadata - based on permissions to the /metadata/ endpoint. If user has secret update. create is not enough for metadata.
|
* @param {boolean} canUpdateSecretMetadata - based on permissions to the /metadata/ endpoint. If user has secret update. create is not enough for metadata.
|
||||||
|
* @param {boolean} buttonDisabled - if true, disables the submit button on the create/update form
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Component from '@glimmer/component';
|
import Component from '@glimmer/component';
|
||||||
|
@ -51,6 +53,7 @@ export default class SecretCreateOrUpdate extends Component {
|
||||||
@tracked validationMessages = null;
|
@tracked validationMessages = null;
|
||||||
|
|
||||||
@service controlGroup;
|
@service controlGroup;
|
||||||
|
@service flashMessages;
|
||||||
@service router;
|
@service router;
|
||||||
@service store;
|
@service store;
|
||||||
|
|
||||||
|
@ -163,6 +166,7 @@ export default class SecretCreateOrUpdate extends Component {
|
||||||
if (error instanceof ControlGroupError) {
|
if (error instanceof ControlGroupError) {
|
||||||
const errorMessage = this.controlGroup.logFromError(error);
|
const errorMessage = this.controlGroup.logFromError(error);
|
||||||
this.error = errorMessage.content;
|
this.error = errorMessage.content;
|
||||||
|
this.controlGroup.saveTokenFromError(error);
|
||||||
}
|
}
|
||||||
throw error;
|
throw error;
|
||||||
});
|
});
|
||||||
|
@ -233,8 +237,13 @@ export default class SecretCreateOrUpdate extends Component {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const secretPath = type === 'create' ? this.args.modelForData.path : this.args.model.id;
|
||||||
this.persistKey(() => {
|
this.persistKey(() => {
|
||||||
this.transitionToRoute(SHOW_ROUTE, this.args.model.path || this.args.model.id);
|
// Show flash message in case there's a control group on read
|
||||||
|
this.flashMessages.success(
|
||||||
|
`Secret ${secretPath} ${type === 'create' ? 'created' : 'updated'} successfully.`
|
||||||
|
);
|
||||||
|
this.transitionToRoute(SHOW_ROUTE, secretPath);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@action
|
@action
|
||||||
|
|
|
@ -109,6 +109,17 @@ export default Service.extend({
|
||||||
return this.router.transitionTo('vault.cluster.access.control-group-accessor', accessor);
|
return this.router.transitionTo('vault.cluster.access.control-group-accessor', accessor);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Handle error from non-read request (eg. POST or UPDATE) so it can be retried
|
||||||
|
saveTokenFromError(error) {
|
||||||
|
const { accessor, token, creation_path, creation_time, ttl } = error;
|
||||||
|
const data = { accessor, token, creation_path, creation_time, ttl };
|
||||||
|
this.storeControlGroupToken(data);
|
||||||
|
// In the read flow the accessor is marked once the user clicks "Visit" from the control group page
|
||||||
|
// On a POST/UPDATE flow we don't redirect, so we need to mark automatically so that on the next try
|
||||||
|
// the request will attempt unwrap.
|
||||||
|
this.markTokenForUnwrap(accessor);
|
||||||
|
},
|
||||||
|
|
||||||
logFromError(error) {
|
logFromError(error) {
|
||||||
const { accessor, token, creation_path, creation_time, ttl } = error;
|
const { accessor, token, creation_path, creation_time, ttl } = error;
|
||||||
const data = { accessor, token, creation_path, creation_time, ttl };
|
const data = { accessor, token, creation_path, creation_time, ttl };
|
||||||
|
|
|
@ -133,12 +133,7 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<div class="field is-grouped box is-fullwidth is-bottomless">
|
<div class="field is-grouped box is-fullwidth is-bottomless">
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<button
|
<button type="submit" disabled={{@buttonDisabled}} class="button is-primary" data-test-secret-save={{true}}>
|
||||||
type="submit"
|
|
||||||
disabled={{or @buttonDisabled this.validationErrorCount this.error}}
|
|
||||||
class="button is-primary"
|
|
||||||
data-test-secret-save={{true}}
|
|
||||||
>
|
|
||||||
Save
|
Save
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -258,7 +258,7 @@ module('Acceptance | secrets/secret/create, read, delete', function (hooks) {
|
||||||
await deleteEngine(enginePath, assert);
|
await deleteEngine(enginePath, assert);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('it disables save when validation errors occur', async function (assert) {
|
test('it shows validation errors', async function (assert) {
|
||||||
assert.expect(5);
|
assert.expect(5);
|
||||||
const enginePath = `kv-secret-${this.uid}`;
|
const enginePath = `kv-secret-${this.uid}`;
|
||||||
const secretPath = 'not-duplicate';
|
const secretPath = 'not-duplicate';
|
||||||
|
@ -280,7 +280,7 @@ module('Acceptance | secrets/secret/create, read, delete', function (hooks) {
|
||||||
assert
|
assert
|
||||||
.dom('[data-test-input="maxVersions"]')
|
.dom('[data-test-input="maxVersions"]')
|
||||||
.hasClass('has-error-border', 'shows border error on input with error');
|
.hasClass('has-error-border', 'shows border error on input with error');
|
||||||
assert.dom('[data-test-secret-save]').isDisabled('Save button is disabled');
|
assert.dom('[data-test-secret-save]').isNotDisabled('Save button is disabled');
|
||||||
await fillIn('[data-test-input="maxVersions"]', 20); // fillIn replaces the text, whereas typeIn only adds to it.
|
await fillIn('[data-test-input="maxVersions"]', 20); // fillIn replaces the text, whereas typeIn only adds to it.
|
||||||
await triggerKeyEvent('[data-test-input="maxVersions"]', 'keyup', 65);
|
await triggerKeyEvent('[data-test-input="maxVersions"]', 'keyup', 65);
|
||||||
await editPage.path(secretPath);
|
await editPage.path(secretPath);
|
||||||
|
|
Loading…
Reference in New Issue