mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-31 02:28:09 +00:00 
			
		
		
		
	UI: wrap client count card in permission conditional (#26848)
* consistent timestamp format * wrap client count card in permissions * add test * add changelog * move tests into module, add more! * final test cleanup, stub permissions manually without helper * use current_billing_period for dashboard, add tests * update mirage to handle new client param * Update ui/app/components/dashboard/client-count-card.js
This commit is contained in:
		
							
								
								
									
										3
									
								
								changelog/26848.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								changelog/26848.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | ```release-note:improvement | ||||||
|  | ui: Hide dashboard client count card if user does not have permission to view clients. | ||||||
|  | ``` | ||||||
| @@ -11,6 +11,11 @@ export default class ActivityAdapter extends ApplicationAdapter { | |||||||
|   // create date object from user's input using Date.UTC() then send to backend as unix |   // create date object from user's input using Date.UTC() then send to backend as unix | ||||||
|   // time params from the backend are formatted as a zulu timestamp |   // time params from the backend are formatted as a zulu timestamp | ||||||
|   formatQueryParams(queryParams) { |   formatQueryParams(queryParams) { | ||||||
|  |     if (queryParams?.current_billing_period) { | ||||||
|  |       // { current_billing_period: true } automatically queries the activity log | ||||||
|  |       // from the builtin license start timestamp to the current month | ||||||
|  |       return queryParams; | ||||||
|  |     } | ||||||
|     let { start_time, end_time } = queryParams; |     let { start_time, end_time } = queryParams; | ||||||
|     start_time = start_time.timestamp || formatDateObject(start_time); |     start_time = start_time.timestamp || formatDateObject(start_time); | ||||||
|     end_time = end_time.timestamp || formatDateObject(end_time, true); |     end_time = end_time.timestamp || formatDateObject(end_time, true); | ||||||
|   | |||||||
| @@ -14,11 +14,7 @@ | |||||||
|  |  | ||||||
|   <hr class="has-background-gray-100" /> |   <hr class="has-background-gray-100" /> | ||||||
|  |  | ||||||
|   {{#if this.noActivityData}} |   {{#if this.hasActivity}} | ||||||
|     {{! This will likely not be show since the client activity api was changed to always return data. In the past it |  | ||||||
|   would return no activity data. Adding this empty state here to match the current client count behavior }} |  | ||||||
|     <Clients::NoData @config={{this.clientConfig}} /> |  | ||||||
|   {{else}} |  | ||||||
|     {{#if this.fetchClientActivity.isRunning}} |     {{#if this.fetchClientActivity.isRunning}} | ||||||
|       <VaultLogoSpinner /> |       <VaultLogoSpinner /> | ||||||
|     {{else}} |     {{else}} | ||||||
| @@ -44,5 +40,9 @@ | |||||||
|         </small> |         </small> | ||||||
|       </div> |       </div> | ||||||
|     {{/if}} |     {{/if}} | ||||||
|  |   {{else}} | ||||||
|  |     {{! This will likely never show since the clients activity api has changed to always return data. In the past it | ||||||
|  |   would return no activity data. Adding this empty state here to match the current client count behavior }} | ||||||
|  |     <Clients::NoData @config={{hash enabled="On"}} /> | ||||||
|   {{/if}} |   {{/if}} | ||||||
| </Hds::Card::Container> | </Hds::Card::Container> | ||||||
| @@ -9,27 +9,22 @@ import { task } from 'ember-concurrency'; | |||||||
| import { waitFor } from '@ember/test-waiters'; | import { waitFor } from '@ember/test-waiters'; | ||||||
| import { tracked } from '@glimmer/tracking'; | import { tracked } from '@glimmer/tracking'; | ||||||
| import { service } from '@ember/service'; | import { service } from '@ember/service'; | ||||||
| import { setStartTimeQuery } from 'core/utils/client-count-utils'; | import { parseAPITimestamp } from 'core/utils/date-formatters'; | ||||||
| import { dateFormat } from 'core/helpers/date-format'; |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * @module DashboardClientCountCard |  * @module DashboardClientCountCard | ||||||
|  * DashboardClientCountCard component are used to display total and new client count information |  * DashboardClientCountCard component are used to display total and new client count information | ||||||
|  * |  * | ||||||
|  * @example |  * @example | ||||||
|  * |  * <Dashboard::ClientCountCard /> | ||||||
|  * <Dashboard::ClientCountCard @isEnterprise={{@version.isEnterprise}} /> |  | ||||||
|  * |  | ||||||
|  * @param {boolean} isEnterprise - used for setting the start time for the activity log query |  | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| export default class DashboardClientCountCard extends Component { | export default class DashboardClientCountCard extends Component { | ||||||
|   @service store; |   @service store; | ||||||
|  |  | ||||||
|   clientConfig = null; |  | ||||||
|   licenseStartTime = null; |  | ||||||
|   @tracked activityData = null; |   @tracked activityData = null; | ||||||
|   @tracked updatedAt = timestamp.now().toISOString(); |   @tracked hasActivity = false; | ||||||
|  |   @tracked updatedAt = null; | ||||||
|  |  | ||||||
|   constructor() { |   constructor() { | ||||||
|     super(...arguments); |     super(...arguments); | ||||||
| @@ -41,12 +36,11 @@ export default class DashboardClientCountCard extends Component { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   get statSubText() { |   get statSubText() { | ||||||
|     const format = (date) => dateFormat([date, 'MMM yyyy'], {}); |     const format = (date) => parseAPITimestamp(date, 'MMM yyyy'); | ||||||
|     return this.licenseStartTime |     const { startTime, endTime } = this.activityData; | ||||||
|  |     return startTime && endTime | ||||||
|       ? { |       ? { | ||||||
|           total: `The number of clients in this billing period (${format(this.licenseStartTime)} - ${format( |           total: `The number of clients in this billing period (${format(startTime)} - ${format(endTime)}).`, | ||||||
|             this.updatedAt |  | ||||||
|           )}).`, |  | ||||||
|           new: 'The number of clients new to Vault in the current month.', |           new: 'The number of clients new to Vault in the current month.', | ||||||
|         } |         } | ||||||
|       : { total: 'No total client data available.', new: 'No new client data available.' }; |       : { total: 'No total client data available.', new: 'No new client data available.' }; | ||||||
| @@ -58,20 +52,11 @@ export default class DashboardClientCountCard extends Component { | |||||||
|     if (e) e.preventDefault(); |     if (e) e.preventDefault(); | ||||||
|     this.updatedAt = timestamp.now().toISOString(); |     this.updatedAt = timestamp.now().toISOString(); | ||||||
|  |  | ||||||
|     if (!this.clientConfig) { |  | ||||||
|       // set config and license start time when component initializes |  | ||||||
|       this.clientConfig = yield this.store.queryRecord('clients/config', {}).catch(() => {}); |  | ||||||
|       this.licenseStartTime = setStartTimeQuery(this.args.isEnterprise, this.clientConfig); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // only make the network request if we have a start_time |  | ||||||
|     if (!this.licenseStartTime) return {}; |  | ||||||
|     try { |     try { | ||||||
|       this.activityData = yield this.store.queryRecord('clients/activity', { |       this.activityData = yield this.store.queryRecord('clients/activity', { | ||||||
|         start_time: { timestamp: this.licenseStartTime }, |         current_billing_period: true, | ||||||
|         end_time: { timestamp: this.updatedAt }, |  | ||||||
|       }); |       }); | ||||||
|       this.noActivityData = this.activityData.activity.id === 'no-data' ? true : false; |       this.hasActivity = this.activityData.id === 'no-data' ? false : true; | ||||||
|     } catch (error) { |     } catch (error) { | ||||||
|       this.error = error; |       this.error = error; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -9,10 +9,10 @@ | |||||||
|   <div class="is-flex-row gap-24"> |   <div class="is-flex-row gap-24"> | ||||||
|     {{#if (and @version.isEnterprise @isRootNamespace)}} |     {{#if (and @version.isEnterprise @isRootNamespace)}} | ||||||
|       <div class="is-flex-column is-flex-1 gap-24"> |       <div class="is-flex-column is-flex-1 gap-24"> | ||||||
|         <Dashboard::ClientCountCard @isEnterprise={{@version.isEnterprise}} /> |         {{#if (has-permission "clients" routeParams="activity")}} | ||||||
|         {{#if |           <Dashboard::ClientCountCard /> | ||||||
|           (and @isRootNamespace (has-permission "status" routeParams="replication") (not (is-empty-value @replication))) |         {{/if}} | ||||||
|         }} |         {{#if (and (has-permission "status" routeParams="replication") (not (is-empty-value @replication)))}} | ||||||
|           <Dashboard::ReplicationCard |           <Dashboard::ReplicationCard | ||||||
|             @replication={{@replication}} |             @replication={{@replication}} | ||||||
|             @version={{@version}} |             @version={{@version}} | ||||||
|   | |||||||
| @@ -79,7 +79,7 @@ | |||||||
|       /> |       /> | ||||||
|       <small class="has-left-margin-xs has-text-grey"> |       <small class="has-left-margin-xs has-text-grey"> | ||||||
|         Updated |         Updated | ||||||
|         {{date-format @updatedAt "MMM dd, yyyy hh:mm:ss"}} |         {{date-format @updatedAt "MMM d yyyy, h:mm:ss aaa" withTimeZone=true}} | ||||||
|       </small> |       </small> | ||||||
|     </div> |     </div> | ||||||
|   {{else}} |   {{else}} | ||||||
|   | |||||||
| @@ -216,6 +216,12 @@ export default function (server) { | |||||||
|  |  | ||||||
|   server.get('/sys/internal/counters/activity', (schema, req) => { |   server.get('/sys/internal/counters/activity', (schema, req) => { | ||||||
|     let { start_time, end_time } = req.queryParams; |     let { start_time, end_time } = req.queryParams; | ||||||
|  |     if (req.queryParams.current_billing_period) { | ||||||
|  |       // { current_billing_period: true } automatically queries the activity log | ||||||
|  |       // from the builtin license start timestamp to the current month | ||||||
|  |       start_time = LICENSE_START.toISOString(); | ||||||
|  |       end_time = STATIC_NOW.toISOString(); | ||||||
|  |     } | ||||||
|     // backend returns a timestamp if given unix time, so first convert to timestamp string here |     // backend returns a timestamp if given unix time, so first convert to timestamp string here | ||||||
|     if (!start_time.includes('T')) start_time = fromUnixTime(start_time).toISOString(); |     if (!start_time.includes('T')) start_time = fromUnixTime(start_time).toISOString(); | ||||||
|     if (!end_time.includes('T')) end_time = fromUnixTime(end_time).toISOString(); |     if (!end_time.includes('T')) end_time = fromUnixTime(end_time).toISOString(); | ||||||
|   | |||||||
| @@ -9,11 +9,12 @@ import { render, click } from '@ember/test-helpers'; | |||||||
| import { hbs } from 'ember-cli-htmlbars'; | import { hbs } from 'ember-cli-htmlbars'; | ||||||
| import { setupMirage } from 'ember-cli-mirage/test-support'; | import { setupMirage } from 'ember-cli-mirage/test-support'; | ||||||
| import sinon from 'sinon'; | import sinon from 'sinon'; | ||||||
| import { LICENSE_START, STATIC_NOW } from 'vault/mirage/handlers/clients'; | import { STATIC_NOW } from 'vault/mirage/handlers/clients'; | ||||||
| import timestamp from 'core/utils/timestamp'; | import timestamp from 'core/utils/timestamp'; | ||||||
| import { ACTIVITY_RESPONSE_STUB } from 'vault/tests/helpers/clients/client-count-helpers'; | import { ACTIVITY_RESPONSE_STUB } from 'vault/tests/helpers/clients/client-count-helpers'; | ||||||
| import { formatNumber } from 'core/helpers/format-number'; | import { formatNumber } from 'core/helpers/format-number'; | ||||||
| import { CLIENT_COUNT } from 'vault/tests/helpers/clients/client-count-selectors'; | import { CLIENT_COUNT } from 'vault/tests/helpers/clients/client-count-selectors'; | ||||||
|  | import { GENERAL } from 'vault/tests/helpers/general-selectors'; | ||||||
|  |  | ||||||
| module('Integration | Component | dashboard/client-count-card', function (hooks) { | module('Integration | Component | dashboard/client-count-card', function (hooks) { | ||||||
|   setupRenderingTest(hooks); |   setupRenderingTest(hooks); | ||||||
| @@ -21,37 +22,31 @@ module('Integration | Component | dashboard/client-count-card', function (hooks) | |||||||
|  |  | ||||||
|   test('it should display client count information', async function (assert) { |   test('it should display client count information', async function (assert) { | ||||||
|     sinon.replace(timestamp, 'now', sinon.fake.returns(STATIC_NOW)); |     sinon.replace(timestamp, 'now', sinon.fake.returns(STATIC_NOW)); | ||||||
|     assert.expect(6); |     assert.expect(5); | ||||||
|     const { months, total } = ACTIVITY_RESPONSE_STUB; |     const { months, total } = ACTIVITY_RESPONSE_STUB; | ||||||
|     const [latestMonth] = months.slice(-1); |     const [latestMonth] = months.slice(-1); | ||||||
|     this.server.get('sys/internal/counters/activity', () => { |     this.server.get('sys/internal/counters/activity', (schema, req) => { | ||||||
|       // this assertion should be hit twice, once initially and then again clicking 'refresh' |       // this assertion should be hit twice, once initially and then again clicking 'refresh' | ||||||
|       assert.true(true, 'makes request to sys/internal/counters/activity'); |       assert.propEqual( | ||||||
|  |         req.queryParams, | ||||||
|  |         { current_billing_period: 'true' }, | ||||||
|  |         'it makes request to sys/internal/counters/activity with builtin license start time' | ||||||
|  |       ); | ||||||
|       return { |       return { | ||||||
|         request_id: 'some-activity-id', |         request_id: 'some-activity-id', | ||||||
|         data: ACTIVITY_RESPONSE_STUB, |         data: ACTIVITY_RESPONSE_STUB, | ||||||
|       }; |       }; | ||||||
|     }); |     }); | ||||||
|     this.server.get('sys/internal/counters/config', function () { |  | ||||||
|       assert.true(true, 'sys/internal/counters/config'); |  | ||||||
|       return { |  | ||||||
|         request_id: 'some-config-id', |  | ||||||
|         data: { |  | ||||||
|           billing_start_timestamp: LICENSE_START.toISOString(), |  | ||||||
|         }, |  | ||||||
|       }; |  | ||||||
|     }); |  | ||||||
|  |  | ||||||
|     await render(hbs`<Dashboard::ClientCountCard @isEnterprise={{true}} />`); |     await render(hbs`<Dashboard::ClientCountCard />`); | ||||||
|     assert.dom('[data-test-client-count-title]').hasText('Client count'); |     assert.dom('[data-test-client-count-title]').hasText('Client count'); | ||||||
|     assert |     assert | ||||||
|       .dom(CLIENT_COUNT.statText('Total')) |       .dom(CLIENT_COUNT.statText('Total')) | ||||||
|       .hasText( |       .hasText( | ||||||
|         `Total The number of clients in this billing period (Jul 2023 - Jan 2024). ${formatNumber([ |         `Total The number of clients in this billing period (Aug 2023 - Sep 2023). ${formatNumber([ | ||||||
|           total.clients, |           total.clients, | ||||||
|         ])}` |         ])}` | ||||||
|       ); |       ); | ||||||
|  |  | ||||||
|     assert |     assert | ||||||
|       .dom(CLIENT_COUNT.statText('New')) |       .dom(CLIENT_COUNT.statText('New')) | ||||||
|       .hasText( |       .hasText( | ||||||
| @@ -64,30 +59,35 @@ module('Integration | Component | dashboard/client-count-card', function (hooks) | |||||||
|     await click('[data-test-refresh]'); |     await click('[data-test-refresh]'); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   test('it does not query activity for community edition', async function (assert) { |   test('it shows no data subtext if no start or end timestamp', async function (assert) { | ||||||
|     assert.expect(3); |     assert.expect(2); | ||||||
|     // in the template this component is wrapped in an isEnterprise conditional so this |     // as far as I know, responses will always have a start/end time | ||||||
|     // state is currently not possible, adding a test to safeguard against introducing |     // stubbing this unrealistic response just to test component subtext logic | ||||||
|     // regressions during future refactors |     this.server.get('sys/internal/counters/activity', () => { | ||||||
|     this.server.get( |  | ||||||
|       'sys/internal/counters/activity', |  | ||||||
|       () => new Error('uh oh! a request was made to sys/internal/counters/activity') |  | ||||||
|     ); |  | ||||||
|     this.server.get('sys/internal/counters/config', function () { |  | ||||||
|       assert.true(true, 'sys/internal/counters/config'); |  | ||||||
|       return { |       return { | ||||||
|         request_id: 'some-config-id', |         request_id: 'some-activity-id', | ||||||
|         data: { |         data: { by_namespace: [], months: [], total: {} }, | ||||||
|           billing_start_timestamp: '0001-01-01T00:00:00Z', |  | ||||||
|         }, |  | ||||||
|       }; |       }; | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     await render(hbs`<Dashboard::ClientCountCard @isEnterprise={{false}} />`); |     await render(hbs`<Dashboard::ClientCountCard />`); | ||||||
|     assert.dom(CLIENT_COUNT.statText('Total')).hasText('Total No total client data available. -'); |     assert.dom(CLIENT_COUNT.statText('Total')).hasText('Total No total client data available. -'); | ||||||
|     assert.dom(CLIENT_COUNT.statText('New')).hasText('New No new client data available. -'); |     assert.dom(CLIENT_COUNT.statText('New')).hasText('New No new client data available. -'); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|     // attempt second request to /activity but component task should return instead of hitting endpoint |   test('it shows empty state if no activity data', async function (assert) { | ||||||
|     await click('[data-test-refresh]'); |     // the activity response has changed and now should ALWAYS return something | ||||||
|  |     // but adding this test until we update the adapter to reflect that | ||||||
|  |     assert.expect(3); | ||||||
|  |     this.server.get('sys/internal/counters/activity', () => { | ||||||
|  |       assert.true(true, 'makes request to sys/internal/counters/activity'); | ||||||
|  |       return { data: {} }; | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     await render(hbs`<Dashboard::ClientCountCard />`); | ||||||
|  |     assert.dom(GENERAL.emptyStateTitle).hasText('No data received'); | ||||||
|  |     assert | ||||||
|  |       .dom(GENERAL.emptyStateMessage) | ||||||
|  |       .hasText('Tracking is turned on and Vault is gathering data. It should appear here within 30 minutes.'); | ||||||
|   }); |   }); | ||||||
| }); | }); | ||||||
|   | |||||||
| @@ -9,7 +9,6 @@ import { render } from '@ember/test-helpers'; | |||||||
| import { hbs } from 'ember-cli-htmlbars'; | import { hbs } from 'ember-cli-htmlbars'; | ||||||
| import { setupMirage } from 'ember-cli-mirage/test-support'; | import { setupMirage } from 'ember-cli-mirage/test-support'; | ||||||
| import { DASHBOARD } from 'vault/tests/helpers/components/dashboard/dashboard-selectors'; | import { DASHBOARD } from 'vault/tests/helpers/components/dashboard/dashboard-selectors'; | ||||||
| import { LICENSE_START } from 'vault/mirage/handlers/clients'; |  | ||||||
|  |  | ||||||
| module('Integration | Component | dashboard/overview', function (hooks) { | module('Integration | Component | dashboard/overview', function (hooks) { | ||||||
|   setupRenderingTest(hooks); |   setupRenderingTest(hooks); | ||||||
| @@ -17,7 +16,11 @@ module('Integration | Component | dashboard/overview', function (hooks) { | |||||||
|  |  | ||||||
|   hooks.beforeEach(function () { |   hooks.beforeEach(function () { | ||||||
|     this.store = this.owner.lookup('service:store'); |     this.store = this.owner.lookup('service:store'); | ||||||
|  |     this.permissions = this.owner.lookup('service:permissions'); | ||||||
|  |     this.version = this.owner.lookup('service:version'); | ||||||
|  |     this.version.version = '1.13.1+ent'; | ||||||
|  |     this.version.type = 'enterprise'; | ||||||
|  |     this.isRootNamespace = true; | ||||||
|     this.replication = { |     this.replication = { | ||||||
|       dr: { |       dr: { | ||||||
|         clusterId: '123', |         clusterId: '123', | ||||||
| @@ -61,28 +64,29 @@ module('Integration | Component | dashboard/overview', function (hooks) { | |||||||
|       ], |       ], | ||||||
|     }; |     }; | ||||||
|     this.refreshModel = () => {}; |     this.refreshModel = () => {}; | ||||||
|     this.server.get('sys/internal/counters/config', function () { |     this.renderComponent = async () => { | ||||||
|       return { |       return await render( | ||||||
|         request_id: 'some-config-id', |  | ||||||
|         data: { |  | ||||||
|           billing_start_timestamp: LICENSE_START.toISOString(), |  | ||||||
|         }, |  | ||||||
|       }; |  | ||||||
|     }); |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
|   test('it should show dashboard empty states', async function (assert) { |  | ||||||
|     this.version = this.owner.lookup('service:version'); |  | ||||||
|     this.version.version = '1.13.1'; |  | ||||||
|     this.isRootNamespace = true; |  | ||||||
|     await render( |  | ||||||
|         hbs` |         hbs` | ||||||
|         <Dashboard::Overview |         <Dashboard::Overview | ||||||
|  |           @secretsEngines={{this.secretsEngines}} | ||||||
|  |           @vaultConfiguration={{this.vaultConfiguration}} | ||||||
|  |           @replication={{this.replication}} | ||||||
|           @version={{this.version}} |           @version={{this.version}} | ||||||
|           @isRootNamespace={{this.isRootNamespace}} |           @isRootNamespace={{this.isRootNamespace}} | ||||||
|           @refreshModel={{this.refreshModel}} /> |           @refreshModel={{this.refreshModel}}  | ||||||
|  |           @replicationUpdatedAt={{this.replicationUpdatedAt}} | ||||||
|  |           /> | ||||||
|       ` |       ` | ||||||
|       ); |       ); | ||||||
|  |     }; | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   test('it should show dashboard empty states in root namespace', async function (assert) { | ||||||
|  |     this.version.version = '1.13.1'; | ||||||
|  |     this.secretsEngines = null; | ||||||
|  |     this.replication = null; | ||||||
|  |     this.vaultConfiguration = null; | ||||||
|  |     await this.renderComponent(); | ||||||
|     assert.dom(DASHBOARD.cardHeader('Vault version')).exists(); |     assert.dom(DASHBOARD.cardHeader('Vault version')).exists(); | ||||||
|     assert.dom(DASHBOARD.cardName('secrets-engines')).exists(); |     assert.dom(DASHBOARD.cardName('secrets-engines')).exists(); | ||||||
|     assert.dom(DASHBOARD.emptyState('secrets-engines')).exists(); |     assert.dom(DASHBOARD.emptyState('secrets-engines')).exists(); | ||||||
| @@ -94,22 +98,15 @@ module('Integration | Component | dashboard/overview', function (hooks) { | |||||||
|     assert.dom(DASHBOARD.cardName('client-count')).doesNotExist(); |     assert.dom(DASHBOARD.cardName('client-count')).doesNotExist(); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   test('it should hide client count and replication card on community', async function (assert) { |   module('client count and replication card', function () { | ||||||
|     this.version = this.owner.lookup('service:version'); |     test('it should hide cards on community in root namespace', async function (assert) { | ||||||
|       this.version.version = '1.13.1'; |       this.version.version = '1.13.1'; | ||||||
|     this.isRootNamespace = true; |       this.version.type = 'community'; | ||||||
|  |       this.server.get( | ||||||
|     await render( |         'sys/internal/counters/activity', | ||||||
|       hbs` |         () => new Error('uh oh! a request was made to sys/internal/counters/activity') | ||||||
|         <Dashboard::Overview |  | ||||||
|           @secretsEngines={{this.secretsEngines}} |  | ||||||
|           @vaultConfiguration={{this.vaultConfiguration}} |  | ||||||
|           @replication={{this.replication}} |  | ||||||
|           @version={{this.version}} |  | ||||||
|           @isRootNamespace={{this.isRootNamespace}} |  | ||||||
|           @refreshModel={{this.refreshModel}} /> |  | ||||||
|       ` |  | ||||||
|       ); |       ); | ||||||
|  |       await this.renderComponent(); | ||||||
|  |  | ||||||
|       assert.dom(DASHBOARD.cardHeader('Vault version')).exists(); |       assert.dom(DASHBOARD.cardHeader('Vault version')).exists(); | ||||||
|       assert.dom(DASHBOARD.cardName('secrets-engines')).exists(); |       assert.dom(DASHBOARD.cardName('secrets-engines')).exists(); | ||||||
| @@ -120,66 +117,104 @@ module('Integration | Component | dashboard/overview', function (hooks) { | |||||||
|       assert.dom(DASHBOARD.cardName('client-count')).doesNotExist(); |       assert.dom(DASHBOARD.cardName('client-count')).doesNotExist(); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|   test('it should show client count on enterprise w/ license', async function (assert) { |     test('it should hide cards on enterprise if permission but not in root namespace', async function (assert) { | ||||||
|     this.version = this.owner.lookup('service:version'); |       this.permissions.exactPaths = { | ||||||
|     this.version.version = '1.13.1+ent'; |         'sys/internal/counters/activity': { | ||||||
|     this.version.type = 'enterprise'; |           capabilities: ['read'], | ||||||
|     this.license = { |         }, | ||||||
|       autoloaded: { |         'sys/replication/status': { | ||||||
|         license_id: '7adbf1f4-56ef-35cd-3a6c-50ef2627865d', |           capabilities: ['read'], | ||||||
|         }, |         }, | ||||||
|       }; |       }; | ||||||
|  |       this.isRootNamespace = false; | ||||||
|  |       await this.renderComponent(); | ||||||
|  |       assert.dom(DASHBOARD.cardName('client-count')).doesNotExist(); | ||||||
|  |       assert.dom(DASHBOARD.cardName('replication')).doesNotExist(); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|     await render( |     test('it should show cards on enterprise if has permission and in root namespace', async function (assert) { | ||||||
|       hbs` |       this.permissions.exactPaths = { | ||||||
|       <Dashboard::Overview |         'sys/internal/counters/activity': { | ||||||
|       @secretsEngines={{this.secretsEngines}} |           capabilities: ['read'], | ||||||
|       @vaultConfiguration={{this.vaultConfiguration}} |         }, | ||||||
|       @replication={{this.replication}} |         'sys/replication/status': { | ||||||
|       @version={{this.version}} |           capabilities: ['read'], | ||||||
|       @isRootNamespace={{true}} |         }, | ||||||
|       @refreshModel={{this.refreshModel}} />` |       }; | ||||||
|     ); |       await this.renderComponent(); | ||||||
|       assert.dom(DASHBOARD.cardHeader('Vault version')).exists(); |       assert.dom(DASHBOARD.cardHeader('Vault version')).exists(); | ||||||
|       assert.dom(DASHBOARD.cardName('secrets-engines')).exists(); |       assert.dom(DASHBOARD.cardName('secrets-engines')).exists(); | ||||||
|       assert.dom(DASHBOARD.cardName('learn-more')).exists(); |       assert.dom(DASHBOARD.cardName('learn-more')).exists(); | ||||||
|       assert.dom(DASHBOARD.cardName('quick-actions')).exists(); |       assert.dom(DASHBOARD.cardName('quick-actions')).exists(); | ||||||
|       assert.dom(DASHBOARD.cardName('configuration-details')).exists(); |       assert.dom(DASHBOARD.cardName('configuration-details')).exists(); | ||||||
|       assert.dom(DASHBOARD.cardName('client-count')).exists(); |       assert.dom(DASHBOARD.cardName('client-count')).exists(); | ||||||
|  |       assert.dom(DASHBOARD.cardName('replication')).exists(); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|   test('it should hide replication on enterprise not on root namespace', async function (assert) { |     test('it should hide cards on enterprise in root namespace but no permission', async function (assert) { | ||||||
|     this.version = this.owner.lookup('service:version'); |       await this.renderComponent(); | ||||||
|     this.version.version = '1.13.1+ent'; |  | ||||||
|     this.version.type = 'enterprise'; |  | ||||||
|     this.isRootNamespace = false; |  | ||||||
|  |  | ||||||
|     await render( |  | ||||||
|       hbs` |  | ||||||
|       <Dashboard::Overview |  | ||||||
|         @version={{this.version}} |  | ||||||
|         @isRootNamespace={{this.isRootNamespace}} |  | ||||||
|         @secretsEngines={{this.secretsEngines}} |  | ||||||
|         @vaultConfiguration={{this.vaultConfiguration}} |  | ||||||
|         @replication={{this.replication}} |  | ||||||
|         @refreshModel={{this.refreshModel}} />` |  | ||||||
|     ); |  | ||||||
|  |  | ||||||
|     assert.dom(DASHBOARD.cardHeader('Vault version')).exists(); |  | ||||||
|     assert.dom('[data-test-badge-namespace]').exists(); |  | ||||||
|     assert.dom(DASHBOARD.cardName('secrets-engines')).exists(); |  | ||||||
|     assert.dom(DASHBOARD.cardName('learn-more')).exists(); |  | ||||||
|     assert.dom(DASHBOARD.cardName('quick-actions')).exists(); |  | ||||||
|     assert.dom(DASHBOARD.cardName('configuration-details')).exists(); |  | ||||||
|     assert.dom(DASHBOARD.cardName('replication')).doesNotExist(); |  | ||||||
|       assert.dom(DASHBOARD.cardName('client-count')).doesNotExist(); |       assert.dom(DASHBOARD.cardName('client-count')).doesNotExist(); | ||||||
|  |       assert.dom(DASHBOARD.cardName('replication')).doesNotExist(); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     test('it should hide cards on enterprise if no permission and not in root namespace', async function (assert) { | ||||||
|  |       this.isRootNamespace = false; | ||||||
|  |       await this.renderComponent(); | ||||||
|  |       assert.dom(DASHBOARD.cardName('client-count')).doesNotExist(); | ||||||
|  |       assert.dom(DASHBOARD.cardName('replication')).doesNotExist(); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     test('it should hide client count on enterprise in root namespace if no activity permission', async function (assert) { | ||||||
|  |       this.permissions.exactPaths = { | ||||||
|  |         'sys/internal/counters/activity': { | ||||||
|  |           capabilities: ['deny'], | ||||||
|  |         }, | ||||||
|  |         'sys/replication/status': { | ||||||
|  |           capabilities: ['read'], | ||||||
|  |         }, | ||||||
|  |       }; | ||||||
|  |  | ||||||
|  |       await this.renderComponent(); | ||||||
|  |       assert.dom(DASHBOARD.cardName('client-count')).doesNotExist(); | ||||||
|  |       assert.dom(DASHBOARD.cardName('replication')).exists(); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     test('it should hide replication on enterprise in root namespace if no replication status permission', async function (assert) { | ||||||
|  |       this.permissions.exactPaths = { | ||||||
|  |         'sys/internal/counters/activity': { | ||||||
|  |           capabilities: ['read'], | ||||||
|  |         }, | ||||||
|  |         'sys/replication/status': { | ||||||
|  |           capabilities: ['deny'], | ||||||
|  |         }, | ||||||
|  |       }; | ||||||
|  |  | ||||||
|  |       await this.renderComponent(); | ||||||
|  |       assert.dom(DASHBOARD.cardName('client-count')).exists(); | ||||||
|  |       assert.dom(DASHBOARD.cardName('replication')).doesNotExist(); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     test('it should hide replication on enterprise if has permission and in root namespace but is empty', async function (assert) { | ||||||
|  |       this.permissions.exactPaths = { | ||||||
|  |         'sys/internal/counters/activity': { | ||||||
|  |           capabilities: ['read'], | ||||||
|  |         }, | ||||||
|  |         'sys/replication/status': { | ||||||
|  |           capabilities: ['read'], | ||||||
|  |         }, | ||||||
|  |       }; | ||||||
|  |       this.replication = {}; | ||||||
|  |       await this.renderComponent(); | ||||||
|  |       assert.dom(DASHBOARD.cardName('client-count')).exists(); | ||||||
|  |       assert.dom(DASHBOARD.cardName('replication')).doesNotExist(); | ||||||
|  |     }); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   module('learn more card', function () { |   module('learn more card', function () { | ||||||
|     test('shows the learn more card on community', async function (assert) { |     test('shows the learn more card on community', async function (assert) { | ||||||
|       await render( |       this.version.version = '1.13.1'; | ||||||
|         hbs`<Dashboard::Overview @secretsEngines={{this.secretsEngines}} @vaultConfiguration={{this.vaultConfiguration}} @replication={{this.replication}} @refreshModel={{this.refreshModel}} />` |       this.version.type = 'community'; | ||||||
|       ); |       await this.renderComponent(); | ||||||
|  |  | ||||||
|       assert.dom('[data-test-learn-more-title]').hasText('Learn more'); |       assert.dom('[data-test-learn-more-title]').hasText('Learn more'); | ||||||
|       assert |       assert | ||||||
| @@ -193,32 +228,13 @@ module('Integration | Component | dashboard/overview', function (hooks) { | |||||||
|         .hasText("Don't see what you're looking for on this page? Let us know via our feedback form ."); |         .hasText("Don't see what you're looking for on this page? Let us know via our feedback form ."); | ||||||
|     }); |     }); | ||||||
|     test('shows the learn more card on enterprise', async function (assert) { |     test('shows the learn more card on enterprise', async function (assert) { | ||||||
|       this.version = this.owner.lookup('service:version'); |  | ||||||
|       this.version.version = '1.13.1+ent'; |  | ||||||
|       this.version.type = 'enterprise'; |  | ||||||
|       this.version.features = [ |       this.version.features = [ | ||||||
|         'Performance Replication', |         'Performance Replication', | ||||||
|         'DR Replication', |         'DR Replication', | ||||||
|         'Namespaces', |         'Namespaces', | ||||||
|         'Transform Secrets Engine', |         'Transform Secrets Engine', | ||||||
|       ]; |       ]; | ||||||
|       this.isRootNamespace = true; |       await this.renderComponent(); | ||||||
|       this.license = { |  | ||||||
|         autoloaded: { |  | ||||||
|           license_id: '7adbf1f4-56ef-35cd-3a6c-50ef2627865d', |  | ||||||
|         }, |  | ||||||
|       }; |  | ||||||
|       await render( |  | ||||||
|         hbs` |  | ||||||
|           <Dashboard::Overview |  | ||||||
|             @version={{this.version}} |  | ||||||
|             @isRootNamespace={{this.isRootNamespace}} |  | ||||||
|             @secretsEngines={{this.secretsEngines}} |  | ||||||
|             @vaultConfiguration={{this.vaultConfiguration}} |  | ||||||
|             @replication={{this.replication}} |  | ||||||
|             @refreshModel={{this.refreshModel}} /> |  | ||||||
|         ` |  | ||||||
|       ); |  | ||||||
|       assert.dom('[data-test-learn-more-title]').hasText('Learn more'); |       assert.dom('[data-test-learn-more-title]').hasText('Learn more'); | ||||||
|       assert |       assert | ||||||
|         .dom('[data-test-learn-more-subtext]') |         .dom('[data-test-learn-more-subtext]') | ||||||
|   | |||||||
| @@ -136,4 +136,18 @@ module('Unit | Adapter | clients activity', function (hooks) { | |||||||
|  |  | ||||||
|     this.store.queryRecord(this.modelName, queryParams); |     this.store.queryRecord(this.modelName, queryParams); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|  |   test('it sends current billing period boolean if provided', async function (assert) { | ||||||
|  |     assert.expect(1); | ||||||
|  |  | ||||||
|  |     this.server.get('sys/internal/counters/activity', (schema, req) => { | ||||||
|  |       assert.propEqual( | ||||||
|  |         req.queryParams, | ||||||
|  |         { current_billing_period: 'true' }, | ||||||
|  |         'it passes current_billing_period to query record' | ||||||
|  |       ); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     this.store.queryRecord(this.modelName, { current_billing_period: true }); | ||||||
|  |   }); | ||||||
| }); | }); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 claire bontempo
					claire bontempo