UI: VAULT-12949 use overview card component for kubernetes overview (#18845)

* VAULT-12949 use overview card component for kubernetes overview

* Add a little more spacing

* Add margin to pki overview form

* Remove form element
This commit is contained in:
Kianna
2023-01-25 16:09:04 -08:00
committed by GitHub
parent 990d3bacc2
commit dbefdc38fa
7 changed files with 111 additions and 118 deletions

View File

@@ -13,6 +13,6 @@
</LinkTo> </LinkTo>
{{/if}} {{/if}}
</div> </div>
<p class="has-text-grey is-size-8 {{unless @actionText 'has-top-margin-xs'}}">{{@subText}}</p> <p class="has-text-grey is-size-8 {{unless @actionText 'has-top-margin-s'}}">{{@subText}}</p>
{{yield}} {{yield}}
</div> </div>

View File

@@ -3,51 +3,40 @@
</TabPageHeader> </TabPageHeader>
{{#if @config}} {{#if @config}}
<div class="has-top-margin-m"> <div class="selectable-card-container has-grid has-top-margin-l has-two-col-grid">
<div class="is-flex"> <OverviewCard
<div class="box has-padding-m has-right-margin-m is-rounded column is-flex-half" data-test-roles-card> @cardTitle="Roles"
<div class="is-flex-between"> @subText="The number of Vault roles being used to generate Kubernetes credentials."
<h2 class="title is-3"> @actionText={{if @roles.length "View Roles" "Create Role"}}
Roles @actionTo={{if @roles.length "roles" "roles.create"}}
</h2> >
{{#if @roles.length}} <h2 class="title is-2 has-font-weight-normal has-top-margin-m" data-test-roles-card-overview-num>{{or
<LinkTo class="is-no-underline" @route="roles">View Roles</LinkTo> @roles.length
{{else}} "None"
<LinkTo class="is-no-underline" @route="roles.create">Create Role</LinkTo> }}</h2>
{{/if}} </OverviewCard>
</div> <OverviewCard @cardTitle="Generate credentials" @subText="Quickly generate credentials by typing the role name.">
<p>The number of Vault roles being used to generate Kubernetes credentials.</p> <div class="has-top-margin-m is-flex">
<h2 class="title has-font-weight-normal is-3 has-top-margin-l"> <SearchSelect
{{or @roles.length "None"}} class="is-flex-1"
</h2> @placeholder="Type to find a role..."
@disallowNewItems={{true}}
@options={{this.roleOptions}}
@selectLimit="1"
@fallbackComponent="input-search"
@onChange={{this.selectRole}}
/>
<button
class="button has-left-margin-s"
type="button"
disabled={{not this.selectedRole}}
{{on "click" this.generateCredential}}
data-test-generate-credential-button
>
Generate
</button>
</div> </div>
<div class="box has-padding-m is-rounded column is-flex-half" data-test-generate-credential-card> </OverviewCard>
<h2 class="title is-3">
Generate credentials
</h2>
<p>Quickly generate credentials by typing the role name.</p>
<div class="is-flex-center has-top-margin-s">
<SearchSelect
class="is-marginless is-flex-1"
@placeholder="Type to find a role..."
@disallowNewItems={{true}}
@options={{this.roleOptions}}
@selectLimit="1"
@fallbackComponent="input-search"
@onChange={{this.selectRole}}
/>
<button
class="button has-left-margin-m"
type="button"
disabled={{not this.selectedRole}}
{{on "click" this.generateCredential}}
data-test-generate-credential-button
>
Generate
</button>
</div>
</div>
</div>
</div> </div>
{{else}} {{else}}
<ConfigCta /> <ConfigCta />

View File

@@ -21,62 +21,52 @@
</OverviewCard> </OverviewCard>
{{/if}} {{/if}}
<OverviewCard @cardTitle="Issue certificate" @subText="Begin issuing a certificate by choosing a role."> <OverviewCard @cardTitle="Issue certificate" @subText="Begin issuing a certificate by choosing a role.">
<form <div class="has-top-margin-m is-flex">
aria-label="issue certificate" <SearchSelect
data-test-selectable-card="Issue certificate" class="is-flex-1"
{{on "submit" this.transitionToIssueCertificates}} @selectLimit="1"
> @models={{array "pki/role"}}
<div class="has-top-padding-s is-flex"> @backend={{@engine.id}}
<SearchSelect @placeholder="Type to find a role..."
class="is-flex-1" @disallowNewItems={{true}}
@selectLimit="1" @onChange={{this.handleRolesInput}}
@models={{array "pki/role"}} @fallbackComponent="input-search"
@backend={{@engine.id}} data-test-issue-certificate-input
@placeholder="Type to find a role..." />
@disallowNewItems={{true}} <button
@onChange={{this.handleRolesInput}} type="submit"
@fallbackComponent="input-search" class="button is-secondary has-left-margin-s"
data-test-issue-certificate-input disabled={{unless this.rolesValue true}}
/> {{on "click" this.transitionToIssueCertificates}}
<button data-test-issue-certificate-button
type="submit" >
class="button is-secondary has-left-margin-s" Issue
disabled={{unless this.rolesValue true}} </button>
data-test-issue-certificate-button </div>
>
Issue
</button>
</div>
</form>
</OverviewCard> </OverviewCard>
<OverviewCard @cardTitle="View certificate" @subText="Quickly view a certificate by typing its serial number."> <OverviewCard @cardTitle="View certificate" @subText="Quickly view a certificate by typing its serial number.">
<form <div class="has-top-margin-m is-flex">
aria-label="view certificate" <SearchSelect
data-test-selectable-card="View certificate" class="is-flex-1"
{{on "submit" this.transitionToViewCertificates}} @selectLimit="1"
> @models={{array "pki/certificate/base"}}
<div class="has-top-padding-s is-flex"> @backend={{@engine.id}}
<SearchSelect @placeholder="33:a3:..."
class="is-flex-1" @disallowNewItems={{true}}
@selectLimit="1" @onChange={{this.handleCertificateInput}}
@models={{array "pki/certificate/base"}} @fallbackComponent="input-search"
@backend={{@engine.id}} data-test-view-certificate-input
@placeholder="33:a3:..." />
@disallowNewItems={{true}} <button
@onChange={{this.handleCertificateInput}} type="button"
@fallbackComponent="input-search" class="button is-secondary has-left-margin-s"
data-test-view-certificate-input disabled={{unless this.certificateValue true}}
/> {{on "click" this.transitionToViewCertificates}}
<button data-test-view-certificate-button
type="submit" >
class="button is-secondary has-left-margin-s" View
disabled={{unless this.certificateValue true}} </button>
data-test-view-certificate-button </div>
>
View
</button>
</div>
</form>
</OverviewCard> </OverviewCard>
</div> </div>

View File

@@ -22,16 +22,14 @@ export default class PkiOverview extends Component<Args> {
@tracked certificateValue = ''; @tracked certificateValue = '';
@action @action
transitionToViewCertificates(event: Event) { transitionToViewCertificates() {
event.preventDefault();
this.router.transitionTo( this.router.transitionTo(
'vault.cluster.secrets.backend.pki.certificates.certificate.details', 'vault.cluster.secrets.backend.pki.certificates.certificate.details',
this.certificateValue this.certificateValue
); );
} }
@action @action
transitionToIssueCertificates(event: Event) { transitionToIssueCertificates() {
event.preventDefault();
this.router.transitionTo('vault.cluster.secrets.backend.pki.roles.role.generate', this.rolesValue); this.router.transitionTo('vault.cluster.secrets.backend.pki.roles.role.generate', this.rolesValue);
} }

View File

@@ -6,6 +6,7 @@ import ENV from 'vault/config/environment';
import authPage from 'vault/tests/pages/auth'; import authPage from 'vault/tests/pages/auth';
import { visit, click, currentRouteName } from '@ember/test-helpers'; import { visit, click, currentRouteName } from '@ember/test-helpers';
import { selectChoose } from 'ember-power-select/test-support'; import { selectChoose } from 'ember-power-select/test-support';
import { SELECTORS } from 'vault/tests/helpers/kubernetes/overview';
module('Acceptance | kubernetes | overview', function (hooks) { module('Acceptance | kubernetes | overview', function (hooks) {
setupApplicationTest(hooks); setupApplicationTest(hooks);
@@ -41,7 +42,7 @@ module('Acceptance | kubernetes | overview', function (hooks) {
assert.expect(1); assert.expect(1);
this.createScenario(); this.createScenario();
await this.visitOverview(); await this.visitOverview();
await click('[data-test-roles-card] .is-no-underline'); await click(SELECTORS.rolesCardLink);
this.validateRoute(assert, 'roles.index', 'Transitions to roles route on View Roles click'); this.validateRoute(assert, 'roles.index', 'Transitions to roles route on View Roles click');
}); });
@@ -49,7 +50,7 @@ module('Acceptance | kubernetes | overview', function (hooks) {
assert.expect(1); assert.expect(1);
this.createScenario(false); this.createScenario(false);
await this.visitOverview(); await this.visitOverview();
await click('[data-test-roles-card] .is-no-underline'); await click(SELECTORS.rolesCardLink);
this.validateRoute(assert, 'roles.create', 'Transitions to roles route on Create Roles click'); this.validateRoute(assert, 'roles.create', 'Transitions to roles route on Create Roles click');
}); });

View File

@@ -0,0 +1,12 @@
export const SELECTORS = {
rolesCardTitle: '[data-test-selectable-card="Roles"] .title',
rolesCardSubTitle: '[data-test-selectable-card-container="Roles"] p',
rolesCardLink: '[data-test-selectable-card="Roles"] a',
rolesCardNumRoles: '[data-test-roles-card-overview-num]',
generateCredentialsCardTitle: '[data-test-selectable-card="Generate credentials"] .title',
generateCredentialsCardSubTitle: '[data-test-selectable-card-container="Generate credentials"] p',
generateCredentialsCardButton: '[data-test-generate-credential-button]',
emptyStateTitle: '.empty-state .empty-state-title',
emptyStateMessage: '.empty-state .empty-state-message',
emptyStateActionText: '.empty-state .empty-state-actions',
};

View File

@@ -4,6 +4,7 @@ import { setupEngine } from 'ember-engines/test-support';
import { setupMirage } from 'ember-cli-mirage/test-support'; import { setupMirage } from 'ember-cli-mirage/test-support';
import { render } from '@ember/test-helpers'; import { render } from '@ember/test-helpers';
import { typeInSearch, clickTrigger, selectChoose } from 'ember-power-select/test-support/helpers'; import { typeInSearch, clickTrigger, selectChoose } from 'ember-power-select/test-support/helpers';
import { SELECTORS } from 'vault/tests/helpers/kubernetes/overview';
import hbs from 'htmlbars-inline-precompile'; import hbs from 'htmlbars-inline-precompile';
module('Integration | Component | kubernetes | Page::Overview', function (hooks) { module('Integration | Component | kubernetes | Page::Overview', function (hooks) {
@@ -53,33 +54,35 @@ module('Integration | Component | kubernetes | Page::Overview', function (hooks)
test('it should display role card', async function (assert) { test('it should display role card', async function (assert) {
await this.renderComponent(); await this.renderComponent();
assert.dom('[data-test-roles-card] .title').hasText('Roles'); assert.dom(SELECTORS.rolesCardTitle).hasText('Roles');
assert assert
.dom('[data-test-roles-card] p') .dom(SELECTORS.rolesCardSubTitle)
.hasText('The number of Vault roles being used to generate Kubernetes credentials.'); .hasText('The number of Vault roles being used to generate Kubernetes credentials.');
assert.dom('[data-test-roles-card] a').hasText('View Roles'); assert.dom(SELECTORS.rolesCardLink).hasText('View Roles');
this.roles = []; this.roles = [];
await this.renderComponent(); await this.renderComponent();
assert.dom('[data-test-roles-card] a').hasText('Create Role'); assert.dom(SELECTORS.rolesCardLink).hasText('Create Role');
}); });
test('it should display correct number of roles in role card', async function (assert) { test('it should display correct number of roles in role card', async function (assert) {
await this.renderComponent(); await this.renderComponent();
assert.dom('[data-test-roles-card] .has-font-weight-normal').hasText('2'); assert.dom(SELECTORS.rolesCardNumRoles).hasText('2');
this.roles = []; this.roles = [];
await this.renderComponent(); await this.renderComponent();
assert.dom('[data-test-roles-card] .has-font-weight-normal').hasText('None');
assert.dom(SELECTORS.rolesCardNumRoles).hasText('None');
}); });
test('it should display generate credentials card', async function (assert) { test('it should display generate credentials card', async function (assert) {
await this.renderComponent(); await this.renderComponent();
assert.dom('[data-test-generate-credential-card] .title').hasText('Generate credentials');
assert.dom(SELECTORS.generateCredentialsCardTitle).hasText('Generate credentials');
assert assert
.dom('[data-test-generate-credential-card] p') .dom(SELECTORS.generateCredentialsCardSubTitle)
.hasText('Quickly generate credentials by typing the role name.'); .hasText('Quickly generate credentials by typing the role name.');
}); });
@@ -89,21 +92,21 @@ module('Integration | Component | kubernetes | Page::Overview', function (hooks)
assert.strictEqual(this.element.querySelectorAll('.ember-power-select-option').length, 2); assert.strictEqual(this.element.querySelectorAll('.ember-power-select-option').length, 2);
await typeInSearch('role-0'); await typeInSearch('role-0');
assert.strictEqual(this.element.querySelectorAll('.ember-power-select-option').length, 1); assert.strictEqual(this.element.querySelectorAll('.ember-power-select-option').length, 1);
assert.dom('[data-test-generate-credential-card] button').isDisabled(); assert.dom(SELECTORS.generateCredentialsCardButton).isDisabled();
await selectChoose('', '.ember-power-select-option', 2); await selectChoose('', '.ember-power-select-option', 2);
assert.dom('[data-test-generate-credential-card] button').isNotDisabled(); assert.dom(SELECTORS.generateCredentialsCardButton).isNotDisabled();
}); });
test('it should show ConfigCta when no config is set up', async function (assert) { test('it should show ConfigCta when no config is set up', async function (assert) {
this.config = null; this.config = null;
await this.renderComponent(); await this.renderComponent();
assert.dom('.empty-state .empty-state-title').hasText('Kubernetes not configured'); assert.dom(SELECTORS.emptyStateTitle).hasText('Kubernetes not configured');
assert assert
.dom('.empty-state .empty-state-message') .dom(SELECTORS.emptyStateMessage)
.hasText( .hasText(
'Get started by establishing the URL of the Kubernetes API to connect to, along with some additional options.' 'Get started by establishing the URL of the Kubernetes API to connect to, along with some additional options.'
); );
assert.dom('.empty-state .empty-state-actions').hasText('Configure Kubernetes'); assert.dom(SELECTORS.emptyStateActionText).hasText('Configure Kubernetes');
}); });
}); });