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:
claire bontempo
2024-05-07 18:45:42 +01:00
committed by GitHub
parent 57e6795c0c
commit 1e8eefade1
10 changed files with 213 additions and 184 deletions

3
changelog/26848.txt Normal file
View File

@@ -0,0 +1,3 @@
```release-note:improvement
ui: Hide dashboard client count card if user does not have permission to view clients.
```

View File

@@ -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);

View File

@@ -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>

View File

@@ -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;
} }

View File

@@ -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}}

View File

@@ -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}}

View File

@@ -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();

View File

@@ -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.');
}); });
}); });

View File

@@ -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]')

View File

@@ -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 });
});
}); });