UI: VAULT-13341 add toggle and select to pki role-form (#19840)
This commit is contained in:
parent
3ed31ff262
commit
985b016da5
|
@ -1,6 +1,8 @@
|
|||
<div class="field">
|
||||
<p class="control has-icons-left has-icons-right">
|
||||
<span class="input has-text-grey-light">{{or @placeholder "Search"}}</span>
|
||||
<Icon @name="search" class="search-icon has-text-grey-light" />
|
||||
</p>
|
||||
<div>
|
||||
<div class="field">
|
||||
<p class="control has-icons-left has-icons-right">
|
||||
<span class="input has-text-grey-light">{{or @placeholder "Search"}}</span>
|
||||
<Icon @name="search" class="search-icon has-text-grey-light" />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
|
@ -2,35 +2,70 @@
|
|||
<div class="box is-sideless is-fullwidth is-marginless">
|
||||
<MessageError @errorMessage={{this.errorBanner}} class="has-top-margin-s" />
|
||||
{{! ARG TODO write a test for namespace reminder }}
|
||||
<NamespaceReminder @mode={{if @model.isNew "create" "update"}} @noun="PKI role" />
|
||||
{{#each @model.formFieldGroups as |fieldGroup|}}
|
||||
<NamespaceReminder @mode={{if @role.isNew "create" "update"}} @noun="PKI role" />
|
||||
{{#each @role.formFieldGroups as |fieldGroup|}}
|
||||
{{#each-in fieldGroup as |group fields|}}
|
||||
{{! DEFAULT VIEW }}
|
||||
{{#if (eq group "default")}}
|
||||
{{#each fields as |attr|}}
|
||||
<FormField
|
||||
data-test-field={{attr}}
|
||||
@attr={{attr}}
|
||||
@model={{@model}}
|
||||
@modelValidations={{this.modelValidations}}
|
||||
@showHelpText={{false}}
|
||||
>
|
||||
<PkiNotValidAfterForm @attr={{attr}} @model={{@model}} />
|
||||
</FormField>
|
||||
{{#if (eq attr.name "issuerRef")}}
|
||||
<div class="has-top-margin-m {{unless this.showDefaultIssuer 'has-bottom-margin-xs' 'has-bottom-margin-m'}}">
|
||||
<FormFieldLabel
|
||||
for={{attr.name}}
|
||||
@label="Issuer ref"
|
||||
@helpText={{(if this.showHelpText attr.options.helpText)}}
|
||||
@subText={{attr.options.subText}}
|
||||
/>
|
||||
<Toggle
|
||||
@name={{concat attr.name "-toggle"}}
|
||||
@status="success"
|
||||
@size="small"
|
||||
@checked={{this.showDefaultIssuer}}
|
||||
@onChange={{this.toggleShowDefaultIssuer}}
|
||||
>
|
||||
<span class="has-text-grey">Use default issuer</span>
|
||||
</Toggle>
|
||||
</div>
|
||||
{{#unless this.showDefaultIssuer}}
|
||||
<div class="has-top-margin-xs has-bottom-margin-l">
|
||||
<div class="select is-fullwidth">
|
||||
<Select
|
||||
@name={{attr.name}}
|
||||
@options={{this.issuers}}
|
||||
@valueAttribute={{"issuerDisplayName"}}
|
||||
@labelAttribute={{"issuerDisplayName"}}
|
||||
@isFullwidth={{true}}
|
||||
@selectedValue={{@role.issuerRef}}
|
||||
@onChange={{action (mut @role.issuerRef)}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{{/unless}}
|
||||
{{else}}
|
||||
<FormField
|
||||
data-test-field={{attr}}
|
||||
@attr={{attr}}
|
||||
@model={{@role}}
|
||||
@modelValidations={{this.modelValidations}}
|
||||
@showHelpText={{false}}
|
||||
>
|
||||
<PkiNotValidAfterForm @attr={{attr}} @model={{@role}} />
|
||||
</FormField>
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
{{else}}
|
||||
{{#let (camelize (concat "show" group)) as |prop|}}
|
||||
<ToggleButton
|
||||
@isOpen={{get @model prop}}
|
||||
@isOpen={{get @role prop}}
|
||||
@openLabel={{concat "Hide " group}}
|
||||
@closedLabel={{group}}
|
||||
@onClick={{fn (mut (get @model prop))}}
|
||||
@onClick={{fn (mut (get @role prop))}}
|
||||
class="is-block"
|
||||
data-test-toggle-group={{group}}
|
||||
/>
|
||||
{{#if (get @model prop)}}
|
||||
{{#if (get @role prop)}}
|
||||
<div class="box is-tall is-marginless" data-test-toggle-div={{group}}>
|
||||
{{#let (get @model.fieldGroupsInfo group) as |toggleGroup|}}
|
||||
{{#let (get @role.fieldGroupsInfo group) as |toggleGroup|}}
|
||||
{{! HEADER }}
|
||||
{{#if toggleGroup.header}}
|
||||
<div class="has-bottom-margin-s">
|
||||
|
@ -44,16 +79,16 @@
|
|||
{{/if}}
|
||||
{{! FIELDS }}
|
||||
{{#if (eq group "Key usage")}}
|
||||
<PkiKeyUsage @model={{@model}} />
|
||||
<PkiKeyUsage @model={{@role}} />
|
||||
{{else if (eq group "Key parameters")}}
|
||||
<PkiKeyParameters @model={{@model}} @fields={{fields}} />
|
||||
<PkiKeyParameters @model={{@role}} @fields={{fields}} />
|
||||
{{else}}
|
||||
{{#each fields as |attr|}}
|
||||
<FormField
|
||||
data-test-field={{true}}
|
||||
@attr={{attr}}
|
||||
@model={{@model}}
|
||||
@modelValidations={{@modelValidations}}
|
||||
@model={{@role}}
|
||||
@modelValidations={{@roleValidations}}
|
||||
@showHelpText={{false}}
|
||||
>
|
||||
{{yield attr}}
|
||||
|
@ -87,7 +122,7 @@
|
|||
disabled={{this.save.isRunning}}
|
||||
data-test-pki-role-save
|
||||
>
|
||||
{{if @model.isNew "Create" "Update"}}
|
||||
{{if @role.isNew "Create" "Update"}}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
|
|
|
@ -7,6 +7,7 @@ import Component from '@glimmer/component';
|
|||
import { inject as service } from '@ember/service';
|
||||
import { task } from 'ember-concurrency';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { action } from '@ember/object';
|
||||
|
||||
/**
|
||||
* @module PkiRoleForm
|
||||
|
@ -18,7 +19,8 @@ import { tracked } from '@glimmer/tracking';
|
|||
* ```
|
||||
* @callback onCancel
|
||||
* @callback onSave
|
||||
* @param {Object} model - pki/role model.
|
||||
* @param {Object} role - pki/role model.
|
||||
* @param {Array} issuers - pki/issuer model.
|
||||
* @param {onCancel} onCancel - Callback triggered when cancel button is clicked.
|
||||
* @param {onSave} onSave - Callback triggered on save success.
|
||||
*/
|
||||
|
@ -31,6 +33,19 @@ export default class PkiRoleForm extends Component {
|
|||
@tracked errorBanner;
|
||||
@tracked invalidFormAlert;
|
||||
@tracked modelValidations;
|
||||
@tracked showDefaultIssuer = true;
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
|
||||
this.showDefaultIssuer = this.args.role.issuerRef === 'default';
|
||||
}
|
||||
|
||||
get issuers() {
|
||||
return this.args.issuers?.map((issuer) => {
|
||||
return { issuerDisplayName: issuer.issuerName || issuer.issuerId };
|
||||
});
|
||||
}
|
||||
|
||||
get breadcrumbs() {
|
||||
const crumbs = [
|
||||
|
@ -38,8 +53,8 @@ export default class PkiRoleForm extends Component {
|
|||
{ label: this.secretMountPath.currentPath, route: 'overview' },
|
||||
{ label: 'roles', route: 'roles.index' },
|
||||
];
|
||||
if (!this.args.model.isNew) {
|
||||
crumbs.push({ label: this.args.model.id, route: 'roles.role.details' }, { label: 'edit' });
|
||||
if (!this.args.role.isNew) {
|
||||
crumbs.push({ label: this.args.role.id, route: 'roles.role.details' }, { label: 'edit' });
|
||||
}
|
||||
return crumbs;
|
||||
}
|
||||
|
@ -48,12 +63,12 @@ export default class PkiRoleForm extends Component {
|
|||
*save(event) {
|
||||
event.preventDefault();
|
||||
try {
|
||||
const { isValid, state, invalidFormMessage } = this.args.model.validate();
|
||||
const { isValid, state, invalidFormMessage } = this.args.role.validate();
|
||||
this.modelValidations = isValid ? null : state;
|
||||
this.invalidFormAlert = invalidFormMessage;
|
||||
if (isValid) {
|
||||
const { isNew, name } = this.args.model;
|
||||
yield this.args.model.save();
|
||||
const { isNew, name } = this.args.role;
|
||||
yield this.args.role.save();
|
||||
this.flashMessages.success(`Successfully ${isNew ? 'created' : 'updated'} the role ${name}.`);
|
||||
this.args.onSave();
|
||||
}
|
||||
|
@ -63,4 +78,13 @@ export default class PkiRoleForm extends Component {
|
|||
this.invalidFormAlert = 'There was an error submitting this form.';
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
toggleShowDefaultIssuer() {
|
||||
this.showDefaultIssuer = !this.showDefaultIssuer;
|
||||
|
||||
if (this.showDefaultIssuer) {
|
||||
this.args.role.issuerRef = 'default';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,15 +6,18 @@
|
|||
import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { withConfirmLeave } from 'core/decorators/confirm-leave';
|
||||
import { hash } from 'rsvp';
|
||||
|
||||
@withConfirmLeave()
|
||||
@withConfirmLeave('model.role', ['model.issuers'])
|
||||
export default class PkiRolesCreateRoute extends Route {
|
||||
@service store;
|
||||
@service secretMountPath;
|
||||
|
||||
model() {
|
||||
return this.store.createRecord('pki/role', {
|
||||
backend: this.secretMountPath.currentPath,
|
||||
const backend = this.secretMountPath.currentPath;
|
||||
return hash({
|
||||
role: this.store.createRecord('pki/role', { backend }),
|
||||
issuers: this.store.query('pki/issuer', { backend }),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -6,23 +6,31 @@
|
|||
import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { withConfirmLeave } from 'core/decorators/confirm-leave';
|
||||
import { hash } from 'rsvp';
|
||||
|
||||
@withConfirmLeave()
|
||||
@withConfirmLeave('model.role', ['model.issuers'])
|
||||
export default class PkiRoleEditRoute extends Route {
|
||||
@service store;
|
||||
@service secretMountPath;
|
||||
|
||||
model() {
|
||||
const { role } = this.paramsFor('roles/role');
|
||||
return this.store.queryRecord('pki/role', {
|
||||
backend: this.secretMountPath.currentPath,
|
||||
id: role,
|
||||
const backend = this.secretMountPath.currentPath;
|
||||
|
||||
return hash({
|
||||
role: this.store.queryRecord('pki/role', {
|
||||
backend,
|
||||
id: role,
|
||||
}),
|
||||
issuers: this.store.query('pki/issuer', { backend }),
|
||||
});
|
||||
}
|
||||
|
||||
setupController(controller, resolvedModel) {
|
||||
super.setupController(controller, resolvedModel);
|
||||
const { id } = resolvedModel;
|
||||
const {
|
||||
role: { id },
|
||||
} = resolvedModel;
|
||||
controller.breadcrumbs = [
|
||||
{ label: 'secrets', route: 'secrets', linkExternal: true },
|
||||
{ label: this.secretMountPath.currentPath, route: 'overview' },
|
||||
|
|
|
@ -10,7 +10,9 @@
|
|||
</PageHeader>
|
||||
|
||||
<PkiRoleForm
|
||||
@role={{this.model.role}}
|
||||
@issuers={{this.model.issuers}}
|
||||
@model={{this.model}}
|
||||
@onCancel={{transition-to "vault.cluster.secrets.backend.pki.roles.index"}}
|
||||
@onSave={{transition-to "vault.cluster.secrets.backend.pki.roles.role.details" this.model.id}}
|
||||
@onSave={{transition-to "vault.cluster.secrets.backend.pki.roles.role.details" this.model.role.id}}
|
||||
/>
|
|
@ -9,7 +9,8 @@
|
|||
</p.levelLeft>
|
||||
</PageHeader>
|
||||
<PkiRoleForm
|
||||
@model={{this.model}}
|
||||
@onCancel={{transition-to "vault.cluster.secrets.backend.pki.roles.role.details" this.model.id}}
|
||||
@onSave={{transition-to "vault.cluster.secrets.backend.pki.roles.role.details" this.model.id}}
|
||||
@role={{this.model.role}}
|
||||
@issuers={{this.model.issuers}}
|
||||
@onCancel={{transition-to "vault.cluster.secrets.backend.pki.roles.role.details" this.model.role.id}}
|
||||
@onSave={{transition-to "vault.cluster.secrets.backend.pki.roles.role.details" this.model.role.id}}
|
||||
/>
|
|
@ -142,7 +142,8 @@ module('Acceptance | pki engine route cleanup test', function (hooks) {
|
|||
|
||||
// Edit role
|
||||
await click(SELECTORS.editRoleLink);
|
||||
await fillIn(SELECTORS.roleForm.issuerRef, 'foobar');
|
||||
await click(SELECTORS.roleForm.issuerRefToggle);
|
||||
await fillIn(SELECTORS.roleForm.issuerRefSelect, 'foobar');
|
||||
role = this.store.peekRecord('pki/role', roleId);
|
||||
assert.true(role.hasDirtyAttributes, 'Role has dirty attrs');
|
||||
// Exit page via cancel button
|
||||
|
@ -153,7 +154,8 @@ module('Acceptance | pki engine route cleanup test', function (hooks) {
|
|||
|
||||
// Edit again
|
||||
await click(SELECTORS.editRoleLink);
|
||||
await fillIn(SELECTORS.roleForm.issuerRef, 'foobar2');
|
||||
await click(SELECTORS.roleForm.issuerRefToggle);
|
||||
await fillIn(SELECTORS.roleForm.issuerRefSelect, 'foobar2');
|
||||
role = this.store.peekRecord('pki/role', roleId);
|
||||
assert.true(role.hasDirtyAttributes, 'Role has dirty attrs');
|
||||
// Exit page via breadcrumbs
|
||||
|
|
|
@ -8,6 +8,8 @@ export const PKI_BASE_URL = `/vault/cluster/secrets/backend/pki/roles`;
|
|||
export const SELECTORS = {
|
||||
roleName: '[data-test-input="name"]',
|
||||
issuerRef: '[data-test-input="issuerRef"]',
|
||||
issuerRefSelect: '[data-test-select="issuerRef"]',
|
||||
issuerRefToggle: '[data-test-toggle-label="issuerRef-toggle"]',
|
||||
customTtl: '[data-test-field="customTtl"]',
|
||||
backdateValidity: '[data-test-ttl-value="Backdate validity"]',
|
||||
maxTtl: '[data-test-toggle-label="Max TTL"]',
|
||||
|
|
|
@ -19,8 +19,11 @@ module('Integration | Component | pki-role-form', function (hooks) {
|
|||
|
||||
hooks.beforeEach(function () {
|
||||
this.store = this.owner.lookup('service:store');
|
||||
this.model = this.store.createRecord('pki/role');
|
||||
this.model.backend = 'pki';
|
||||
this.role = this.store.createRecord('pki/role');
|
||||
this.store.createRecord('pki/issuer', { issuerName: 'issuer-0', issuerId: 'abcd-efgh' });
|
||||
this.store.createRecord('pki/issuer', { issuerName: 'issuer-1', issuerId: 'ijkl-mnop' });
|
||||
this.issuers = this.store.peekAll('pki/issuer');
|
||||
this.role.backend = 'pki';
|
||||
this.onCancel = sinon.spy();
|
||||
});
|
||||
|
||||
|
@ -29,14 +32,15 @@ module('Integration | Component | pki-role-form', function (hooks) {
|
|||
await render(
|
||||
hbs`
|
||||
<PkiRoleForm
|
||||
@model={{this.model}}
|
||||
@role={{this.role}}
|
||||
@issuers={{this.issuers}}
|
||||
@onCancel={{this.onCancel}}
|
||||
@onSave={{this.onSave}}
|
||||
/>
|
||||
`,
|
||||
{ owner: this.engine }
|
||||
);
|
||||
assert.dom(SELECTORS.issuerRef).exists('shows form-field issuer ref');
|
||||
assert.dom(SELECTORS.issuerRefToggle).exists('shows issuer ref toggle');
|
||||
assert.dom(SELECTORS.backdateValidity).exists('shows form-field backdate validity');
|
||||
assert.dom(SELECTORS.customTtl).exists('shows custom yielded form field');
|
||||
assert.dom(SELECTORS.maxTtl).exists('shows form-field max ttl');
|
||||
|
@ -54,7 +58,7 @@ module('Integration | Component | pki-role-form', function (hooks) {
|
|||
test('it should save a new pki role with various options selected', async function (assert) {
|
||||
// Key usage, Key params and Not valid after options are tested in their respective component tests
|
||||
assert.expect(9);
|
||||
this.server.post(`/${this.model.backend}/roles/test-role`, (schema, req) => {
|
||||
this.server.post(`/${this.role.backend}/roles/test-role`, (schema, req) => {
|
||||
assert.ok(true, 'Request made to save role');
|
||||
const request = JSON.parse(req.requestBody);
|
||||
const allowedDomainsTemplate = request.allowed_domains_template;
|
||||
|
@ -78,7 +82,8 @@ module('Integration | Component | pki-role-form', function (hooks) {
|
|||
await render(
|
||||
hbs`
|
||||
<PkiRoleForm
|
||||
@model={{this.model}}
|
||||
@role={{this.role}}
|
||||
@issuers={{this.issuers}}
|
||||
@onCancel={{this.onCancel}}
|
||||
@onSave={{this.onSave}}
|
||||
/>
|
||||
|
@ -87,6 +92,7 @@ module('Integration | Component | pki-role-form', function (hooks) {
|
|||
);
|
||||
|
||||
await click(SELECTORS.roleCreateButton);
|
||||
|
||||
assert
|
||||
.dom(SELECTORS.roleName)
|
||||
.hasClass('has-error-border', 'shows border error on role name field when no role name is submitted');
|
||||
|
@ -120,6 +126,7 @@ module('Integration | Component | pki-role-form', function (hooks) {
|
|||
|
||||
test('it should update attributes on the model on update', async function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
this.store.pushPayload('pki/role', {
|
||||
modelName: 'pki/role',
|
||||
name: 'test-role',
|
||||
|
@ -127,21 +134,22 @@ module('Integration | Component | pki-role-form', function (hooks) {
|
|||
id: 'role-id',
|
||||
});
|
||||
|
||||
this.model = this.store.peekRecord('pki/role', 'role-id');
|
||||
this.role = this.store.peekRecord('pki/role', 'role-id');
|
||||
|
||||
await render(
|
||||
hbs`
|
||||
<PkiRoleForm
|
||||
@model={{this.model}}
|
||||
@role={{this.role}}
|
||||
@issuers={{this.issuers}}
|
||||
@onCancel={{this.onCancel}}
|
||||
@onSave={{this.onSave}}
|
||||
/>
|
||||
`,
|
||||
{ owner: this.engine }
|
||||
);
|
||||
|
||||
await fillIn(SELECTORS.issuerRef, 'not-default');
|
||||
await click(SELECTORS.issuerRefToggle);
|
||||
await fillIn(SELECTORS.issuerRefSelect, 'issuer-1');
|
||||
await click(SELECTORS.roleCreateButton);
|
||||
assert.strictEqual(this.model.issuerRef, 'not-default', 'Issuer Ref correctly saved on create');
|
||||
assert.strictEqual(this.role.issuerRef, 'issuer-1', 'Issuer Ref correctly saved on create');
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue