mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-02 11:38:02 +00:00
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:
@@ -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>
|
||||||
@@ -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 />
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
12
ui/tests/helpers/kubernetes/overview.js
Normal file
12
ui/tests/helpers/kubernetes/overview.js
Normal 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',
|
||||||
|
};
|
||||||
@@ -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');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user