mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-29 09:42:25 +00:00
UI: remove current_billing_period from dashboard activity log request (#27559)
* remove current_billing_period from dashboard request * add changelog * remove timestamp from assertion * update mirage
This commit is contained in:
3
changelog/27559.txt
Normal file
3
changelog/27559.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
```release-note:improvement
|
||||
ui: Remove deprecated `current_billing_period` from dashboard activity log request
|
||||
```
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
import ApplicationAdapter from '../application';
|
||||
import { formatDateObject } from 'core/utils/client-count-utils';
|
||||
import { debug } from '@ember/debug';
|
||||
|
||||
export default class ActivityAdapter extends ApplicationAdapter {
|
||||
// javascript localizes new Date() objects but all activity log data is stored in UTC
|
||||
@@ -33,4 +34,12 @@ export default class ActivityAdapter extends ApplicationAdapter {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
urlForFindRecord(id) {
|
||||
// debug reminder so model is stored in Ember data with the same id for consistency
|
||||
if (id !== 'clients/activity') {
|
||||
debug(`findRecord('clients/activity') should pass 'clients/activity' as the id, you passed: '${id}'`);
|
||||
}
|
||||
return `${this.buildURL()}/internal/counters/activity`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
~}}
|
||||
|
||||
{{#if (eq @config.enabled "On")}}
|
||||
{{#if (or @config.reportingEnabled (eq @config.enabled "On"))}}
|
||||
<EmptyState
|
||||
@title="No data received {{if @dateRangeMessage @dateRangeMessage}}"
|
||||
@message="Tracking is turned on and Vault is gathering data. It should appear here within 30 minutes."
|
||||
class="is-shadowless"
|
||||
/>
|
||||
{{else}}
|
||||
{{else if @config}}
|
||||
<EmptyState
|
||||
@title="Data tracking is disabled"
|
||||
@message="Tracking is disabled, and no data is being collected. To turn it on, edit the configuration."
|
||||
@@ -24,4 +24,10 @@
|
||||
/>
|
||||
{{/if}}
|
||||
</EmptyState>
|
||||
{{else}}
|
||||
<EmptyState
|
||||
@title="Activity configuration data is unavailable"
|
||||
@message="Reporting status is unknown and could be enabled or disabled. Check the Vault logs for more information."
|
||||
class="is-shadowless"
|
||||
/>
|
||||
{{/if}}
|
||||
@@ -14,10 +14,10 @@
|
||||
|
||||
<hr class="has-background-gray-100" />
|
||||
|
||||
{{#if this.hasActivity}}
|
||||
{{#if this.fetchClientActivity.isRunning}}
|
||||
<VaultLogoSpinner />
|
||||
{{else}}
|
||||
{{#if this.fetchClientActivity.isRunning}}
|
||||
<VaultLogoSpinner />
|
||||
{{else}}
|
||||
{{#if this.activityData}}
|
||||
<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={{this.statSubText.total}} />
|
||||
<StatText @label="New" @value={{this.currentMonthActivityTotalCount}} @size="l" @subText={{this.statSubText.new}} />
|
||||
@@ -34,15 +34,13 @@
|
||||
{{on "click" (perform this.fetchClientActivity)}}
|
||||
data-test-refresh
|
||||
/>
|
||||
<small class="has-left-margin-xs has-text-grey">
|
||||
<small class="has-left-margin-xs has-text-grey" data-test-updated-timestamp>
|
||||
Updated
|
||||
{{date-format this.updatedAt "MMM d yyyy, h:mm:ss aaa" withTimeZone=true}}
|
||||
</small>
|
||||
</div>
|
||||
{{else}}
|
||||
<Clients::NoData @config={{this.activityConfig}} />
|
||||
{{/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}}
|
||||
</Hds::Card::Container>
|
||||
@@ -23,7 +23,7 @@ export default class DashboardClientCountCard extends Component {
|
||||
@service store;
|
||||
|
||||
@tracked activityData = null;
|
||||
@tracked hasActivity = false;
|
||||
@tracked activityConfig = null;
|
||||
@tracked updatedAt = null;
|
||||
|
||||
constructor() {
|
||||
@@ -53,11 +53,10 @@ export default class DashboardClientCountCard extends Component {
|
||||
this.updatedAt = timestamp.now().toISOString();
|
||||
|
||||
try {
|
||||
this.activityData = yield this.store.queryRecord('clients/activity', {
|
||||
current_billing_period: true,
|
||||
});
|
||||
this.hasActivity = this.activityData.id === 'no-data' ? false : true;
|
||||
this.activityData = yield this.store.findRecord('clients/activity', 'clients/activity');
|
||||
} catch (error) {
|
||||
// used for rendering the "No data" empty state, swallow any errors requesting config data
|
||||
this.activityConfig = yield this.store.queryRecord('clients/config', {}).catch(() => null);
|
||||
this.error = error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,8 +35,10 @@ export default class ClientsConfigModel extends Model {
|
||||
|
||||
@attr('number') minimumRetentionMonths;
|
||||
|
||||
// refers specifically to the activitylog and will always be on for enterprise
|
||||
@attr('string') enabled;
|
||||
|
||||
// reporting_enabled is for automated reporting and only true of the customer hasn’t opted-out of automated license reporting
|
||||
@attr('boolean') reportingEnabled;
|
||||
|
||||
@attr('date') billingStartTimestamp;
|
||||
|
||||
@@ -215,9 +215,9 @@ export default function (server) {
|
||||
|
||||
server.get('/sys/internal/counters/activity', (schema, req) => {
|
||||
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
|
||||
if (!start_time && !end_time) {
|
||||
// if there are no date query params, the activity log default behavior
|
||||
// queries from the builtin license start timestamp to the current month
|
||||
start_time = LICENSE_START.toISOString();
|
||||
end_time = STATIC_NOW.toISOString();
|
||||
}
|
||||
|
||||
@@ -402,7 +402,7 @@ module('Acceptance | landing page dashboard', function (hooks) {
|
||||
assert.true(version.isEnterprise, 'version is enterprise');
|
||||
assert.strictEqual(currentURL(), '/vault/dashboard');
|
||||
assert.dom(DASHBOARD.cardName('client-count')).exists();
|
||||
const response = await this.store.peekRecord('clients/activity', 'some-activity-id');
|
||||
const response = await this.store.findRecord('clients/activity', 'clients/activity');
|
||||
assert.dom('[data-test-client-count-title]').hasText('Client count');
|
||||
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]));
|
||||
|
||||
93
ui/tests/integration/components/clients/no-data-test.js
Normal file
93
ui/tests/integration/components/clients/no-data-test.js
Normal file
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { module, test } from 'qunit';
|
||||
import { setupRenderingTest } from 'vault/tests/helpers';
|
||||
import { render } from '@ember/test-helpers';
|
||||
import { hbs } from 'ember-cli-htmlbars';
|
||||
import { setupMirage } from 'ember-cli-mirage/test-support';
|
||||
import { GENERAL } from 'vault/tests/helpers/general-selectors';
|
||||
import { allowAllCapabilitiesStub } from 'vault/tests/helpers/stubs';
|
||||
|
||||
module('Integration | Component | clients/no-data', function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
hooks.beforeEach(async function () {
|
||||
this.server.post('/sys/capabilities-self', allowAllCapabilitiesStub());
|
||||
this.store = this.owner.lookup('service:store');
|
||||
this.setConfig = async (data) => {
|
||||
// the clients/config model does some funky serializing for the "enabled" param
|
||||
// so stubbing the request here instead of just the model for additional coverage
|
||||
this.server.get('sys/internal/counters/config', () => {
|
||||
return {
|
||||
request_id: '25a94b99-b49a-c4ac-cb7b-5ba0eb390a25',
|
||||
data,
|
||||
};
|
||||
});
|
||||
return this.store.queryRecord('clients/config', {});
|
||||
};
|
||||
this.renderComponent = async () => {
|
||||
return render(hbs`<Clients::NoData @config={{this.config}} />`);
|
||||
};
|
||||
});
|
||||
|
||||
test('it renders empty state when enabled is "on"', async function (assert) {
|
||||
assert.expect(2);
|
||||
const data = {
|
||||
enabled: 'default-enabled',
|
||||
reporting_enabled: false,
|
||||
};
|
||||
``;
|
||||
this.config = await this.setConfig(data);
|
||||
await this.renderComponent();
|
||||
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.');
|
||||
});
|
||||
|
||||
test('it renders empty state when reporting_enabled is true', async function (assert) {
|
||||
assert.expect(2);
|
||||
const data = {
|
||||
enabled: 'default-disabled',
|
||||
reporting_enabled: true,
|
||||
};
|
||||
this.config = await this.setConfig(data);
|
||||
await this.renderComponent();
|
||||
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.');
|
||||
});
|
||||
|
||||
test('it renders empty state when reporting is fully disabled', async function (assert) {
|
||||
assert.expect(2);
|
||||
const data = {
|
||||
enabled: 'default-disabled',
|
||||
reporting_enabled: false,
|
||||
};
|
||||
this.config = await this.setConfig(data);
|
||||
await this.renderComponent();
|
||||
assert.dom(GENERAL.emptyStateTitle).hasText('Data tracking is disabled');
|
||||
assert
|
||||
.dom(GENERAL.emptyStateMessage)
|
||||
.hasText(
|
||||
'Tracking is disabled, and no data is being collected. To turn it on, edit the configuration.'
|
||||
);
|
||||
});
|
||||
|
||||
test('it renders empty state when config data is not available', async function (assert) {
|
||||
assert.expect(2);
|
||||
this.config = null;
|
||||
await this.renderComponent();
|
||||
assert.dom(GENERAL.emptyStateTitle).hasText('Activity configuration data is unavailable');
|
||||
assert
|
||||
.dom(GENERAL.emptyStateMessage)
|
||||
.hasText(
|
||||
'Reporting status is unknown and could be enabled or disabled. Check the Vault logs for more information.'
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -8,6 +8,7 @@ import { setupRenderingTest } from 'vault/tests/helpers';
|
||||
import { render, click } from '@ember/test-helpers';
|
||||
import { hbs } from 'ember-cli-htmlbars';
|
||||
import { setupMirage } from 'ember-cli-mirage/test-support';
|
||||
import { Response } from 'miragejs';
|
||||
import sinon from 'sinon';
|
||||
import { STATIC_NOW } from 'vault/mirage/handlers/clients';
|
||||
import timestamp from 'core/utils/timestamp';
|
||||
@@ -21,21 +22,14 @@ module('Integration | Component | dashboard/client-count-card', function (hooks)
|
||||
setupMirage(hooks);
|
||||
|
||||
test('it should display client count information', async function (assert) {
|
||||
sinon.replace(timestamp, 'now', sinon.fake.returns(STATIC_NOW));
|
||||
assert.expect(5);
|
||||
assert.expect(6);
|
||||
sinon.replace(timestamp, 'now', sinon.fake.returns(STATIC_NOW)); // 1/25/24
|
||||
const { months, total } = ACTIVITY_RESPONSE_STUB;
|
||||
const [latestMonth] = months.slice(-1);
|
||||
this.server.get('sys/internal/counters/activity', (schema, req) => {
|
||||
this.server.get('sys/internal/counters/activity', () => {
|
||||
// this assertion should be hit twice, once initially and then again clicking 'refresh'
|
||||
assert.propEqual(
|
||||
req.queryParams,
|
||||
{ current_billing_period: 'true' },
|
||||
'it makes request to sys/internal/counters/activity with builtin license start time'
|
||||
);
|
||||
return {
|
||||
request_id: 'some-activity-id',
|
||||
data: ACTIVITY_RESPONSE_STUB,
|
||||
};
|
||||
assert.true(true, 'makes request to sys/internal/counters/activity');
|
||||
return { data: ACTIVITY_RESPONSE_STUB };
|
||||
});
|
||||
|
||||
await render(hbs`<Dashboard::ClientCountCard />`);
|
||||
@@ -54,6 +48,7 @@ module('Integration | Component | dashboard/client-count-card', function (hooks)
|
||||
latestMonth.new_clients.counts.clients,
|
||||
])}`
|
||||
);
|
||||
assert.dom('[data-test-updated-timestamp]').hasTextContaining('Updated Jan 25 2024');
|
||||
|
||||
// fires second request to /activity
|
||||
await click('[data-test-refresh]');
|
||||
@@ -65,7 +60,6 @@ module('Integration | Component | dashboard/client-count-card', function (hooks)
|
||||
// stubbing this unrealistic response just to test component subtext logic
|
||||
this.server.get('sys/internal/counters/activity', () => {
|
||||
return {
|
||||
request_id: 'some-activity-id',
|
||||
data: { by_namespace: [], months: [], total: {} },
|
||||
};
|
||||
});
|
||||
@@ -75,19 +69,48 @@ module('Integration | Component | dashboard/client-count-card', function (hooks)
|
||||
assert.dom(CLIENT_COUNT.statText('New')).hasText('New No new client data available. -');
|
||||
});
|
||||
|
||||
test('it shows empty state if no activity data', async function (assert) {
|
||||
test('it shows empty state if no activity data and reporting is enabled', async function (assert) {
|
||||
// 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);
|
||||
assert.expect(4);
|
||||
this.server.get('sys/internal/counters/activity', () => {
|
||||
assert.true(true, 'makes request to sys/internal/counters/activity');
|
||||
return { data: {} };
|
||||
});
|
||||
|
||||
this.server.get('sys/internal/counters/config', () => {
|
||||
assert.true(true, 'makes request to sys/internal/counters/config');
|
||||
return {
|
||||
request_id: '25a94b99-b49a-c4ac-cb7b-5ba0eb390a25',
|
||||
data: { reporting_enabled: true },
|
||||
};
|
||||
});
|
||||
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.');
|
||||
});
|
||||
|
||||
test('it shows empty state if no activity data and config data is unavailable', async function (assert) {
|
||||
assert.expect(4);
|
||||
this.server.get('sys/internal/counters/activity', () => {
|
||||
assert.true(true, 'makes request to sys/internal/counters/activity');
|
||||
return { data: {} };
|
||||
});
|
||||
this.server.get('sys/internal/counters/config', () => {
|
||||
assert.true(true, 'makes request to sys/internal/counters/config');
|
||||
return new Response(
|
||||
403,
|
||||
{ 'Content-Type': 'application/json' },
|
||||
JSON.stringify({ errors: ['permission denied'] })
|
||||
);
|
||||
});
|
||||
await render(hbs`<Dashboard::ClientCountCard />`);
|
||||
assert.dom(GENERAL.emptyStateTitle).hasText('Activity configuration data is unavailable');
|
||||
assert
|
||||
.dom(GENERAL.emptyStateMessage)
|
||||
.hasText(
|
||||
'Reporting status is unknown and could be enabled or disabled. Check the Vault logs for more information.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user