From ac23e1be6ec4da0d8ba47e59564c2bf13c874147 Mon Sep 17 00:00:00 2001 From: Arnav Palnitkar Date: Wed, 15 Sep 2021 00:19:33 -0700 Subject: [PATCH 1/5] Client count updates - Added Current month tab which leverages partial monthly activity api - Refactored Vault usage to Monthly history - New client count history component based on StatText and BarChart component - Restrict bar chart to showcase only top 10 namespaces - Removed config route, as config and history component will be rendered based on query param - Updated all metrics reference to clients - Removed old tests and added integration test for current month --- .../adapters/{metrics => clients}/activity.js | 6 +- .../adapters/{metrics => clients}/config.js | 0 .../config.js} | 12 +- ui/app/components/clients/history.js | 26 +++++ ui/app/components/pricing-metrics-dates.js | 42 +------ .../vault/cluster/clients/index.js | 8 ++ .../vault/cluster/metrics/index.js | 8 -- .../models/{metrics => clients}/activity.js | 1 + ui/app/models/{metrics => clients}/config.js | 0 ui/app/router.js | 3 +- .../cluster/{metrics => clients}/edit.js | 2 +- .../cluster/{metrics => clients}/index.js | 37 +++--- ui/app/routes/vault/cluster/metrics/config.js | 8 -- .../{metrics => clients}/activity.js | 0 .../{metrics => clients}/config.js | 0 ui/app/services/permissions.js | 2 +- ui/app/styles/components/bar-chart.scss | 5 +- ui/app/styles/components/stat-text.scss | 4 + .../config.hbs} | 3 +- .../templates/components/clients/history.hbs | 94 ++++++++++++++++ ui/app/templates/components/cluster-info.hbs | 6 +- .../components/pricing-metrics-dates.hbs | 10 -- .../cluster/{metrics => clients}/edit.hbs | 2 +- .../templates/vault/cluster/clients/index.hbs | 47 ++++++++ .../vault/cluster/metrics/config.hbs | 36 ------ .../templates/vault/cluster/metrics/index.hbs | 78 ------------- ui/lib/core/addon/components/bar-chart.js | 8 +- ui/mirage/config.js | 4 +- ui/mirage/scenarios/default.js | 2 +- ui/tests/acceptance/usage-metrics-test.js | 106 ------------------ ...-config-test.js => clients-config-test.js} | 12 +- .../components/clients-current-test.js | 57 ++++++++++ .../components/clients-history-test.js | 67 +++++++++++ .../components/pricing-metrics-dates-test.js | 28 ----- 34 files changed, 362 insertions(+), 362 deletions(-) rename ui/app/adapters/{metrics => clients}/activity.js (77%) rename ui/app/adapters/{metrics => clients}/config.js (100%) rename ui/app/components/{pricing-metrics-config.js => clients/config.js} (82%) create mode 100644 ui/app/components/clients/history.js create mode 100644 ui/app/controllers/vault/cluster/clients/index.js delete mode 100644 ui/app/controllers/vault/cluster/metrics/index.js rename ui/app/models/{metrics => clients}/activity.js (84%) rename ui/app/models/{metrics => clients}/config.js (100%) rename ui/app/routes/vault/cluster/{metrics => clients}/edit.js (62%) rename ui/app/routes/vault/cluster/{metrics => clients}/index.js (51%) delete mode 100644 ui/app/routes/vault/cluster/metrics/config.js rename ui/app/serializers/{metrics => clients}/activity.js (100%) rename ui/app/serializers/{metrics => clients}/config.js (100%) rename ui/app/templates/components/{pricing-metrics-config.hbs => clients/config.hbs} (98%) create mode 100644 ui/app/templates/components/clients/history.hbs rename ui/app/templates/vault/cluster/{metrics => clients}/edit.hbs (71%) create mode 100644 ui/app/templates/vault/cluster/clients/index.hbs delete mode 100644 ui/app/templates/vault/cluster/metrics/config.hbs delete mode 100644 ui/app/templates/vault/cluster/metrics/index.hbs delete mode 100644 ui/tests/acceptance/usage-metrics-test.js rename ui/tests/integration/components/{pricing-metrics-config-test.js => clients-config-test.js} (91%) create mode 100644 ui/tests/integration/components/clients-current-test.js create mode 100644 ui/tests/integration/components/clients-history-test.js diff --git a/ui/app/adapters/metrics/activity.js b/ui/app/adapters/clients/activity.js similarity index 77% rename from ui/app/adapters/metrics/activity.js rename to ui/app/adapters/clients/activity.js index 09ea312b030e5..df54b0ea449fd 100644 --- a/ui/app/adapters/metrics/activity.js +++ b/ui/app/adapters/clients/activity.js @@ -5,7 +5,11 @@ export default Application.extend({ return 'internal/counters/activity'; }, queryRecord(store, type, query) { - const url = this.urlForQuery(null, type); + let url = this.urlForQuery(null, type); + if (query.tab === 'current') { + url = `${url}/monthly`; + query = null; + } // API accepts start and end as query params return this.ajax(url, 'GET', { data: query }).then(resp => { let response = resp || {}; diff --git a/ui/app/adapters/metrics/config.js b/ui/app/adapters/clients/config.js similarity index 100% rename from ui/app/adapters/metrics/config.js rename to ui/app/adapters/clients/config.js diff --git a/ui/app/components/pricing-metrics-config.js b/ui/app/components/clients/config.js similarity index 82% rename from ui/app/components/pricing-metrics-config.js rename to ui/app/components/clients/config.js index a61ef3d3420cf..9b093ecae603c 100644 --- a/ui/app/components/pricing-metrics-config.js +++ b/ui/app/components/clients/config.js @@ -1,12 +1,12 @@ /** - * @module PricingMetricsConfig - * PricingMetricsConfig components are used to show and edit the pricing metrics config information. + * @module ClientsConfig + * ClientsConfig components are used to show and edit the client count config information. * * @example * ```js - * + * * ``` - * @param {object} model - model is the DS metrics/config model which should be passed in + * @param {object} model - model is the DS clients/config model which should be passed in * @param {string} [mode=show] - mode is either show or edit. Show results in a table with the config, show has a form. */ @@ -16,7 +16,7 @@ import { inject as service } from '@ember/service'; import { tracked } from '@glimmer/tracking'; import { task } from 'ember-concurrency'; -export default class PricingMetricsConfigComponent extends Component { +export default class ConfigComponent extends Component { @service router; @tracked mode = 'show'; @tracked modalOpen = false; @@ -57,7 +57,7 @@ export default class PricingMetricsConfigComponent extends Component { this.error = err.message; return; } - this.router.transitionTo('vault.cluster.metrics.config'); + this.router.transitionTo('vault.cluster.clients.index'); }).drop()) save; diff --git a/ui/app/components/clients/history.js b/ui/app/components/clients/history.js new file mode 100644 index 0000000000000..6a71ed6da5e9e --- /dev/null +++ b/ui/app/components/clients/history.js @@ -0,0 +1,26 @@ +import Component from '@glimmer/component'; + +export default class HistoryComponent extends Component { + max_namespaces = 10; + + get dataset() { + if (!this.args.model.activity || !this.args.model.activity.byNamespace) { + return null; + } + let dataset = this.args.model.activity.byNamespace; + // Filter out root data + dataset = dataset.filter(item => { + return item.namespace_id != 'root'; + }); + // Show only top 10 namespaces + dataset = dataset.slice(0, this.max_namespaces); + return dataset.map(d => { + return { + label: d['namespace_path'], + non_entity_tokens: d['counts']['non_entity_tokens'], + distinct_entities: d['counts']['distinct_entities'], + total: d['counts']['clients'], + }; + }); + } +} diff --git a/ui/app/components/pricing-metrics-dates.js b/ui/app/components/pricing-metrics-dates.js index 2189ae0f8f438..0cc7a3b7653bd 100644 --- a/ui/app/components/pricing-metrics-dates.js +++ b/ui/app/components/pricing-metrics-dates.js @@ -18,16 +18,7 @@ import { set, computed } from '@ember/object'; import { inject as service } from '@ember/service'; import Component from '@ember/component'; -import { - differenceInSeconds, - isValid, - subMonths, - startOfToday, - format, - endOfMonth, - startOfMonth, - isBefore, -} from 'date-fns'; +import { subMonths, startOfToday, format, endOfMonth, startOfMonth, isBefore } from 'date-fns'; import layout from '../templates/components/pricing-metrics-dates'; import { parseDateString } from 'vault/helpers/parse-date-string'; @@ -69,35 +60,6 @@ export default Component.extend({ } }), - // We don't want the warning to show when inputs are being updated before query is made - /* eslint-disable-next-line ember/require-computed-property-dependencies */ - showResultsWarning: computed('resultEnd', 'resultStart', function() { - if (!this.queryStart || !this.queryEnd || !this.resultStart || !this.resultEnd) { - return false; - } - const resultStart = new Date(this.resultStart); - const resultEnd = new Date(this.resultEnd); - let queryStart, queryEnd; - try { - queryStart = parseDateString(this.queryStart, '-'); - queryEnd = parseDateString(this.queryEnd, '-'); - } catch (e) { - // Log error for debugging purposes - console.debug(e); - } - - if (!queryStart || !queryEnd || !isValid(resultStart) || !isValid(resultEnd)) { - return false; - } - if (Math.abs(differenceInSeconds(queryStart, resultStart)) >= 86400) { - return true; - } - if (Math.abs(differenceInSeconds(resultEnd, endOfMonth(queryEnd))) >= 86400) { - return true; - } - return false; - }), - error: computed('end', 'endDate', 'retentionMonths', 'start', 'startDate', function() { if (!this.startDate) { return 'Start date is invalid. Please use format MM/yyyy'; @@ -148,7 +110,7 @@ export default Component.extend({ handleQuery() { const start = format(this.startDate, 'MM-yyyy'); const end = format(this.endDate, 'MM-yyyy'); - this.router.transitionTo('vault.cluster.metrics', { + this.router.transitionTo('vault.cluster.clients', { queryParams: { start, end, diff --git a/ui/app/controllers/vault/cluster/clients/index.js b/ui/app/controllers/vault/cluster/clients/index.js new file mode 100644 index 0000000000000..8cb0262e7f832 --- /dev/null +++ b/ui/app/controllers/vault/cluster/clients/index.js @@ -0,0 +1,8 @@ +import Controller from '@ember/controller'; + +export default class ClientsController extends Controller { + queryParams = ['tab', 'start', 'end']; + tab = null; + start = null; + end = null; +} diff --git a/ui/app/controllers/vault/cluster/metrics/index.js b/ui/app/controllers/vault/cluster/metrics/index.js deleted file mode 100644 index e355af5b80848..0000000000000 --- a/ui/app/controllers/vault/cluster/metrics/index.js +++ /dev/null @@ -1,8 +0,0 @@ -import Controller from '@ember/controller'; - -export default Controller.extend({ - queryParams: ['start', 'end'], - - start: null, - end: null, -}); diff --git a/ui/app/models/metrics/activity.js b/ui/app/models/clients/activity.js similarity index 84% rename from ui/app/models/metrics/activity.js rename to ui/app/models/clients/activity.js index d220bf184ad30..ba88d9839d91a 100644 --- a/ui/app/models/metrics/activity.js +++ b/ui/app/models/clients/activity.js @@ -2,6 +2,7 @@ import Model, { attr } from '@ember-data/model'; export default Model.extend({ total: attr('object'), + byNamespace: attr('array'), endTime: attr('string'), startTime: attr('string'), }); diff --git a/ui/app/models/metrics/config.js b/ui/app/models/clients/config.js similarity index 100% rename from ui/app/models/metrics/config.js rename to ui/app/models/clients/config.js diff --git a/ui/app/router.js b/ui/app/router.js index ee964bfb77ac5..090def1fa2acc 100644 --- a/ui/app/router.js +++ b/ui/app/router.js @@ -15,9 +15,8 @@ Router.map(function() { this.route('logout'); this.mount('open-api-explorer', { path: '/api-explorer' }); this.route('license'); - this.route('metrics', function() { + this.route('clients', function() { this.route('index', { path: '/' }); - this.route('config'); this.route('edit'); }); this.route('storage', { path: '/storage/raft' }); diff --git a/ui/app/routes/vault/cluster/metrics/edit.js b/ui/app/routes/vault/cluster/clients/edit.js similarity index 62% rename from ui/app/routes/vault/cluster/metrics/edit.js rename to ui/app/routes/vault/cluster/clients/edit.js index ddb4f482a2157..51f0bb9b86c43 100644 --- a/ui/app/routes/vault/cluster/metrics/edit.js +++ b/ui/app/routes/vault/cluster/clients/edit.js @@ -2,6 +2,6 @@ import Route from '@ember/routing/route'; export default Route.extend({ model() { - return this.store.queryRecord('metrics/config', {}); + return this.store.queryRecord('clients/config', {}); }, }); diff --git a/ui/app/routes/vault/cluster/metrics/index.js b/ui/app/routes/vault/cluster/clients/index.js similarity index 51% rename from ui/app/routes/vault/cluster/metrics/index.js rename to ui/app/routes/vault/cluster/clients/index.js index 59e7b5a3cd9cd..b08d01e0783ce 100644 --- a/ui/app/routes/vault/cluster/metrics/index.js +++ b/ui/app/routes/vault/cluster/clients/index.js @@ -4,23 +4,27 @@ import { hash } from 'rsvp'; import { getTime } from 'date-fns'; import { parseDateString } from 'vault/helpers/parse-date-string'; -const getActivityParams = ({ start, end }) => { +const getActivityParams = ({ tab, start, end }) => { // Expects MM-yyyy format // TODO: minStart, maxEnd let params = {}; - if (start) { - let startDate = parseDateString(start); - if (startDate) { - // TODO: Replace with formatRFC3339 when date-fns is updated - // converts to milliseconds, divide by 1000 to get epoch - params.start_time = getTime(startDate) / 1000; + if (tab === 'current') { + params.tab = tab; + } else if (tab === 'history') { + if (start) { + let startDate = parseDateString(start); + if (startDate) { + // TODO: Replace with formatRFC3339 when date-fns is updated + // converts to milliseconds, divide by 1000 to get epoch + params.start_time = getTime(startDate) / 1000; + } } - } - if (end) { - let endDate = parseDateString(end); - if (endDate) { - // TODO: Replace with formatRFC3339 when date-fns is updated - params.end_time = getTime(endDate) / 1000; + if (end) { + let endDate = parseDateString(end); + if (endDate) { + // TODO: Replace with formatRFC3339 when date-fns is updated + params.end_time = getTime(endDate) / 1000; + } } } return params; @@ -28,6 +32,9 @@ const getActivityParams = ({ start, end }) => { export default Route.extend(ClusterRoute, { queryParams: { + tab: { + refreshModel: true, + }, start: { refreshModel: true, }, @@ -37,13 +44,13 @@ export default Route.extend(ClusterRoute, { }, model(params) { - let config = this.store.queryRecord('metrics/config', {}).catch(e => { + let config = this.store.queryRecord('clients/config', {}).catch(e => { console.debug(e); // swallowing error so activity can show if no config permissions return {}; }); const activityParams = getActivityParams(params); - let activity = this.store.queryRecord('metrics/activity', activityParams); + let activity = this.store.queryRecord('clients/activity', activityParams); return hash({ queryStart: params.start, diff --git a/ui/app/routes/vault/cluster/metrics/config.js b/ui/app/routes/vault/cluster/metrics/config.js deleted file mode 100644 index ed1a32d5e4e44..0000000000000 --- a/ui/app/routes/vault/cluster/metrics/config.js +++ /dev/null @@ -1,8 +0,0 @@ -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', {}); - }, -}); diff --git a/ui/app/serializers/metrics/activity.js b/ui/app/serializers/clients/activity.js similarity index 100% rename from ui/app/serializers/metrics/activity.js rename to ui/app/serializers/clients/activity.js diff --git a/ui/app/serializers/metrics/config.js b/ui/app/serializers/clients/config.js similarity index 100% rename from ui/app/serializers/metrics/config.js rename to ui/app/serializers/clients/config.js diff --git a/ui/app/services/permissions.js b/ui/app/services/permissions.js index c58bb3f39317e..aa67e2128ce73 100644 --- a/ui/app/services/permissions.js +++ b/ui/app/services/permissions.js @@ -29,7 +29,7 @@ const API_PATHS = { seal: 'sys/seal', raft: 'sys/storage/raft/configuration', }, - metrics: { + clients: { activity: 'sys/internal/counters/activity', config: 'sys/internal/counters/config', }, diff --git a/ui/app/styles/components/bar-chart.scss b/ui/app/styles/components/bar-chart.scss index 1cc9bc12689e8..44458d04c58cc 100644 --- a/ui/app/styles/components/bar-chart.scss +++ b/ui/app/styles/components/bar-chart.scss @@ -7,14 +7,11 @@ > div.is-border { border: 0.3px solid $ui-gray-200; - width: 94%; - margin-left: 3%; margin-bottom: $spacing-xxs; } } .chart-header { - margin-left: $spacing-l; display: grid; grid-template-columns: 3fr 1fr; @@ -47,7 +44,7 @@ } .bar-chart-container { - padding: $spacing-m $spacing-l $spacing-m $spacing-l; + padding: $spacing-m 0; } .bar-chart { diff --git a/ui/app/styles/components/stat-text.scss b/ui/app/styles/components/stat-text.scss index 814d8a87bedb1..efd76fa62140a 100644 --- a/ui/app/styles/components/stat-text.scss +++ b/ui/app/styles/components/stat-text.scss @@ -1,5 +1,8 @@ .stat-text-container { line-height: normal; + height: 100%; + display: flex; + flex-direction: column; &.l, &.m { @@ -13,6 +16,7 @@ font-weight: $font-weight-normal; color: $ui-gray-700; line-height: inherit; + flex-grow: 1; } .stat-value { font-size: $size-3; diff --git a/ui/app/templates/components/pricing-metrics-config.hbs b/ui/app/templates/components/clients/config.hbs similarity index 98% rename from ui/app/templates/components/pricing-metrics-config.hbs rename to ui/app/templates/components/clients/config.hbs index b6813735770cf..0551956de61af 100644 --- a/ui/app/templates/components/pricing-metrics-config.hbs +++ b/ui/app/templates/components/clients/config.hbs @@ -54,7 +54,8 @@ Save Cancel diff --git a/ui/app/templates/components/clients/history.hbs b/ui/app/templates/components/clients/history.hbs new file mode 100644 index 0000000000000..209b29f90fbe1 --- /dev/null +++ b/ui/app/templates/components/clients/history.hbs @@ -0,0 +1,94 @@ +{{#if (eq @model.config.queriesAvailable false)}} + {{#if (eq @model.config.enabled "On")}} + + {{else}} + + {{#if @model.config.configPath.canUpdate}} +

Go to configuration

+ {{/if}} +
+ {{/if}} +{{else}} +
+ {{#if (eq @tab "current")}} +

Current month

+

The below data is for the current month starting from the first day. For historical data, see the monthly history tab.

+ {{#if (eq @model.config.enabled 'Off')}} + + {{#if @model.config.configPath.canUpdate}} + Go to configuration + {{/if}} + + {{/if}} + {{else}} + {{#if (eq @model.config.enabled 'Off')}} + + Tracking is currently disabled and data is not being collected. Historical data can be searched, but you will need to edit the configuration to enable tracking again. + + {{/if}} +

Monthly history

+

This data is presented by full month. If there is data missing, it's possible that tracking was turned off at the time. Vault will only show data for contiguous blocks of time during which tracking was on.

+ + {{/if}} + {{#unless @model.activity.total}} + {{#if (eq @tab "current")}} + {{#if (eq @model.config.enabled 'On')}} + + {{/if}} + {{else}} + + {{/if}} + {{else}} +
+
+
+
+

Total usage

+

These totals are within this namespace and all its children.

+
+ + Learn more + +
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+ + +
+
+ +
+
+ {{/unless}} +
+{{/if}} diff --git a/ui/app/templates/components/cluster-info.hbs b/ui/app/templates/components/cluster-info.hbs index c2a28a49cbd49..c404841d7f39c 100644 --- a/ui/app/templates/components/cluster-info.hbs +++ b/ui/app/templates/components/cluster-info.hbs @@ -116,12 +116,12 @@ {{/if}} {{/if}} - {{#if ( and (has-permission 'metrics' routeParams='activity') (not @cluster.dr.isSecondary) this.auth.currentToken)}} + {{#if ( and (has-permission 'clients' routeParams='activity') (not @cluster.dr.isSecondary) this.auth.currentToken)}}