UI: Add acme route and tab (#26355)

This commit is contained in:
claire bontempo 2024-04-11 08:07:48 -07:00 committed by GitHub
parent b01edee904
commit f8b092c201
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 168 additions and 74 deletions

View File

@ -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

View 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>

View 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 {}

View File

@ -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))}}

View File

@ -5,4 +5,4 @@
import ActivityComponent from '../activity';
export default ActivityComponent;
export default class ClientsOverviewPageComponent extends ActivityComponent {}

View File

@ -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"

View File

@ -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}}

View File

@ -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}}

View File

@ -47,7 +47,7 @@
data-test-stat-text="non-entity-clients"
/>
</div>
{{#if @isSecretsSyncActivated}}
{{#if @showSecretSyncs}}
<div class="column">
<StatText
class="column"

View 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>

View File

@ -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

View File

@ -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;
}
}

View File

@ -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');

View 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 {}

View File

@ -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}}

View File

@ -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}}

View 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}}
/>

View File

@ -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}}
/>

View File

@ -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" />

View File

@ -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) {

View File

@ -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]');

View File

@ -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();