mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-31 10:37:56 +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
	 Chelsea Shaw
					Chelsea Shaw