mirror of
https://github.com/hashicorp/vault.git
synced 2026-05-05 12:26:34 +02:00
UI: Add acme route and tab (#26355)
This commit is contained in:
parent
b01edee904
commit
f8b092c201
@ -7,11 +7,13 @@
|
||||
<EmptyState
|
||||
@title="No data received {{if @dateRangeMessage @dateRangeMessage}}"
|
||||
@message="Tracking is turned on and Vault is gathering data. It should appear here within 30 minutes."
|
||||
class="is-shadowless"
|
||||
/>
|
||||
{{else}}
|
||||
<EmptyState
|
||||
@title="Data tracking is disabled"
|
||||
@message="Tracking is disabled, and no data is being collected. To turn it on, edit the configuration."
|
||||
class="is-shadowless"
|
||||
>
|
||||
{{#if @config.canEdit}}
|
||||
<Hds::Link::Standalone
|
||||
|
||||
14
ui/app/components/clients/page/acme.hbs
Normal file
14
ui/app/components/clients/page/acme.hbs
Normal file
@ -0,0 +1,14 @@
|
||||
{{!
|
||||
Copyright (c) HashiCorp, Inc.
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
~}}
|
||||
|
||||
<div class="chart-wrapper" data-test-usage-stats>
|
||||
<div class="chart-header has-bottom-margin-m">
|
||||
<h2 class="chart-title">ACME usage</h2>
|
||||
<p class="chart-description has-bottom-padding-m">This data can be used to understand how many ACME clients have been
|
||||
used for the queried
|
||||
{{if this.isDateRange "date range" "month"}}. Each ACME request is counted as one client.</p>
|
||||
</div>
|
||||
<StatText @label="Total ACME clients" @value={{this.totalUsageCounts.acme_clients}} @size="l" />
|
||||
</div>
|
||||
8
ui/app/components/clients/page/acme.ts
Normal file
8
ui/app/components/clients/page/acme.ts
Normal file
@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import ActivityComponent from '../activity';
|
||||
|
||||
export default class ClientsAcmePageComponent extends ActivityComponent {}
|
||||
@ -3,6 +3,14 @@
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
~}}
|
||||
|
||||
<PageHeader as |p|>
|
||||
<p.levelLeft>
|
||||
<h1 class="title is-3">
|
||||
Vault Usage Metrics
|
||||
</h1>
|
||||
</p.levelLeft>
|
||||
</PageHeader>
|
||||
|
||||
<div class="box is-sideless is-fullwidth is-marginless is-bottomless">
|
||||
<p class="has-bottom-margin-xl">
|
||||
This dashboard surfaces Vault client usage over time.
|
||||
@ -103,7 +111,7 @@
|
||||
|
||||
{{#if this.filteredActivity}}
|
||||
{{#if this.upgradeExplanations}}
|
||||
<Hds::Alert data-test-clients-upgrade-warning @type="inline" @color="warning" class="has-bottom-margin-s" as |A|>
|
||||
<Hds::Alert data-test-clients-upgrade-warning @type="inline" @color="warning" class="has-bottom-margin-m" as |A|>
|
||||
<A.Title>
|
||||
Client count data contains
|
||||
{{pluralize this.upgradeExplanations.length "upgrade"}}
|
||||
@ -138,6 +146,34 @@
|
||||
</Hds::Alert>
|
||||
{{/if}}
|
||||
|
||||
<nav class="tabs has-bottom-margin-s" aria-label="navigation for managing client counts">
|
||||
<ul>
|
||||
<li>
|
||||
<LinkTo @route="vault.cluster.clients.counts.overview" data-test-tab="overview">
|
||||
Overview
|
||||
</LinkTo>
|
||||
</li>
|
||||
<li>
|
||||
<LinkTo @route="vault.cluster.clients.counts.token" data-test-tab="token">
|
||||
Entity/Non-entity clients
|
||||
</LinkTo>
|
||||
</li>
|
||||
{{#if this.version.hasSecretsSync}}
|
||||
<li>
|
||||
<LinkTo @route="vault.cluster.clients.counts.sync" data-test-tab="sync">
|
||||
Secrets sync clients
|
||||
</LinkTo>
|
||||
</li>
|
||||
{{/if}}
|
||||
<li>
|
||||
<LinkTo @route="vault.cluster.clients.counts.acme" data-test-tab="acme">
|
||||
ACME clients
|
||||
</LinkTo>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
{{! CLIENT COUNT PAGE COMPONENTS RENDER HERE }}
|
||||
{{yield}}
|
||||
|
||||
{{else if (and (not @config.billingStartTimestamp) (not @startTimestamp))}}
|
||||
|
||||
@ -5,4 +5,4 @@
|
||||
|
||||
import ActivityComponent from '../activity';
|
||||
|
||||
export default ActivityComponent;
|
||||
export default class ClientsOverviewPageComponent extends ActivityComponent {}
|
||||
|
||||
@ -63,7 +63,11 @@
|
||||
</div>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<EmptyState @title="No Secrets Sync clients" @message="No data is available because Secrets Sync has not been activated.">
|
||||
<EmptyState
|
||||
@title="No Secrets Sync clients"
|
||||
@message="No data is available because Secrets Sync has not been activated."
|
||||
class="is-shadowless"
|
||||
>
|
||||
<Hds::Link::Standalone
|
||||
@icon="chevron-right"
|
||||
@iconPosition="trailing"
|
||||
|
||||
@ -82,6 +82,7 @@
|
||||
'namespace'
|
||||
}} in this date range."
|
||||
@bottomBorder={{true}}
|
||||
class="is-shadowless"
|
||||
/>
|
||||
</:emptyState>
|
||||
</Clients::ChartContainer>
|
||||
@ -96,7 +97,7 @@
|
||||
this.isCurrentMonth
|
||||
"Only totals are available when viewing the current month. To see a breakdown of new and total clients for this month, select the 'Current Billing Period' filter."
|
||||
}}"
|
||||
@isSecretsSyncActivated={{@isSecretsSyncActivated}}
|
||||
@showSecretSyncs={{false}}
|
||||
@totalUsageCounts={{this.tokenUsageCounts}}
|
||||
/>
|
||||
{{/if}}
|
||||
@ -118,7 +118,7 @@
|
||||
@isCurrentMonth
|
||||
"Only totals are available when viewing the current month. To see a breakdown of new and total clients for this month, select the 'Current billing period' filter."
|
||||
}}"
|
||||
@isSecretsSyncActivated={{@isSecretsSyncActivated}}
|
||||
@showSecretSyncs={{@isSecretsSyncActivated}}
|
||||
@totalUsageCounts={{@runningTotals}}
|
||||
/>
|
||||
{{/if}}
|
||||
|
||||
@ -47,7 +47,7 @@
|
||||
data-test-stat-text="non-entity-clients"
|
||||
/>
|
||||
</div>
|
||||
{{#if @isSecretsSyncActivated}}
|
||||
{{#if @showSecretSyncs}}
|
||||
<div class="column">
|
||||
<StatText
|
||||
class="column"
|
||||
|
||||
31
ui/app/components/sidebar/nav/clients.hbs
Normal file
31
ui/app/components/sidebar/nav/clients.hbs
Normal file
@ -0,0 +1,31 @@
|
||||
{{!
|
||||
Copyright (c) HashiCorp, Inc.
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
~}}
|
||||
|
||||
<Hds::SideNav::Portal @ariaLabel="Client Count Navigation Links" data-test-sidebar-nav-panel="Client Count" as |Nav|>
|
||||
<Nav.BackLink
|
||||
@route="vault.cluster"
|
||||
@current-when={{false}}
|
||||
@icon="arrow-left"
|
||||
@text="Back to main navigation"
|
||||
data-test-sidebar-nav-link="Back to main navigation"
|
||||
/>
|
||||
|
||||
<Nav.Title data-test-sidebar-nav-heading="Client Count">Client Count</Nav.Title>
|
||||
|
||||
<Nav.Link
|
||||
@route="vault.cluster.clients.counts.overview"
|
||||
@current-when="vault.cluster.clients.counts"
|
||||
@text="Vault Usage Metrics"
|
||||
data-test-sidebar-nav-link="Vault Usage Metrics"
|
||||
/>
|
||||
{{#if @canReadConfig}}
|
||||
<Nav.Link
|
||||
@route="vault.cluster.clients.config"
|
||||
@text="Configuration"
|
||||
@current-when="vault.cluster.clients.config vault.cluster.clients.edit"
|
||||
data-test-sidebar-nav-link="Configuration"
|
||||
/>
|
||||
{{/if}}
|
||||
</Hds::SideNav::Portal>
|
||||
@ -82,7 +82,12 @@
|
||||
/>
|
||||
{{/if}}
|
||||
{{#if (and (has-permission "clients" routeParams="activity") (not this.cluster.dr.isSecondary))}}
|
||||
<Nav.Link @route="vault.cluster.clients" @text="Client Count" data-test-sidebar-nav-link="Client Count" />
|
||||
<Nav.Link
|
||||
@route="vault.cluster.clients"
|
||||
@text="Client Count"
|
||||
@hasSubItems={{true}}
|
||||
data-test-sidebar-nav-link="Client Count"
|
||||
/>
|
||||
{{/if}}
|
||||
{{#if
|
||||
(and
|
||||
|
||||
@ -1,16 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import Controller from '@ember/controller';
|
||||
import { service } from '@ember/service';
|
||||
import type VersionService from 'vault/services/version';
|
||||
|
||||
export default class ClientsController extends Controller {
|
||||
@service declare readonly version: VersionService;
|
||||
|
||||
get hasSecretsSync() {
|
||||
return this.version.hasSecretsSync;
|
||||
}
|
||||
}
|
||||
@ -29,8 +29,9 @@ Router.map(function () {
|
||||
this.route('clients', function () {
|
||||
this.route('counts', function () {
|
||||
this.route('overview');
|
||||
this.route('sync');
|
||||
this.route('token');
|
||||
this.route('sync');
|
||||
this.route('acme');
|
||||
});
|
||||
this.route('config');
|
||||
this.route('edit');
|
||||
|
||||
8
ui/app/routes/vault/cluster/clients/counts/acme.ts
Normal file
8
ui/app/routes/vault/cluster/clients/counts/acme.ts
Normal file
@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import Route from '@ember/routing/route';
|
||||
|
||||
export default class ClientsCountsAcmeRoute extends Route {}
|
||||
@ -3,47 +3,5 @@
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
~}}
|
||||
|
||||
<PageHeader as |p|>
|
||||
<p.levelLeft>
|
||||
<h1 class="title is-3">
|
||||
Vault Usage Metrics
|
||||
</h1>
|
||||
</p.levelLeft>
|
||||
</PageHeader>
|
||||
|
||||
<div class="tabs-container box is-bottomless is-marginless is-fullwidth is-paddingless">
|
||||
<nav class="tabs" aria-label="navigation for managing client counts">
|
||||
<ul>
|
||||
<li>
|
||||
<LinkTo @route="vault.cluster.clients.counts.overview" data-test-tab="overview">
|
||||
Overview
|
||||
</LinkTo>
|
||||
</li>
|
||||
<li>
|
||||
<LinkTo @route="vault.cluster.clients.counts.token" data-test-tab="token">
|
||||
Entity/Non-entity clients
|
||||
</LinkTo>
|
||||
</li>
|
||||
{{#if this.hasSecretsSync}}
|
||||
<li>
|
||||
<LinkTo @route="vault.cluster.clients.counts.sync" data-test-tab="sync">
|
||||
Secrets sync clients
|
||||
</LinkTo>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if (or @model.config.canRead @model.canRead)}}
|
||||
<li>
|
||||
<LinkTo
|
||||
@route="vault.cluster.clients.config"
|
||||
@current-when="vault.cluster.clients.config vault.cluster.clients.edit"
|
||||
data-test-tab="config"
|
||||
>
|
||||
Configuration
|
||||
</LinkTo>
|
||||
</li>
|
||||
{{/if}}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<Sidebar::Nav::Clients @canReadConfig={{this.model.config.canRead}} />
|
||||
{{outlet}}
|
||||
@ -3,6 +3,14 @@
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
~}}
|
||||
|
||||
<PageHeader as |p|>
|
||||
<p.levelLeft>
|
||||
<h1 class="title is-3">
|
||||
Configuration
|
||||
</h1>
|
||||
</p.levelLeft>
|
||||
</PageHeader>
|
||||
|
||||
<Toolbar>
|
||||
<ToolbarActions>
|
||||
{{#if @model.canEdit}}
|
||||
|
||||
13
ui/app/templates/vault/cluster/clients/counts/acme.hbs
Normal file
13
ui/app/templates/vault/cluster/clients/counts/acme.hbs
Normal file
@ -0,0 +1,13 @@
|
||||
{{!
|
||||
Copyright (c) HashiCorp, Inc.
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
~}}
|
||||
|
||||
<Clients::Page::Acme
|
||||
@activity={{this.model.activity}}
|
||||
@versionHistory={{this.model.versionHistory}}
|
||||
@startTimestamp={{this.model.startTimestamp}}
|
||||
@endTimestamp={{this.model.endTimestamp}}
|
||||
@namespace={{this.countsController.ns}}
|
||||
@mountPath={{this.countsController.mountPath}}
|
||||
/>
|
||||
@ -8,7 +8,6 @@
|
||||
@versionHistory={{this.model.versionHistory}}
|
||||
@startTimestamp={{this.model.startTimestamp}}
|
||||
@endTimestamp={{this.model.endTimestamp}}
|
||||
@isSecretsSyncActivated={{this.model.isSecretsSyncActivated}}
|
||||
@namespace={{this.countsController.ns}}
|
||||
@mountPath={{this.countsController.mountPath}}
|
||||
/>
|
||||
@ -3,4 +3,12 @@
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
~}}
|
||||
|
||||
<PageHeader as |p|>
|
||||
<p.levelLeft>
|
||||
<h1 class="title is-3">
|
||||
Edit Configuration
|
||||
</h1>
|
||||
</p.levelLeft>
|
||||
</PageHeader>
|
||||
|
||||
<Clients::Config @model={{@model}} @mode="edit" />
|
||||
@ -43,7 +43,7 @@ module('Acceptance | clients | overview', function (hooks) {
|
||||
test('it should render the correct tabs', async function (assert) {
|
||||
assert.dom(GENERAL.tab('overview')).exists();
|
||||
assert.dom(GENERAL.tab('token')).exists();
|
||||
assert.dom(GENERAL.tab('config')).exists();
|
||||
assert.dom(GENERAL.tab('acme')).exists();
|
||||
});
|
||||
|
||||
test('it should render charts', async function (assert) {
|
||||
|
||||
@ -105,7 +105,7 @@ module('Acceptance | sidebar navigation', function (hooks) {
|
||||
assert.expect(7);
|
||||
|
||||
await click(link('Tools'));
|
||||
assert.dom(panel('Tools')).exists('Access nav panel renders');
|
||||
assert.dom(panel('Tools')).exists('Tools nav panel renders');
|
||||
|
||||
const links = [
|
||||
{ label: 'Wrap', route: '/vault/tools/wrap' },
|
||||
@ -122,6 +122,20 @@ module('Acceptance | sidebar navigation', function (hooks) {
|
||||
}
|
||||
});
|
||||
|
||||
test('it should link to correct routes at the client counts level', async function (assert) {
|
||||
assert.expect(7);
|
||||
await click(link('Client Count'));
|
||||
assert.dom(panel('Client Count')).exists('Client counts nav panel renders');
|
||||
assert.strictEqual(currentURL(), '/vault/clients/counts/overview', 'Top level nav link renders overview');
|
||||
assert.dom(link('Vault Usage Metrics')).hasClass('active');
|
||||
await click(link('Configuration'));
|
||||
assert.strictEqual(currentURL(), '/vault/clients/config', 'Clients configuration renders');
|
||||
assert.dom(link('Configuration')).hasClass('active');
|
||||
await click(link('Vault Usage Metrics'));
|
||||
assert.strictEqual(currentURL(), '/vault/clients/counts/overview', 'Sub nav link navigates to overview');
|
||||
assert.dom(link('Vault Usage Metrics')).hasClass('active');
|
||||
});
|
||||
|
||||
test('it should display access nav when mounting and configuring auth methods', async function (assert) {
|
||||
await click(link('Access'));
|
||||
await click('[data-test-auth-enable]');
|
||||
|
||||
@ -12,12 +12,12 @@ module('Integration | Component | clients/usage-stats', function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
this.isSecretsSyncActivated = false;
|
||||
this.showSecretSyncs = false;
|
||||
this.counts = {};
|
||||
|
||||
this.renderComponent = async () =>
|
||||
await render(
|
||||
hbs`<Clients::UsageStats @totalUsageCounts={{this.counts}} @isSecretsSyncActivated={{this.isSecretsSyncActivated}} />`
|
||||
hbs`<Clients::UsageStats @totalUsageCounts={{this.counts}} @showSecretSyncs={{this.showSecretSyncs}} />`
|
||||
);
|
||||
});
|
||||
|
||||
@ -72,7 +72,7 @@ module('Integration | Component | clients/usage-stats', function (hooks) {
|
||||
});
|
||||
|
||||
test('with secrets sync activated', async function (assert) {
|
||||
this.isSecretsSyncActivated = true;
|
||||
this.showSecretSyncs = true;
|
||||
|
||||
await this.renderComponent();
|
||||
|
||||
@ -83,7 +83,7 @@ module('Integration | Component | clients/usage-stats', function (hooks) {
|
||||
});
|
||||
|
||||
test('with secrets sync NOT activated', async function (assert) {
|
||||
this.isSecretsSyncActivated = false;
|
||||
this.showSecretSyncs = false;
|
||||
|
||||
await this.renderComponent();
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user