Skip to content

Commit

Permalink
backport of commit 3df0935 (#26121)
Browse files Browse the repository at this point in the history
Co-authored-by: claire bontempo <68122737+hellobontempo@users.noreply.github.com>
  • Loading branch information
1 parent 6a694d0 commit bc9c844
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 17 deletions.
6 changes: 5 additions & 1 deletion ui/app/components/clients/page/counts.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,11 @@
{{else}}
<EmptyState
@title="No data received {{if this.dateRangeMessage this.dateRangeMessage}}"
@message="Update the filter values or click the button to reset them."
@message={{if
this.version.isCommunity
"Select a start date above to query client count data."
"Update the filter values or click the button to reset them."
}}
>
<Hds::Button @text="Reset filters" @color="tertiary" @icon="reload" {{on "click" this.resetFilters}} />
</EmptyState>
Expand Down
19 changes: 12 additions & 7 deletions ui/app/components/clients/page/sync.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,18 @@
</:subTitle>

<:stats>
<StatText
@label="Average sync clients per month"
@value={{this.average this.byMonthActivityData "secret_syncs"}}
@size="m"
class="data-details-top has-top-padding-l"
data-test-average-sync-clients
/>
{{#let (this.average this.byMonthActivityData "secret_syncs") as |avg|}}
{{! intentionally hides a 0 average (0 is falsy) }}
{{#if avg}}
<StatText
@label="Average sync clients per month"
@value={{avg}}
@size="m"
class="data-details-top has-top-padding-l"
data-test-average-sync-clients
/>
{{/if}}
{{/let}}
</:stats>

<:chart>
Expand Down
17 changes: 8 additions & 9 deletions ui/app/routes/vault/cluster/clients/counts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { getUnixTime } from 'date-fns';

import type StoreService from 'vault/services/store';
import type VersionService from 'vault/services/version';

import type { ClientsRouteModel } from '../clients';
import type ClientsConfigModel from 'vault/models/clients/config';
import type ClientsVersionHistoryModel from 'vault/models/clients/version-history';
Expand Down Expand Up @@ -60,12 +61,9 @@ export default class ClientsCountsRoute extends Route {
mountPath: { refreshModel: false, replace: true },
};

async getActivity(
start_time: number,
end_time: number
): Promise<[ClientsActivityModel | undefined, AdapterError | unknown] | [Record<string, never>, null]> {
async getActivity(start_time: number | null, end_time: number) {
let activity, activityError;
// if there is no billingStartTimestamp or selected start date initially we allow the user to manually choose a date
// if there is no start_time we want the user to manually choose a date
// in that case bypass the query so that the user isn't stuck viewing the activity error
if (start_time) {
try {
Expand Down Expand Up @@ -93,7 +91,7 @@ export default class ClientsCountsRoute extends Route {
}
}

async isSecretsSyncActivated(activity: ClientsActivityModel | Record<string, never> | undefined) {
async isSecretsSyncActivated(activity: ClientsActivityModel) {
// if there are secrets, the feature is activated
if (activity && activity.total?.secret_syncs > 0) return true;

Expand All @@ -107,12 +105,13 @@ export default class ClientsCountsRoute extends Route {

async model(params: ClientsCountsRouteParams) {
const { config, versionHistory } = this.modelFor('vault.cluster.clients') as ClientsRouteModel;
// we could potentially make an additional request to fetch the license and get the start date from there if the config request fails
const startTimestamp = Number(params.start_time) || getUnixTime(config.billingStartTimestamp);
// only enterprise versions will have a relevant billing start date, pass null so community users must select initial start time
const startTime = this.version.isEnterprise ? getUnixTime(config.billingStartTimestamp) : null;
const startTimestamp = Number(params.start_time) || startTime;
const endTimestamp = Number(params.end_time) || getUnixTime(timestamp.now());
const [activity, activityError] = await this.getActivity(startTimestamp, endTimestamp);

const isSecretsSyncActivated = await this.isSecretsSyncActivated(activity);
const isSecretsSyncActivated = await this.isSecretsSyncActivated(activity as ClientsActivityModel);

return {
activity,
Expand Down
9 changes: 9 additions & 0 deletions ui/tests/acceptance/clients/counts-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ module('Acceptance | clients | counts', function (hooks) {
timestamp.now.restore();
});

test('it should prompt user to query start time for community version', async function (assert) {
assert.expect(2);
this.owner.lookup('service:version').type = 'community';
await visit('/vault/clients/counts/overview');

assert.dom(ts.emptyStateTitle).hasText('No data received');
assert.dom(ts.emptyStateMessage).hasText('Select a start date above to query client count data.');
});

test('it should redirect to counts overview route for transitions to parent', async function (assert) {
await visit('/vault/clients');
assert.strictEqual(currentURL(), '/vault/clients/counts/overview', 'Redirects to counts overview route');
Expand Down
3 changes: 3 additions & 0 deletions ui/tests/acceptance/clients/counts/overview-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,9 @@ module('Acceptance | clients | overview | sync not in license', function (hooks)

hooks.beforeEach(async function () {
this.store = this.owner.lookup('service:store');
// mocks endpoint for no additional license modules
this.server.get('/sys/license/features', () => ({ features: [] }));

await authPage.login();
return visit('/vault/clients/counts/overview');
});
Expand Down
45 changes: 45 additions & 0 deletions ui/tests/integration/components/clients/page/sync-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,4 +136,49 @@ module('Integration | Component | clients | Clients::Page::Sync', function (hook
assert.dom(syncTab.total).doesNotExist();
assert.dom(syncTab.average).doesNotExist();
});

test('it should render an empty chart if secrets sync is activated but no secrets synced', async function (assert) {
this.isSecretsSyncActivated = true;
const counts = {
clients: 10,
entity_clients: 4,
non_entity_clients: 6,
secret_syncs: 0,
};
const monthData = {
month: '1/24',
timestamp: '2024-01-01T00:00:00-08:00',
...counts,
namespaces: [
{
label: 'root',
...counts,
mounts: [],
},
],
};
this.activity.byMonth = [
{
...monthData,
namespaces_by_key: {
root: {
...monthData,
mounts_by_key: {},
},
},
new_clients: {
...monthData,
},
},
];
this.activity.total = counts;
await this.renderComponent();

assert
.dom(syncTab.total)
.hasText(
'Total sync clients The total number of secrets synced from Vault to other destinations during this date range. 0'
);
assert.dom(syncTab.average).doesNotExist('Does not render average if the calculation is 0');
});
});

0 comments on commit bc9c844

Please sign in to comment.