mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-29 09:42:25 +00:00
UI: Update dashboard client count query to use billing_start_timestamp (#26729)
* remvoe request tolicense in dashboard client count card * cleanup jsdoc * add changelog * use helper to set start time * update component tests * update overview test * update util tests * throw error instead, add comment to util file * fix accidentally removed type from import * remove typo arg from test component * rename token stat getter to avoid future typos
This commit is contained in:
3
changelog/26729.txt
Normal file
3
changelog/26729.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
```release-note:improvement
|
||||
ui (enterprise): Update dashboard to make activity log query using the same start time as the metrics overview
|
||||
```
|
||||
@@ -15,7 +15,7 @@
|
||||
<StatText
|
||||
@label="Total clients"
|
||||
@subText="The total number of entity and non-entity clients for this date range."
|
||||
@value={{this.totalUsageCounts.clients}}
|
||||
@value={{this.tokenStats.total}}
|
||||
@tooltipText="This number is the total for the queried date range. The chart displays a monthly breakdown of total clients per month."
|
||||
@size="l"
|
||||
/>
|
||||
@@ -100,21 +100,21 @@
|
||||
<StatText
|
||||
class="column"
|
||||
@label="Total clients"
|
||||
@value={{this.tokenUsageCounts.clients}}
|
||||
@value={{this.tokenStats.total}}
|
||||
@size="l"
|
||||
@subText="The number of clients which interacted with Vault during this month. This is Vault’s primary billing metric."
|
||||
/>
|
||||
<StatText
|
||||
class="column"
|
||||
@label="Entity"
|
||||
@value={{this.tokenUsageCounts.entity_clients}}
|
||||
@value={{this.tokenStats.entity_clients}}
|
||||
@size="l"
|
||||
@subText="Representations of a particular user, client, or application that created a token via login."
|
||||
/>
|
||||
<StatText
|
||||
class="column"
|
||||
@label="Non-entity"
|
||||
@value={{this.tokenUsageCounts.non_entity_clients}}
|
||||
@value={{this.tokenStats.non_entity_clients}}
|
||||
@size="l"
|
||||
@subText="Clients created with a shared set of permissions, but not associated with an entity."
|
||||
/>
|
||||
|
||||
@@ -37,11 +37,11 @@ export default class ClientsTokenPageComponent extends ActivityComponent {
|
||||
return this.calculateClientAverages(this.byMonthNewClients);
|
||||
}
|
||||
|
||||
get tokenUsageCounts() {
|
||||
get tokenStats() {
|
||||
if (this.totalUsageCounts) {
|
||||
const { entity_clients, non_entity_clients } = this.totalUsageCounts;
|
||||
return {
|
||||
clients: entity_clients + non_entity_clients,
|
||||
total: entity_clients + non_entity_clients,
|
||||
entity_clients,
|
||||
non_entity_clients,
|
||||
};
|
||||
|
||||
@@ -23,23 +23,8 @@
|
||||
<VaultLogoSpinner />
|
||||
{{else}}
|
||||
<div class="is-grid grid-2-columns grid-gap-2 has-top-margin-m grid-align-items-start is-flex-v-centered">
|
||||
<StatText
|
||||
@label="Total"
|
||||
@value={{this.activityData.total.clients}}
|
||||
@size="l"
|
||||
@subText="The number of clients in this billing period ({{date-format
|
||||
this.licenseStartTime
|
||||
'MMM yyyy'
|
||||
}} - {{date-format this.updatedAt 'MMM yyyy'}})."
|
||||
data-test-stat-text="total-clients"
|
||||
/>
|
||||
<StatText
|
||||
@label="New"
|
||||
@value={{this.currentMonthActivityTotalCount}}
|
||||
@size="l"
|
||||
@subText="The number of clients new to Vault in the current month."
|
||||
data-test-stat-text="new-clients"
|
||||
/>
|
||||
<StatText @label="Total" @value={{this.activityData.total.clients}} @size="l" @subText={{this.statSubText.total}} />
|
||||
<StatText @label="New" @value={{this.currentMonthActivityTotalCount}} @size="l" @subText={{this.statSubText.new}} />
|
||||
</div>
|
||||
|
||||
<div class="has-top-margin-l is-flex-center">
|
||||
@@ -55,7 +40,7 @@
|
||||
/>
|
||||
<small class="has-left-margin-xs has-text-grey">
|
||||
Updated
|
||||
{{date-format this.updatedAt "MMM dd, yyyy hh:mm:ss"}}
|
||||
{{date-format this.updatedAt "MMM d yyyy, h:mm:ss aaa" withTimeZone=true}}
|
||||
</small>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
@@ -4,43 +4,52 @@
|
||||
*/
|
||||
|
||||
import Component from '@glimmer/component';
|
||||
import getStorage from 'vault/lib/token-storage';
|
||||
import timestamp from 'core/utils/timestamp';
|
||||
import { task } from 'ember-concurrency';
|
||||
import { waitFor } from '@ember/test-waiters';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { service } from '@ember/service';
|
||||
import { setStartTimeQuery } from 'core/utils/client-count-utils';
|
||||
import { dateFormat } from 'core/helpers/date-format';
|
||||
|
||||
/**
|
||||
* @module DashboardClientCountCard
|
||||
* DashboardClientCountCard component are used to display total and new client count information
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <Dashboard::ClientCountCard @license={{@model.license}} />
|
||||
* ```
|
||||
* @param {object} license - license object passed from the parent
|
||||
*
|
||||
* <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 {
|
||||
@service store;
|
||||
|
||||
clientConfig = null;
|
||||
licenseStartTime = null;
|
||||
@tracked activityData = null;
|
||||
@tracked clientConfig = null;
|
||||
@tracked updatedAt = timestamp.now().toISOString();
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.fetchClientActivity.perform();
|
||||
this.clientConfig = this.store.queryRecord('clients/config', {}).catch(() => {});
|
||||
}
|
||||
|
||||
get currentMonthActivityTotalCount() {
|
||||
return this.activityData?.byMonth?.lastObject?.new_clients.clients;
|
||||
}
|
||||
|
||||
get licenseStartTime() {
|
||||
return this.args.license.startTime || getStorage().getItem('vault:ui-inputted-start-date') || null;
|
||||
get statSubText() {
|
||||
const format = (date) => dateFormat([date, 'MMM yyyy'], {});
|
||||
return this.licenseStartTime
|
||||
? {
|
||||
total: `The number of clients in this billing period (${format(this.licenseStartTime)} - ${format(
|
||||
this.updatedAt
|
||||
)}).`,
|
||||
new: 'The number of clients new to Vault in the current month.',
|
||||
}
|
||||
: { total: 'No total client data available.', new: 'No new client data available.' };
|
||||
}
|
||||
|
||||
@task
|
||||
@@ -48,6 +57,13 @@ export default class DashboardClientCountCard extends Component {
|
||||
*fetchClientActivity(e) {
|
||||
if (e) e.preventDefault();
|
||||
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 {
|
||||
|
||||
@@ -7,11 +7,9 @@
|
||||
|
||||
<div class="has-bottom-margin-xl">
|
||||
<div class="is-flex-row gap-24">
|
||||
{{#if (and @version.isEnterprise (or @license @isRootNamespace))}}
|
||||
{{#if (and @version.isEnterprise @isRootNamespace)}}
|
||||
<div class="is-flex-column is-flex-1 gap-24">
|
||||
{{#if @license}}
|
||||
<Dashboard::ClientCountCard @license={{@license}} />
|
||||
{{/if}}
|
||||
<Dashboard::ClientCountCard @isEnterprise={{@version.isEnterprise}} />
|
||||
{{#if
|
||||
(and @isRootNamespace (has-permission "status" routeParams="replication") (not (is-empty-value @replication)))
|
||||
}}
|
||||
|
||||
@@ -14,9 +14,10 @@ import type VersionService from 'vault/services/version';
|
||||
|
||||
import type { ModelFrom } from 'vault/vault/route';
|
||||
import type ClientsRoute from '../clients';
|
||||
import type ClientsConfigModel from 'vault/models/clients/config';
|
||||
import type ClientsActivityModel from 'vault/models/clients/activity';
|
||||
import type ClientsCountsController from 'vault/controllers/vault/cluster/clients/counts';
|
||||
import { setStartTimeQuery } from 'core/utils/client-count-utils';
|
||||
|
||||
export interface ClientsCountsRouteParams {
|
||||
start_time?: string | number | undefined;
|
||||
end_time?: string | number | undefined;
|
||||
@@ -86,10 +87,7 @@ export default class ClientsCountsRoute extends Route {
|
||||
async model(params: ClientsCountsRouteParams) {
|
||||
const { config, versionHistory } = this.modelFor('vault.cluster.clients') as ModelFrom<ClientsRoute>;
|
||||
// only enterprise versions will have a relevant billing start date, if null users must select initial start time
|
||||
let startTime = null;
|
||||
if (this.version.isEnterprise && this._hasConfig(config)) {
|
||||
startTime = getUnixTime(config.billingStartTimestamp);
|
||||
}
|
||||
const startTime = setStartTimeQuery(this.version.isEnterprise, config);
|
||||
|
||||
const startTimestamp = Number(params.start_time) || startTime;
|
||||
const endTimestamp = Number(params.end_time) || getUnixTime(timestamp.now());
|
||||
@@ -118,8 +116,4 @@ export default class ClientsCountsRoute extends Route {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_hasConfig(model: ClientsConfigModel | object): model is ClientsConfigModel {
|
||||
return 'billingStartTimestamp' in model;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,6 @@ export default class VaultClusterDashboardRoute extends Route.extend(ClusterRout
|
||||
return hash({
|
||||
replication,
|
||||
secretsEngines: this.store.query('secret-engine', {}),
|
||||
license: this.store.queryRecord('license', {}).catch(() => null),
|
||||
isRootNamespace: this.namespace.inRootNamespace && !hasChroot,
|
||||
version: this.version,
|
||||
vaultConfiguration: hasChroot ? null : this.getVaultConfiguration(),
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
<Dashboard::Overview
|
||||
@replication={{this.model.replication}}
|
||||
@secretsEngines={{this.model.secretsEngines}}
|
||||
@license={{this.model.license}}
|
||||
@isRootNamespace={{this.model.isRootNamespace}}
|
||||
@version={{this.model.version}}
|
||||
@vaultConfiguration={{this.model.vaultConfiguration}}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import { parseAPITimestamp } from 'core/utils/date-formatters';
|
||||
import { compareAsc, getUnixTime, isWithinInterval } from 'date-fns';
|
||||
|
||||
import type ClientsConfigModel from 'vault/models/clients/config';
|
||||
import type ClientsVersionHistoryModel from 'vault/vault/models/clients/version-history';
|
||||
|
||||
/*
|
||||
@@ -59,6 +60,18 @@ export const filterVersionHistory = (
|
||||
return [];
|
||||
};
|
||||
|
||||
export const setStartTimeQuery = (
|
||||
isEnterprise: boolean,
|
||||
config: ClientsConfigModel | Record<string, never>
|
||||
) => {
|
||||
// CE versions have no license and so the start time defaults to "0001-01-01T00:00:00Z"
|
||||
if (isEnterprise && _hasConfig(config)) {
|
||||
return getUnixTime(config.billingStartTimestamp);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
// METHODS FOR SERIALIZING ACTIVITY RESPONSE
|
||||
export const formatDateObject = (dateObj: { monthIdx: number; year: number }, isEnd: boolean) => {
|
||||
const { year, monthIdx } = dateObj;
|
||||
// day=0 for Date.UTC() returns the last day of the month before
|
||||
@@ -188,6 +201,11 @@ export const namespaceArrayToObject = (
|
||||
};
|
||||
|
||||
// type guards for conditionals
|
||||
function _hasConfig(model: ClientsConfigModel | object): model is ClientsConfigModel {
|
||||
if (!model) return false;
|
||||
return 'billingStartTimestamp' in model;
|
||||
}
|
||||
|
||||
export function hasMountsKey(
|
||||
obj: ByMonthNewClients | NamespaceNewClients | MountNewClients
|
||||
): obj is NamespaceNewClients {
|
||||
@@ -201,7 +219,6 @@ export function hasNamespacesKey(
|
||||
}
|
||||
|
||||
// TYPES RETURNED BY UTILS (serialized)
|
||||
|
||||
export interface TotalClients {
|
||||
clients: number;
|
||||
entity_clients: number;
|
||||
|
||||
@@ -404,16 +404,14 @@ module('Acceptance | landing page dashboard', function (hooks) {
|
||||
assert.dom(DASHBOARD.cardName('client-count')).exists();
|
||||
const response = await this.store.peekRecord('clients/activity', 'some-activity-id');
|
||||
assert.dom('[data-test-client-count-title]').hasText('Client count');
|
||||
assert.dom('[data-test-stat-text="total-clients"] .stat-label').hasText('Total');
|
||||
assert.dom('[data-test-stat-text="Total"] .stat-label').hasText('Total');
|
||||
assert.dom('[data-test-stat-text="Total"] .stat-value').hasText(formatNumber([response.total.clients]));
|
||||
assert.dom('[data-test-stat-text="New"] .stat-label').hasText('New');
|
||||
assert
|
||||
.dom('[data-test-stat-text="total-clients"] .stat-value')
|
||||
.hasText(formatNumber([response.total.clients]));
|
||||
assert.dom('[data-test-stat-text="new-clients"] .stat-label').hasText('New');
|
||||
assert
|
||||
.dom('[data-test-stat-text="new-clients"] .stat-text')
|
||||
.dom('[data-test-stat-text="New"] .stat-text')
|
||||
.hasText('The number of clients new to Vault in the current month.');
|
||||
assert
|
||||
.dom('[data-test-stat-text="new-clients"] .stat-value')
|
||||
.dom('[data-test-stat-text="New"] .stat-value')
|
||||
.hasText(formatNumber([response.byMonth.lastObject.new_clients.clients]));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -69,21 +69,25 @@ module('Integration | Component | clients | Clients::Page::Token', function (hoo
|
||||
|
||||
test('it should render monthly total chart', async function (assert) {
|
||||
const count = this.activity.byMonth.length;
|
||||
assert.expect(count + 7);
|
||||
const { entity_clients, non_entity_clients } = this.activity.total;
|
||||
assert.expect(count + 8);
|
||||
const getAverage = (data) => {
|
||||
const average = ['entity_clients', 'non_entity_clients'].reduce((count, key) => {
|
||||
return (count += calculateAverage(data, key) || 0);
|
||||
}, 0);
|
||||
return formatNumber([average]);
|
||||
};
|
||||
const expectedTotal = getAverage(this.activity.byMonth);
|
||||
const expectedAvg = getAverage(this.activity.byMonth);
|
||||
const expectedTotal = formatNumber([entity_clients + non_entity_clients]);
|
||||
const chart = CHARTS.container('Entity/Non-entity clients usage');
|
||||
|
||||
await this.renderComponent();
|
||||
|
||||
assert
|
||||
.dom(CLIENT_COUNT.statTextValue('Average total clients per month'))
|
||||
.dom(CLIENT_COUNT.statTextValue('Total clients'))
|
||||
.hasText(expectedTotal, 'renders correct total clients');
|
||||
assert
|
||||
.dom(CLIENT_COUNT.statTextValue('Average total clients per month'))
|
||||
.hasText(expectedAvg, 'renders correct average clients');
|
||||
|
||||
// assert bar chart is correct
|
||||
assert.dom(`${chart} ${CHARTS.xAxis}`).hasText('7/23 8/23 9/23 10/23 11/23 12/23 1/24');
|
||||
|
||||
@@ -13,6 +13,7 @@ import { LICENSE_START, STATIC_NOW } from 'vault/mirage/handlers/clients';
|
||||
import timestamp from 'core/utils/timestamp';
|
||||
import { ACTIVITY_RESPONSE_STUB } from 'vault/tests/helpers/clients/client-count-helpers';
|
||||
import { formatNumber } from 'core/helpers/format-number';
|
||||
import { CLIENT_COUNT } from 'vault/tests/helpers/clients/client-count-selectors';
|
||||
|
||||
module('Integration | Component | dashboard/client-count-card', function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
@@ -22,18 +23,12 @@ module('Integration | Component | dashboard/client-count-card', function (hooks)
|
||||
sinon.stub(timestamp, 'now').callsFake(() => STATIC_NOW);
|
||||
});
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
this.license = {
|
||||
startTime: LICENSE_START.toISOString(),
|
||||
};
|
||||
});
|
||||
|
||||
hooks.after(function () {
|
||||
timestamp.now.restore();
|
||||
});
|
||||
|
||||
test('it should display client count information', async function (assert) {
|
||||
assert.expect(9);
|
||||
assert.expect(6);
|
||||
const { months, total } = ACTIVITY_RESPONSE_STUB;
|
||||
const [latestMonth] = months.slice(-1);
|
||||
this.server.get('sys/internal/counters/activity', () => {
|
||||
@@ -44,24 +39,62 @@ module('Integration | Component | dashboard/client-count-card', function (hooks)
|
||||
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 @license={{this.license}} />`);
|
||||
await render(hbs`<Dashboard::ClientCountCard @isEnterprise={{true}} />`);
|
||||
assert.dom('[data-test-client-count-title]').hasText('Client count');
|
||||
assert.dom('[data-test-stat-text="total-clients"] .stat-label').hasText('Total');
|
||||
assert
|
||||
.dom('[data-test-stat-text="total-clients"] .stat-text')
|
||||
.hasText('The number of clients in this billing period (Jul 2023 - Jan 2024).');
|
||||
.dom(CLIENT_COUNT.statText('Total'))
|
||||
.hasText(
|
||||
`Total The number of clients in this billing period (Jul 2023 - Jan 2024). ${formatNumber([
|
||||
total.clients,
|
||||
])}`
|
||||
);
|
||||
|
||||
assert
|
||||
.dom('[data-test-stat-text="total-clients"] .stat-value')
|
||||
.hasText(`${formatNumber([total.clients])}`);
|
||||
assert.dom('[data-test-stat-text="new-clients"] .stat-label').hasText('New');
|
||||
assert
|
||||
.dom('[data-test-stat-text="new-clients"] .stat-text')
|
||||
.hasText('The number of clients new to Vault in the current month.');
|
||||
assert
|
||||
.dom('[data-test-stat-text="new-clients"] .stat-value')
|
||||
.hasText(`${formatNumber([latestMonth.new_clients.counts.clients])}`);
|
||||
.dom(CLIENT_COUNT.statText('New'))
|
||||
.hasText(
|
||||
`New The number of clients new to Vault in the current month. ${formatNumber([
|
||||
latestMonth.new_clients.counts.clients,
|
||||
])}`
|
||||
);
|
||||
|
||||
// fires second request to /activity
|
||||
await click('[data-test-refresh]');
|
||||
});
|
||||
|
||||
test('it does not query activity for community edition', async function (assert) {
|
||||
assert.expect(3);
|
||||
// in the template this component is wrapped in an isEnterprise conditional so this
|
||||
// state is currently not possible, adding a test to safeguard against introducing
|
||||
// regressions during future refactors
|
||||
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 {
|
||||
request_id: 'some-config-id',
|
||||
data: {
|
||||
billing_start_timestamp: '0001-01-01T00:00:00Z',
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
await render(hbs`<Dashboard::ClientCountCard @isEnterprise={{false}} />`);
|
||||
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. -');
|
||||
|
||||
// attempt second request to /activity but component task should return instead of hitting endpoint
|
||||
await click('[data-test-refresh]');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -9,6 +9,7 @@ import { render } from '@ember/test-helpers';
|
||||
import { hbs } from 'ember-cli-htmlbars';
|
||||
import { setupMirage } from 'ember-cli-mirage/test-support';
|
||||
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) {
|
||||
setupRenderingTest(hooks);
|
||||
@@ -60,6 +61,14 @@ module('Integration | Component | dashboard/overview', function (hooks) {
|
||||
],
|
||||
};
|
||||
this.refreshModel = () => {};
|
||||
this.server.get('sys/internal/counters/config', function () {
|
||||
return {
|
||||
request_id: 'some-config-id',
|
||||
data: {
|
||||
billing_start_timestamp: LICENSE_START.toISOString(),
|
||||
},
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
test('it should show dashboard empty states', async function (assert) {
|
||||
@@ -129,7 +138,6 @@ module('Integration | Component | dashboard/overview', function (hooks) {
|
||||
@replication={{this.replication}}
|
||||
@version={{this.version}}
|
||||
@isRootNamespace={{true}}
|
||||
@license={{this.license}}
|
||||
@refreshModel={{this.refreshModel}} />`
|
||||
);
|
||||
assert.dom(DASHBOARD.cardHeader('Vault version')).exists();
|
||||
@@ -140,43 +148,11 @@ module('Integration | Component | dashboard/overview', function (hooks) {
|
||||
assert.dom(DASHBOARD.cardName('client-count')).exists();
|
||||
});
|
||||
|
||||
test('it should hide client count on enterprise w/o license ', async function (assert) {
|
||||
this.version = this.owner.lookup('service:version');
|
||||
this.version.version = '1.13.1+ent';
|
||||
this.version.type = 'enterprise';
|
||||
this.isRootNamespace = true;
|
||||
|
||||
await render(
|
||||
hbs`
|
||||
<Dashboard::Overview
|
||||
@secretsEngines={{this.secretsEngines}}
|
||||
@vaultConfiguration={{this.vaultConfiguration}}
|
||||
@replication={{this.replication}}
|
||||
@version={{this.version}}
|
||||
@isRootNamespace={{this.isRootNamespace}}
|
||||
@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('client-count')).doesNotExist();
|
||||
});
|
||||
|
||||
test('it should hide replication on enterprise not on root namespace', async function (assert) {
|
||||
this.version = this.owner.lookup('service:version');
|
||||
this.version.version = '1.13.1+ent';
|
||||
this.version.type = 'enterprise';
|
||||
this.isRootNamespace = false;
|
||||
this.license = {
|
||||
autoloaded: {
|
||||
license_id: '7adbf1f4-56ef-35cd-3a6c-50ef2627865d',
|
||||
},
|
||||
};
|
||||
|
||||
await render(
|
||||
hbs`
|
||||
@@ -186,7 +162,6 @@ module('Integration | Component | dashboard/overview', function (hooks) {
|
||||
@secretsEngines={{this.secretsEngines}}
|
||||
@vaultConfiguration={{this.vaultConfiguration}}
|
||||
@replication={{this.replication}}
|
||||
@license={{this.license}}
|
||||
@refreshModel={{this.refreshModel}} />`
|
||||
);
|
||||
|
||||
@@ -197,7 +172,7 @@ module('Integration | Component | dashboard/overview', function (hooks) {
|
||||
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')).exists();
|
||||
assert.dom(DASHBOARD.cardName('client-count')).doesNotExist();
|
||||
});
|
||||
|
||||
module('learn more card', function () {
|
||||
@@ -238,7 +213,6 @@ module('Integration | Component | dashboard/overview', function (hooks) {
|
||||
<Dashboard::Overview
|
||||
@version={{this.version}}
|
||||
@isRootNamespace={{this.isRootNamespace}}
|
||||
@license={{this.license}}
|
||||
@secretsEngines={{this.secretsEngines}}
|
||||
@vaultConfiguration={{this.vaultConfiguration}}
|
||||
@replication={{this.replication}}
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
destructureClientCounts,
|
||||
namespaceArrayToObject,
|
||||
sortMonthsByTimestamp,
|
||||
setStartTimeQuery,
|
||||
} from 'core/utils/client-count-utils';
|
||||
import { LICENSE_START } from 'vault/mirage/handlers/clients';
|
||||
import {
|
||||
@@ -27,6 +28,9 @@ used to normalize the sys/counters/activity response in the clients/activity
|
||||
serializer. these functions are tested individually here, instead of all at once
|
||||
in a serializer test for easier debugging
|
||||
*/
|
||||
|
||||
// TODO refactor tests into a module for each util method, then make each assertion its separate tests
|
||||
|
||||
module('Integration | Util | client count utils', function (hooks) {
|
||||
setupTest(hooks);
|
||||
|
||||
@@ -372,4 +376,35 @@ module('Integration | Util | client count utils', function (hooks) {
|
||||
'it formats combined data for monthly namespaces_by_key spanning upgrade to 1.10'
|
||||
);
|
||||
});
|
||||
|
||||
test('setStartTimeQuery: it returns start time query for activity log', async function (assert) {
|
||||
assert.expect(6);
|
||||
const apiPath = 'sys/internal/counters/config';
|
||||
assert.strictEqual(setStartTimeQuery(true, {}), null, `it returns null if no permission to ${apiPath}`);
|
||||
assert.strictEqual(
|
||||
setStartTimeQuery(false, {}),
|
||||
null,
|
||||
`it returns null for community edition and no permission to ${apiPath}`
|
||||
);
|
||||
assert.strictEqual(
|
||||
setStartTimeQuery(true, { billingStartTimestamp: new Date('2022-06-08T00:00:00Z') }),
|
||||
1654646400,
|
||||
'it returns unix time if enterprise and billing_start_timestamp exists'
|
||||
);
|
||||
assert.strictEqual(
|
||||
setStartTimeQuery(false, { billingStartTimestamp: new Date('0001-01-01T00:00:00Z') }),
|
||||
null,
|
||||
'it returns null time for community edition even if billing_start_timestamp exists'
|
||||
);
|
||||
assert.strictEqual(
|
||||
setStartTimeQuery(false, { foo: 'bar' }),
|
||||
null,
|
||||
'it returns null if billing_start_timestamp key does not exist'
|
||||
);
|
||||
assert.strictEqual(
|
||||
setStartTimeQuery(false, undefined),
|
||||
null,
|
||||
'fails gracefully if no config model is passed'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user