mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-30 18:17:55 +00:00
Ui/pricing metrics page setup (#10049)
* Create model and adapter for metrics/activity * Query activity and return fake data on adapterError * Add stub of pricing metrics cards and search form elements to metrics template * Metrics page has pricing metrics rather than all-time tokens and requests * update metrics config model * Add metrics-config route and page * Remove metrics/http-requests route and template * remove log * Add alert banner for when tracking disabled, and add result dates * Small edits
This commit is contained in:
14
ui/app/adapters/metrics/activity.js
Normal file
14
ui/app/adapters/metrics/activity.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import Application from '../application';
|
||||
|
||||
export default Application.extend({
|
||||
queryRecord() {
|
||||
return this.ajax(this.urlForQuery(), 'GET').then(resp => {
|
||||
resp.id = resp.request_id;
|
||||
return resp;
|
||||
});
|
||||
},
|
||||
|
||||
urlForQuery() {
|
||||
return this.buildURL() + '/internal/counters/activity';
|
||||
},
|
||||
});
|
||||
14
ui/app/adapters/metrics/config.js
Normal file
14
ui/app/adapters/metrics/config.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import Application from '../application';
|
||||
|
||||
export default Application.extend({
|
||||
queryRecord() {
|
||||
return this.ajax(this.urlForQuery(), 'GET').then(resp => {
|
||||
resp.id = resp.request_id;
|
||||
return resp;
|
||||
});
|
||||
},
|
||||
|
||||
urlForQuery() {
|
||||
return this.buildURL() + '/internal/counters/config';
|
||||
},
|
||||
});
|
||||
24
ui/app/controllers/vault/cluster/metrics-config.js
Normal file
24
ui/app/controllers/vault/cluster/metrics-config.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import Controller from '@ember/controller';
|
||||
import { computed } from '@ember/object';
|
||||
|
||||
export default Controller.extend({
|
||||
infoRows: computed(function() {
|
||||
return [
|
||||
{
|
||||
label: 'Usage data collection',
|
||||
helperText: 'Enable or disable collecting data to track clients.',
|
||||
valueKey: 'enabled',
|
||||
},
|
||||
{
|
||||
label: 'Retention period',
|
||||
helperText: 'The number of months of activity logs to maintain for client tracking.',
|
||||
valueKey: 'retentionMonths',
|
||||
},
|
||||
{
|
||||
label: 'Default display',
|
||||
helperText: 'The number of months we’ll display in the Vault usage dashboard by default.',
|
||||
valueKey: 'defaultReportMonths',
|
||||
},
|
||||
];
|
||||
}),
|
||||
});
|
||||
7
ui/app/models/metrics/activity.js
Normal file
7
ui/app/models/metrics/activity.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import DS from 'ember-data';
|
||||
|
||||
export default DS.Model.extend({
|
||||
total: DS.attr('object'),
|
||||
endTime: DS.attr('string'),
|
||||
startTime: DS.attr('string'),
|
||||
});
|
||||
10
ui/app/models/metrics/config.js
Normal file
10
ui/app/models/metrics/config.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import DS from 'ember-data';
|
||||
|
||||
const { attr } = DS;
|
||||
|
||||
export default DS.Model.extend({
|
||||
queriesAvailable: attr('boolean'),
|
||||
defaultReportMonths: attr('number'),
|
||||
retentionMonths: attr('number'),
|
||||
enabled: attr('string'),
|
||||
});
|
||||
@@ -15,10 +15,7 @@ Router.map(function() {
|
||||
this.route('logout');
|
||||
this.mount('open-api-explorer', { path: '/api-explorer' });
|
||||
this.route('license');
|
||||
this.route('metrics', function() {
|
||||
this.route('index', { path: '/' });
|
||||
this.route('http-requests');
|
||||
});
|
||||
this.route('metrics');
|
||||
this.route('storage', { path: '/storage/raft' });
|
||||
this.route('storage-restore', { path: '/storage/raft/restore' });
|
||||
this.route('settings', function() {
|
||||
@@ -137,6 +134,7 @@ Router.map(function() {
|
||||
}
|
||||
|
||||
this.route('not-found', { path: '/*path' });
|
||||
this.route('metrics-config');
|
||||
});
|
||||
this.route('not-found', { path: '/*path' });
|
||||
});
|
||||
|
||||
8
ui/app/routes/vault/cluster/metrics-config.js
Normal file
8
ui/app/routes/vault/cluster/metrics-config.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import ClusterRoute from 'vault/mixins/cluster-route';
|
||||
|
||||
export default Route.extend(ClusterRoute, {
|
||||
model() {
|
||||
return this.store.queryRecord('metrics/config', {});
|
||||
},
|
||||
});
|
||||
@@ -1,8 +1,16 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import ClusterRoute from 'vault/mixins/cluster-route';
|
||||
import { hash } from 'rsvp';
|
||||
|
||||
export default Route.extend(ClusterRoute, {
|
||||
model() {
|
||||
return {};
|
||||
let config = this.store.queryRecord('metrics/config', {});
|
||||
|
||||
let activity = this.store.queryRecord('metrics/activity', {});
|
||||
|
||||
return hash({
|
||||
activity,
|
||||
config,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
import ClusterRouteBase from '../cluster-route-base';
|
||||
|
||||
export default ClusterRouteBase.extend({
|
||||
model() {
|
||||
return this.store.queryRecord('metrics/http-requests', {});
|
||||
},
|
||||
});
|
||||
@@ -1,26 +0,0 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import ClusterRoute from 'vault/mixins/cluster-route';
|
||||
import { hash } from 'rsvp';
|
||||
|
||||
export default Route.extend(ClusterRoute, {
|
||||
model() {
|
||||
let totalEntities = this.store.queryRecord('metrics/entity', {}).then(response => {
|
||||
return response.entities.total;
|
||||
});
|
||||
|
||||
let httpsRequests = this.store.queryRecord('metrics/http-requests', {}).then(response => {
|
||||
let reverseArray = response.counters.reverse();
|
||||
return reverseArray;
|
||||
});
|
||||
|
||||
let totalTokens = this.store.queryRecord('metrics/token', {}).then(response => {
|
||||
return response.service_tokens.total;
|
||||
});
|
||||
|
||||
return hash({
|
||||
totalEntities,
|
||||
httpsRequests,
|
||||
totalTokens,
|
||||
});
|
||||
},
|
||||
});
|
||||
3
ui/app/serializers/metrics/activity.js
Normal file
3
ui/app/serializers/metrics/activity.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import ApplicationSerializer from '../application';
|
||||
|
||||
export default ApplicationSerializer.extend({});
|
||||
12
ui/app/serializers/metrics/config.js
Normal file
12
ui/app/serializers/metrics/config.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import ApplicationSerializer from '../application';
|
||||
|
||||
export default ApplicationSerializer.extend({
|
||||
normalizeResponse(store, primaryModelClass, payload, id, requestType) {
|
||||
const normalizedPayload = {
|
||||
id: payload.id,
|
||||
...payload.data,
|
||||
enabled: payload.data.enabled.includes('enabled') ? 'On' : 'Off',
|
||||
};
|
||||
return this._super(store, primaryModelClass, normalizedPayload, id, requestType);
|
||||
},
|
||||
});
|
||||
48
ui/app/templates/vault/cluster/metrics-config.hbs
Normal file
48
ui/app/templates/vault/cluster/metrics-config.hbs
Normal file
@@ -0,0 +1,48 @@
|
||||
<PageHeader as |p|>
|
||||
<p.levelLeft>
|
||||
<h1 class="title is-3">
|
||||
Metrics
|
||||
</h1>
|
||||
</p.levelLeft>
|
||||
</PageHeader>
|
||||
|
||||
<div class="tabs-container box is-bottomless is-marginless is-fullwidth is-paddingless">
|
||||
<nav class="tabs">
|
||||
<ul>
|
||||
{{#link-to
|
||||
"vault.cluster.metrics"
|
||||
tagName="li"
|
||||
activeClass="is-active"
|
||||
}}
|
||||
{{#link-to
|
||||
"vault.cluster.metrics"
|
||||
data-test-configuration-tab=false
|
||||
}}
|
||||
Vault usage
|
||||
{{/link-to}}
|
||||
{{/link-to}}
|
||||
{{#link-to
|
||||
"vault.cluster.metrics-config"
|
||||
tagName="li"
|
||||
activeClass="is-active"
|
||||
}}
|
||||
{{#link-to
|
||||
"vault.cluster.metrics-config"
|
||||
data-test-configuration-tab=true
|
||||
}}
|
||||
Configuration
|
||||
{{/link-to}}
|
||||
{{/link-to}}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<div class="tabs-container box is-bottomless is-marginless is-fullwidth is-paddingless">
|
||||
{{#each infoRows as |item|}}
|
||||
{{info-table-row
|
||||
label=item.label
|
||||
helperText=item.helperText
|
||||
value=(get model item.valueKey)
|
||||
}}
|
||||
{{/each}}
|
||||
</div>
|
||||
70
ui/app/templates/vault/cluster/metrics.hbs
Normal file
70
ui/app/templates/vault/cluster/metrics.hbs
Normal file
@@ -0,0 +1,70 @@
|
||||
<PageHeader as |p|>
|
||||
<p.levelLeft>
|
||||
<h1 class="title is-3">
|
||||
Metrics
|
||||
</h1>
|
||||
</p.levelLeft>
|
||||
</PageHeader>
|
||||
|
||||
<div class="tabs-container box is-bottomless is-marginless is-fullwidth is-paddingless">
|
||||
<nav class="tabs">
|
||||
<ul>
|
||||
{{#link-to
|
||||
"vault.cluster.metrics"
|
||||
tagName="li"
|
||||
activeClass="is-active"
|
||||
}}
|
||||
{{#link-to
|
||||
"vault.cluster.metrics"
|
||||
data-test-configuration-tab=false
|
||||
}}
|
||||
Vault usage
|
||||
{{/link-to}}
|
||||
{{/link-to}}
|
||||
{{#link-to
|
||||
"vault.cluster.metrics-config"
|
||||
tagName="li"
|
||||
activeClass="is-active"
|
||||
}}
|
||||
{{#link-to
|
||||
"vault.cluster.metrics-config"
|
||||
data-test-configuration-tab=true
|
||||
}}
|
||||
Configuration
|
||||
{{/link-to}}
|
||||
{{/link-to}}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<div class="box is-sideless is-fullwidth is-marginless is-bottomless">
|
||||
{{#unless (eq model.config.enabled 'On')}}
|
||||
<AlertBanner
|
||||
@type="warning"
|
||||
@title="Tracking is disabled"
|
||||
>
|
||||
This feature is currently disabled and data is not being collected. {{#link-to 'vault.cluster.metrics-config'}}Edit the configuration{{/link-to}} to enable tracking again.
|
||||
</AlertBanner>
|
||||
{{/unless}}
|
||||
<p class="has-bottom-margin-s">The active clients metric contributes to billing. It is collected at the end of each month alongside unique entities and direct active tokens.</p>
|
||||
<h2 class="title is-4">
|
||||
{{date-format model.activity.startTime "MMM DD, YYYY"}} through {{date-format model.activity.endTime "MMM DD, YYYY"}}
|
||||
</h2>
|
||||
<div class="selectable-card-container">
|
||||
<SelectableCard
|
||||
@cardTitle="Active clients"
|
||||
@total={{model.activity.total.clients}}
|
||||
@subText="Current namespace"
|
||||
/>
|
||||
<SelectableCard
|
||||
@cardTitle="Unique entities"
|
||||
@total={{model.activity.total.distinct_entities}}
|
||||
@subText="Current namespace"
|
||||
/>
|
||||
<SelectableCard
|
||||
@cardTitle="Active direct tokens"
|
||||
@total={{model.activity.total.non_entity_tokens}}
|
||||
@subText="Current namespace"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,21 +0,0 @@
|
||||
<PageHeader as |p|>
|
||||
<p.top>
|
||||
<nav class="key-value-header breadcrumb">
|
||||
<ul>
|
||||
<li>
|
||||
<span class="sep">/</span>
|
||||
{{#link-to "vault.cluster.metrics"}}
|
||||
Metrics
|
||||
{{/link-to}}
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</p.top>
|
||||
<p.levelLeft>
|
||||
<h1 class="title is-3">
|
||||
HTTP Request Volume
|
||||
</h1>
|
||||
</p.levelLeft>
|
||||
</PageHeader>
|
||||
|
||||
<HttpRequestsContainer @counters={{model.counters}}/>
|
||||
@@ -1,15 +0,0 @@
|
||||
<PageHeader as |p|>
|
||||
<p.levelLeft>
|
||||
<h1 class="title is-3">
|
||||
Metrics
|
||||
</h1>
|
||||
</p.levelLeft>
|
||||
</PageHeader>
|
||||
|
||||
<div class="box is-sideless is-fullwidth is-marginless is-bottomless">
|
||||
{{#if (gt model.httpsRequests.length 1) }}
|
||||
<SelectableCardContainer @counters={{model}} @gridContainer="true"/>
|
||||
{{else}}
|
||||
<SelectableCardContainer @counters={{model}} />
|
||||
{{/if}}
|
||||
</div>
|
||||
Reference in New Issue
Block a user