From d55c6b777d335cc678bef3865906dbac24038d1b Mon Sep 17 00:00:00 2001
From: Chelsea Shaw
Date: Wed, 17 Jul 2024 15:28:27 -0500
Subject: [PATCH 01/14] update adapter to make call without params
---
ui/app/adapters/clients/activity.js | 41 ++++++++++++-------
.../unit/adapters/clients-activity-test.js | 30 ++++++++++----
2 files changed, 49 insertions(+), 22 deletions(-)
diff --git a/ui/app/adapters/clients/activity.js b/ui/app/adapters/clients/activity.js
index 3e9455228e94..419d951fabe2 100644
--- a/ui/app/adapters/clients/activity.js
+++ b/ui/app/adapters/clients/activity.js
@@ -8,31 +8,42 @@ import { formatDateObject } from 'core/utils/client-count-utils';
import { debug } from '@ember/debug';
export default class ActivityAdapter extends ApplicationAdapter {
+ formatTimeParam(dateObj, isEnd = false) {
+ let formatted;
+ if (dateObj) {
+ try {
+ const iso = dateObj.timestamp || formatDateObject(dateObj, isEnd);
+ formatted = iso;
+ } catch (e) {
+ // carry on
+ }
+ }
+ return formatted;
+ }
// javascript localizes new Date() objects but all activity log data is stored in UTC
// 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
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;
+ const query = {};
+ const start = this.formatTimeParam(queryParams?.start_time);
+ const end = this.formatTimeParam(queryParams?.end_time, true);
+ if (start) {
+ query.start_time = start;
}
- let { start_time, end_time } = queryParams;
- start_time = start_time.timestamp || formatDateObject(start_time);
- end_time = end_time.timestamp || formatDateObject(end_time, true);
- return { start_time, end_time };
+ if (end) {
+ query.end_time = end;
+ }
+ return query;
}
queryRecord(store, type, query) {
const url = `${this.buildURL()}/internal/counters/activity`;
const queryParams = this.formatQueryParams(query);
- if (queryParams) {
- return this.ajax(url, 'GET', { data: queryParams }).then((resp) => {
- const response = resp || {};
- response.id = response.request_id || 'no-data';
- return response;
- });
- }
+ return this.ajax(url, 'GET', { data: queryParams }).then((resp) => {
+ const response = resp || {};
+ response.id = response.request_id || 'no-data';
+ return response;
+ });
}
urlForFindRecord(id) {
diff --git a/ui/tests/unit/adapters/clients-activity-test.js b/ui/tests/unit/adapters/clients-activity-test.js
index 7d23d1e9758b..0e732c793342 100644
--- a/ui/tests/unit/adapters/clients-activity-test.js
+++ b/ui/tests/unit/adapters/clients-activity-test.js
@@ -137,17 +137,33 @@ module('Unit | Adapter | clients activity', function (hooks) {
this.store.queryRecord(this.modelName, queryParams);
});
- test('it sends current billing period boolean if provided', async function (assert) {
+ test('it sends without query if no dates 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'
- );
+ assert.propEqual(req.queryParams, {});
+ });
+
+ this.store.queryRecord(this.modelName, { foo: 'bar' });
+ });
+
+ test('it sends without query if no valid dates provided', async function (assert) {
+ assert.expect(1);
+
+ this.server.get('sys/internal/counters/activity', (schema, req) => {
+ assert.propEqual(req.queryParams, {});
+ });
+
+ this.store.queryRecord(this.modelName, { start_time: 'bar' });
+ });
+
+ test('it handles empty query gracefully', async function (assert) {
+ assert.expect(1);
+
+ this.server.get('sys/internal/counters/activity', (schema, req) => {
+ assert.propEqual(req.queryParams, {});
});
- this.store.queryRecord(this.modelName, { current_billing_period: true });
+ this.store.queryRecord(this.modelName, {});
});
});
From 07ab143f8cddaa2ceb6fdc629737d89d8f42b2d8 Mon Sep 17 00:00:00 2001
From: Chelsea Shaw
Date: Wed, 17 Jul 2024 15:44:51 -0500
Subject: [PATCH 02/14] Update counts in route, and downstream effects
---
ui/app/components/clients/activity.ts | 14 +---
ui/app/components/clients/page/counts.hbs | 4 +-
ui/app/components/clients/page/counts.ts | 30 ++++-----
ui/app/components/clients/page/overview.hbs | 4 +-
ui/app/routes/vault/cluster/clients/counts.ts | 65 +++++++++++++------
ui/lib/core/addon/utils/client-count-utils.ts | 11 ----
.../utils/client-count-utils-test.js | 35 ----------
7 files changed, 63 insertions(+), 100 deletions(-)
diff --git a/ui/app/components/clients/activity.ts b/ui/app/components/clients/activity.ts
index f22134b94a43..10a419b2e992 100644
--- a/ui/app/components/clients/activity.ts
+++ b/ui/app/components/clients/activity.ts
@@ -7,7 +7,7 @@
// contains getters that filter and extract data from activity model for use in charts
import Component from '@glimmer/component';
-import { isSameMonth, fromUnixTime } from 'date-fns';
+import { isSameMonth } from 'date-fns';
import { parseAPITimestamp } from 'core/utils/date-formatters';
import { calculateAverage } from 'vault/utils/chart-helpers';
import { filterVersionHistory, hasMountsKey, hasNamespacesKey } from 'core/utils/client-count-utils';
@@ -24,8 +24,8 @@ import type {
interface Args {
activity: ClientsActivityModel;
versionHistory: ClientsVersionHistoryModel[];
- startTimestamp: number;
- endTimestamp: number;
+ startTimestamp: string;
+ endTimestamp: string;
namespace: string;
mountPath: string;
}
@@ -40,14 +40,6 @@ export default class ClientsActivityComponent extends Component {
return calculateAverage(data, key);
};
- get startTimeISO() {
- return fromUnixTime(this.args.startTimestamp).toISOString();
- }
-
- get endTimeISO() {
- return fromUnixTime(this.args.endTimestamp).toISOString();
- }
-
get byMonthActivityData() {
const { activity, namespace } = this.args;
return namespace ? this.filteredActivityByMonth : activity.byMonth;
diff --git a/ui/app/components/clients/page/counts.hbs b/ui/app/components/clients/page/counts.hbs
index bb369ced1f11..38b8fd840cc1 100644
--- a/ui/app/components/clients/page/counts.hbs
+++ b/ui/app/components/clients/page/counts.hbs
@@ -19,8 +19,8 @@
diff --git a/ui/app/components/clients/page/counts.ts b/ui/app/components/clients/page/counts.ts
index b2cf003dddc4..bd53145a54b3 100644
--- a/ui/app/components/clients/page/counts.ts
+++ b/ui/app/components/clients/page/counts.ts
@@ -6,7 +6,7 @@
import Component from '@glimmer/component';
import { service } from '@ember/service';
import { action } from '@ember/object';
-import { fromUnixTime, isSameMonth, isAfter } from 'date-fns';
+import { isSameMonth, isAfter } from 'date-fns';
import { parseAPITimestamp } from 'core/utils/date-formatters';
import { filterVersionHistory } from 'core/utils/client-count-utils';
@@ -21,11 +21,11 @@ interface Args {
activity: ClientsActivityModel;
activityError?: AdapterError;
config: ClientsConfigModel;
- endTimestamp: number;
+ endTimestamp: string; // ISO format
mountPath: string;
namespace: string;
onFilterChange: CallableFunction;
- startTimestamp: number;
+ startTimestamp: string; // ISO format
versionHistory: ClientsVersionHistoryModel[];
}
@@ -34,29 +34,21 @@ export default class ClientsCountsPageComponent extends Component {
@service declare readonly version: VersionService;
@service declare readonly store: StoreService;
- get startTimestampISO() {
- return this.args.startTimestamp ? fromUnixTime(this.args.startTimestamp).toISOString() : null;
- }
-
- get endTimestampISO() {
- return this.args.endTimestamp ? fromUnixTime(this.args.endTimestamp).toISOString() : null;
- }
-
get formattedStartDate() {
- return this.startTimestampISO ? parseAPITimestamp(this.startTimestampISO, 'MMMM yyyy') : null;
+ return this.args.startTimestamp ? parseAPITimestamp(this.args.startTimestamp, 'MMMM yyyy') : null;
}
// returns text for empty state message if noActivityData
get dateRangeMessage() {
- if (this.startTimestampISO && this.endTimestampISO) {
+ if (this.args.startTimestamp && this.args.endTimestamp) {
const endMonth = isSameMonth(
- parseAPITimestamp(this.startTimestampISO) as Date,
- parseAPITimestamp(this.endTimestampISO) as Date
+ parseAPITimestamp(this.args.startTimestamp) as Date,
+ parseAPITimestamp(this.args.endTimestamp) as Date
)
? ''
- : `to ${parseAPITimestamp(this.endTimestampISO, 'MMMM yyyy')}`;
+ : `to ${parseAPITimestamp(this.args.endTimestamp, 'MMMM yyyy')}`;
// completes the message 'No data received from { dateRangeMessage }'
- return `from ${parseAPITimestamp(this.startTimestampISO, 'MMMM yyyy')} ${endMonth}`;
+ return `from ${parseAPITimestamp(this.args.startTimestamp, 'MMMM yyyy')} ${endMonth}`;
}
return null;
}
@@ -127,9 +119,9 @@ export default class ClientsCountsPageComponent extends Component {
// show banner if startTime returned from activity log (response) is after the queried startTime
const { activity, config } = this.args;
const activityStartDateObject = parseAPITimestamp(activity.startTime) as Date;
- const queryStartDateObject = parseAPITimestamp(this.startTimestampISO) as Date;
+ const queryStartDateObject = parseAPITimestamp(this.args.startTimestamp) as Date;
const isEnterprise =
- this.startTimestampISO === config.billingStartTimestamp?.toISOString() && this.version.isEnterprise;
+ this.args.startTimestamp === config.billingStartTimestamp?.toISOString() && this.version.isEnterprise;
const message = isEnterprise ? 'Your license start date is' : 'You requested data from';
if (
diff --git a/ui/app/components/clients/page/overview.hbs b/ui/app/components/clients/page/overview.hbs
index f069423df279..e8abfc6abfed 100644
--- a/ui/app/components/clients/page/overview.hbs
+++ b/ui/app/components/clients/page/overview.hbs
@@ -21,8 +21,8 @@
@totalClientAttribution={{this.totalClientAttribution}}
@newClientAttribution={{this.newClientAttribution}}
@selectedNamespace={{@namespace}}
- @startTimestamp={{this.startTimeISO}}
- @endTimestamp={{this.endTimeISO}}
+ @startTimestamp={{@startTimestamp}}
+ @endTimestamp={{@endTimestamp}}
@responseTimestamp={{@activity.responseTimestamp}}
@isHistoricalMonth={{and (not this.isCurrentMonth) (not this.isDateRange)}}
@upgradesDuringActivity={{this.upgradesDuringActivity}}
diff --git a/ui/app/routes/vault/cluster/clients/counts.ts b/ui/app/routes/vault/cluster/clients/counts.ts
index b2322970db80..814a51da8ba8 100644
--- a/ui/app/routes/vault/cluster/clients/counts.ts
+++ b/ui/app/routes/vault/cluster/clients/counts.ts
@@ -5,8 +5,7 @@
import Route from '@ember/routing/route';
import { service } from '@ember/service';
-import timestamp from 'core/utils/timestamp';
-import { getUnixTime } from 'date-fns';
+import { fromUnixTime } from 'date-fns';
import type FlagsService from 'vault/services/flags';
import type StoreService from 'vault/services/store';
@@ -14,7 +13,6 @@ import type VersionService from 'vault/services/version';
import type { ModelFrom } from 'vault/vault/route';
import type ClientsRoute from '../clients';
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;
@@ -39,38 +37,65 @@ export default class ClientsCountsRoute extends Route {
return this.flags.fetchActivatedFlags();
}
- async getActivity(start_time: number | null, end_time: number) {
+ paramOrResponseTimestamp(
+ qpMillisString: string | number | undefined,
+ activityTimeStamp: string | undefined
+ ) {
+ let timestamp: string | undefined;
+ const millis = Number(qpMillisString);
+ if (!isNaN(millis)) {
+ timestamp = fromUnixTime(millis).toISOString();
+ }
+ // fallback to activity timestamp only if there was no query param
+ if (!timestamp && activityTimeStamp) {
+ timestamp = activityTimeStamp;
+ }
+ return timestamp;
+ }
+
+ async getActivity(params: ClientsCountsRouteParams) {
let activity, activityError;
- // 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) {
+ const query = {
+ // start and end params are optional -- if not provided, will fallback to API default
+ start_time: this.formatTimeQuery(params?.start_time),
+ end_time: this.formatTimeQuery(params?.end_time),
+ };
+ // if CE without start time we want to skip the activity call
+ // so that the user is forced to choose a date range
+ if (this.version.isEnterprise || params.start_time) {
try {
- activity = await this.store.queryRecord('clients/activity', {
- start_time: { timestamp: start_time },
- end_time: { timestamp: end_time },
- });
+ activity = await this.store.queryRecord('clients/activity', query);
} catch (error) {
activityError = error;
}
}
- return { activity, activityError };
+ return {
+ activity,
+ activityError,
+ };
+ }
+
+ // Takes the string URL param and formats it as the adapter expects it,
+ // if it exists and is valid
+ formatTimeQuery(param: string | number | undefined) {
+ let timeParam: { timestamp: number } | undefined;
+ const millis = Number(param);
+ if (!isNaN(millis)) {
+ timeParam = { timestamp: millis };
+ }
+ return timeParam;
}
async model(params: ClientsCountsRouteParams) {
const { config, versionHistory } = this.modelFor('vault.cluster.clients') as ModelFrom;
- // only enterprise versions will have a relevant billing start date, if null users must select initial start time
- const startTime = setStartTimeQuery(this.version.isEnterprise, config);
-
- 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 { activity, activityError } = await this.getActivity(params);
return {
activity,
activityError,
config,
- endTimestamp,
- startTimestamp,
+ startTimestamp: this.paramOrResponseTimestamp(params?.start_time, activity.startDate),
+ endTimestamp: this.paramOrResponseTimestamp(params?.end_time, activity.endDate),
versionHistory,
};
}
diff --git a/ui/lib/core/addon/utils/client-count-utils.ts b/ui/lib/core/addon/utils/client-count-utils.ts
index 69091f888ea1..243cd35741c5 100644
--- a/ui/lib/core/addon/utils/client-count-utils.ts
+++ b/ui/lib/core/addon/utils/client-count-utils.ts
@@ -66,17 +66,6 @@ export const filterVersionHistory = (
return [];
};
-export const setStartTimeQuery = (
- isEnterprise: boolean,
- config: ClientsConfigModel | Record
-) => {
- // 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;
diff --git a/ui/tests/integration/utils/client-count-utils-test.js b/ui/tests/integration/utils/client-count-utils-test.js
index d6da1a5a04ef..703d098dc54f 100644
--- a/ui/tests/integration/utils/client-count-utils-test.js
+++ b/ui/tests/integration/utils/client-count-utils-test.js
@@ -13,7 +13,6 @@ import {
destructureClientCounts,
namespaceArrayToObject,
sortMonthsByTimestamp,
- setStartTimeQuery,
} from 'core/utils/client-count-utils';
import clientsHandler from 'vault/mirage/handlers/clients';
import {
@@ -28,9 +27,6 @@ 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);
@@ -443,35 +439,4 @@ 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'
- );
- });
});
From aa27711c8090cb7c42698b5ff8390ed5f1c086d7 Mon Sep 17 00:00:00 2001
From: Chelsea Shaw
Date: Fri, 19 Jul 2024 09:53:42 -0500
Subject: [PATCH 03/14] safeguard against empty activity response, update tests
---
ui/app/routes/vault/cluster/clients/counts.ts | 5 ++---
ui/tests/acceptance/clients/counts-test.js | 8 ++++----
.../components/clients/page/counts-test.js | 20 +++++++++++++------
3 files changed, 20 insertions(+), 13 deletions(-)
diff --git a/ui/app/routes/vault/cluster/clients/counts.ts b/ui/app/routes/vault/cluster/clients/counts.ts
index 814a51da8ba8..85777dd8d428 100644
--- a/ui/app/routes/vault/cluster/clients/counts.ts
+++ b/ui/app/routes/vault/cluster/clients/counts.ts
@@ -89,13 +89,12 @@ export default class ClientsCountsRoute extends Route {
async model(params: ClientsCountsRouteParams) {
const { config, versionHistory } = this.modelFor('vault.cluster.clients') as ModelFrom;
const { activity, activityError } = await this.getActivity(params);
-
return {
activity,
activityError,
config,
- startTimestamp: this.paramOrResponseTimestamp(params?.start_time, activity.startDate),
- endTimestamp: this.paramOrResponseTimestamp(params?.end_time, activity.endDate),
+ startTimestamp: this.paramOrResponseTimestamp(params?.start_time, activity?.startTime),
+ endTimestamp: this.paramOrResponseTimestamp(params?.end_time, activity?.endTime),
versionHistory,
};
}
diff --git a/ui/tests/acceptance/clients/counts-test.js b/ui/tests/acceptance/clients/counts-test.js
index 4c283f4b83e3..ba99641bc9ed 100644
--- a/ui/tests/acceptance/clients/counts-test.js
+++ b/ui/tests/acceptance/clients/counts-test.js
@@ -43,19 +43,19 @@ module('Acceptance | clients | counts', function (hooks) {
test('it should persist filter query params between child routes', async function (assert) {
await visit('/vault/clients/counts/overview');
await click(CLIENT_COUNT.dateRange.edit);
- await fillIn(CLIENT_COUNT.dateRange.editDate('start'), '2020-03');
- await fillIn(CLIENT_COUNT.dateRange.editDate('start'), '2022-02');
+ await fillIn(CLIENT_COUNT.dateRange.editDate('start'), '2023-03');
+ await fillIn(CLIENT_COUNT.dateRange.editDate('end'), '2023-10');
await click(GENERAL.saveButton);
assert.strictEqual(
currentURL(),
- '/vault/clients/counts/overview?end_time=1706659200&start_time=1643673600',
+ '/vault/clients/counts/overview?end_time=1698710400&start_time=1677628800',
'Start and end times added as query params'
);
await click(GENERAL.tab('token'));
assert.strictEqual(
currentURL(),
- '/vault/clients/counts/token?end_time=1706659200&start_time=1643673600',
+ '/vault/clients/counts/token?end_time=1698710400&start_time=1677628800',
'Start and end times persist through child route change'
);
diff --git a/ui/tests/integration/components/clients/page/counts-test.js b/ui/tests/integration/components/clients/page/counts-test.js
index 4577d695c6df..07644a6590e9 100644
--- a/ui/tests/integration/components/clients/page/counts-test.js
+++ b/ui/tests/integration/components/clients/page/counts-test.js
@@ -9,7 +9,7 @@ import { setupMirage } from 'ember-cli-mirage/test-support';
import { render, click, findAll, fillIn } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import clientsHandler, { LICENSE_START, STATIC_NOW } from 'vault/mirage/handlers/clients';
-import { getUnixTime } from 'date-fns';
+import { fromUnixTime, getUnixTime } from 'date-fns';
import { GENERAL } from 'vault/tests/helpers/general-selectors';
import { CLIENT_COUNT } from 'vault/tests/helpers/clients/client-count-selectors';
import { selectChoose } from 'ember-power-select/test-support';
@@ -19,6 +19,8 @@ import { allowAllCapabilitiesStub } from 'vault/tests/helpers/stubs';
const START_TIME = getUnixTime(LICENSE_START);
const END_TIME = getUnixTime(STATIC_NOW);
+const START_ISO = LICENSE_START.toISOString();
+const END_ISO = STATIC_NOW.toISOString();
module('Integration | Component | clients | Page::Counts', function (hooks) {
setupRenderingTest(hooks);
@@ -35,8 +37,8 @@ module('Integration | Component | clients | Page::Counts', function (hooks) {
};
this.activity = await this.store.queryRecord('clients/activity', activityQuery);
this.config = await this.store.queryRecord('clients/config', {});
- this.startTimestamp = START_TIME;
- this.endTimestamp = END_TIME;
+ this.startTimestamp = START_ISO;
+ this.endTimestamp = END_ISO;
this.versionHistory = [];
this.renderComponent = () =>
render(hbs`
@@ -103,8 +105,14 @@ module('Integration | Component | clients | Page::Counts', function (hooks) {
const expected = { start_time: START_TIME, end_time: END_TIME };
this.onFilterChange = (params) => {
assert.deepEqual(params, expected, 'Correct values sent on filter change');
- this.set('startTimestamp', params.start_time || START_TIME);
- this.set('endTimestamp', params.end_time || END_TIME);
+ // in the app, the timestamp choices trigger a qp refresh as millis from epoch,
+ // but in the model they are translated from millis to ISO timestamps before being
+ // passed to this component. Mock that behavior here.
+ this.set(
+ 'startTimestamp',
+ params?.start_time ? fromUnixTime(params.start_time).toISOString() : START_ISO
+ );
+ this.set('endTimestamp', params?.end_time ? fromUnixTime(params.end_time).toISOString() : END_ISO);
};
// page starts with default billing dates, which are july 23 - jan 24
await this.renderComponent();
@@ -168,7 +176,7 @@ module('Integration | Component | clients | Page::Counts', function (hooks) {
});
test('it should render start time discrepancy alert', async function (assert) {
- this.startTimestamp = getUnixTime(new Date('2022-06-01T00:00:00Z'));
+ this.startTimestamp = new Date('2022-06-01T00:00:00Z').toISOString();
await this.renderComponent();
From aea20ede2eeee126c6a2a6babce078701455faa2 Mon Sep 17 00:00:00 2001
From: Chelsea Shaw
Date: Fri, 19 Jul 2024 09:55:43 -0500
Subject: [PATCH 04/14] edit test so it plays nicely between ent & CE
---
ui/app/components/clients/date-range.hbs | 2 +-
ui/tests/helpers/clients/client-count-selectors.ts | 1 -
ui/tests/integration/components/clients/date-range-test.js | 4 ++--
ui/tests/integration/components/clients/page/counts-test.js | 2 +-
4 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/ui/app/components/clients/date-range.hbs b/ui/app/components/clients/date-range.hbs
index 0d5ed63634bc..1298345eb92b 100644
--- a/ui/app/components/clients/date-range.hbs
+++ b/ui/app/components/clients/date-range.hbs
@@ -27,7 +27,7 @@
@text="Set date range"
@icon="edit"
{{on "click" (fn (mut this.showEditModal) true)}}
- data-test-set-date-range
+ data-test-date-range-edit
/>
{{/if}}
diff --git a/ui/tests/helpers/clients/client-count-selectors.ts b/ui/tests/helpers/clients/client-count-selectors.ts
index 53691cfabfa3..ef820a6860d2 100644
--- a/ui/tests/helpers/clients/client-count-selectors.ts
+++ b/ui/tests/helpers/clients/client-count-selectors.ts
@@ -14,7 +14,6 @@ export const CLIENT_COUNT = {
},
dateRange: {
dateDisplay: (name: string) => (name ? `[data-test-date-range="${name}"]` : '[data-test-date-range]'),
- set: '[data-test-set-date-range]',
edit: '[data-test-date-range-edit]',
editModal: '[data-test-date-range-edit-modal]',
editDate: (name: string) => `[data-test-date-edit="${name}"]`,
diff --git a/ui/tests/integration/components/clients/date-range-test.js b/ui/tests/integration/components/clients/date-range-test.js
index beec2fe491f8..2a5c6bb60976 100644
--- a/ui/tests/integration/components/clients/date-range-test.js
+++ b/ui/tests/integration/components/clients/date-range-test.js
@@ -33,9 +33,9 @@ module('Integration | Component | clients/date-range', function (hooks) {
this.startTime = undefined;
await this.renderComponent();
- assert.dom(DATE_RANGE.set).exists();
+ assert.dom(DATE_RANGE.edit).hasText('Set date range');
- await click(DATE_RANGE.set);
+ await click(DATE_RANGE.edit);
assert.dom(DATE_RANGE.editModal).exists();
assert.dom(DATE_RANGE.editDate('start')).hasValue('');
await fillIn(DATE_RANGE.editDate('start'), '2018-01');
diff --git a/ui/tests/integration/components/clients/page/counts-test.js b/ui/tests/integration/components/clients/page/counts-test.js
index 07644a6590e9..df14cf43f3c9 100644
--- a/ui/tests/integration/components/clients/page/counts-test.js
+++ b/ui/tests/integration/components/clients/page/counts-test.js
@@ -244,7 +244,7 @@ module('Integration | Component | clients | Page::Counts', function (hooks) {
await this.renderComponent();
assert.dom(GENERAL.emptyStateTitle).hasText('No start date found', 'Empty state renders');
- assert.dom(CLIENT_COUNT.dateRange.set).exists();
+ assert.dom(CLIENT_COUNT.dateRange.edit).hasText('Set date range');
});
test('it should render catch all empty state', async function (assert) {
From c8b5fce3d375bf671c9fba08567524fc8188ecf4 Mon Sep 17 00:00:00 2001
From: Chelsea Shaw
Date: Fri, 19 Jul 2024 11:21:44 -0500
Subject: [PATCH 05/14] use first month timestamp instead of startTime which
reflects first month with data
---
ui/app/routes/vault/cluster/clients/counts.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ui/app/routes/vault/cluster/clients/counts.ts b/ui/app/routes/vault/cluster/clients/counts.ts
index 85777dd8d428..ab7e35a6b2f1 100644
--- a/ui/app/routes/vault/cluster/clients/counts.ts
+++ b/ui/app/routes/vault/cluster/clients/counts.ts
@@ -93,7 +93,7 @@ export default class ClientsCountsRoute extends Route {
activity,
activityError,
config,
- startTimestamp: this.paramOrResponseTimestamp(params?.start_time, activity?.startTime),
+ startTimestamp: this.paramOrResponseTimestamp(params?.start_time, activity?.byMonth[0].timestamp),
endTimestamp: this.paramOrResponseTimestamp(params?.end_time, activity?.endTime),
versionHistory,
};
From cbb037ea2258d98d59a9d044df867d6e410a9e50 Mon Sep 17 00:00:00 2001
From: Chelsea Shaw
Date: Fri, 19 Jul 2024 11:56:03 -0500
Subject: [PATCH 06/14] Update part of activity response used for start date,
add test
---
ui/app/routes/vault/cluster/clients/counts.ts | 2 +-
ui/tests/acceptance/clients/counts-test.js | 79 +++++++++++++++++++
.../clients/counts/overview-test.js | 2 +-
3 files changed, 81 insertions(+), 2 deletions(-)
diff --git a/ui/app/routes/vault/cluster/clients/counts.ts b/ui/app/routes/vault/cluster/clients/counts.ts
index ab7e35a6b2f1..81689bc931f3 100644
--- a/ui/app/routes/vault/cluster/clients/counts.ts
+++ b/ui/app/routes/vault/cluster/clients/counts.ts
@@ -93,7 +93,7 @@ export default class ClientsCountsRoute extends Route {
activity,
activityError,
config,
- startTimestamp: this.paramOrResponseTimestamp(params?.start_time, activity?.byMonth[0].timestamp),
+ startTimestamp: this.paramOrResponseTimestamp(params?.start_time, activity?.byMonth[0]?.timestamp),
endTimestamp: this.paramOrResponseTimestamp(params?.end_time, activity?.endTime),
versionHistory,
};
diff --git a/ui/tests/acceptance/clients/counts-test.js b/ui/tests/acceptance/clients/counts-test.js
index ba99641bc9ed..ab32f0718bb4 100644
--- a/ui/tests/acceptance/clients/counts-test.js
+++ b/ui/tests/acceptance/clients/counts-test.js
@@ -81,4 +81,83 @@ module('Acceptance | clients | counts', function (hooks) {
'You must be granted permissions to view this page. Ask your administrator if you think you should have access to the /v1/sys/internal/counters/activity endpoint.'
);
});
+
+ test('it should use the first month timestamp from default response rather than response start_time', async function (assert) {
+ assert.expect(2);
+ const getCounts = () => {
+ return {
+ acme_clients: 0,
+ clients: 0,
+ entity_clients: 0,
+ non_entity_clients: 0,
+ secret_syncs: 0,
+ distinct_entities: 0,
+ non_entity_tokens: 1,
+ };
+ };
+ // set to enterprise because when community the initial activity call is skipped
+ this.owner.lookup('service:version').type = 'enterprise';
+ this.server.get('/sys/internal/counters/activity', function () {
+ return {
+ request_id: 'some-activity-id',
+ data: {
+ start_time: '2023-04-01T00:00:00Z', // reflects the first month with data
+ end_time: '2023-04-30T00:00:00Z',
+ by_namespace: [],
+ months: [
+ {
+ timestamp: '2023-02-01T00:00:00Z',
+ counts: null,
+ namespaces: null,
+ new_clients: null,
+ },
+ {
+ timestamp: '2023-03-01T00:00:00Z',
+ counts: null,
+ namespaces: null,
+ new_clients: null,
+ },
+ {
+ timestamp: '2023-04-01T00:00:00Z',
+ counts: getCounts(),
+ namespaces: [
+ {
+ namespace_id: 'root',
+ namespace_path: '',
+ counts: getCounts(),
+ mounts: [
+ {
+ mount_path: 'auth/authid/0',
+ counts: getCounts(),
+ },
+ ],
+ },
+ ],
+ new_clients: {
+ counts: getCounts(),
+ namespaces: [
+ {
+ namespace_id: 'root',
+ namespace_path: '',
+ counts: getCounts(),
+ mounts: [
+ {
+ mount_path: 'auth/authid/0',
+ counts: getCounts(),
+ },
+ ],
+ },
+ ],
+ },
+ },
+ ],
+ total: getCounts(),
+ },
+ };
+ });
+ await visit('/vault/clients/counts/overview');
+ assert.dom(CLIENT_COUNT.dateRange.dateDisplay('start')).hasText('February 2023');
+ assert.dom(CLIENT_COUNT.dateRange.dateDisplay('end')).hasText('April 2023');
+ assert.dom(CLIENT_COUNT.counts.startDiscrepancy).exists();
+ });
});
diff --git a/ui/tests/acceptance/clients/counts/overview-test.js b/ui/tests/acceptance/clients/counts/overview-test.js
index 6e5ba2dedc33..56d8ce5000ad 100644
--- a/ui/tests/acceptance/clients/counts/overview-test.js
+++ b/ui/tests/acceptance/clients/counts/overview-test.js
@@ -72,7 +72,7 @@ module('Acceptance | clients | overview', function (hooks) {
.exists('new client attribution has empty state');
assert
.dom(GENERAL.emptyStateSubtitle)
- .hasText('There are no new clients for this namespace during this time period. ');
+ .hasText('There are no new clients for this namespace during this time period.');
assert.dom(CHARTS.container('total-clients')).exists('total client attribution chart shows');
// reset to billing period
From 32dc1613c602db15cee0a844861bc57bedce155d Mon Sep 17 00:00:00 2001
From: Chelsea Shaw
Date: Fri, 19 Jul 2024 12:01:23 -0500
Subject: [PATCH 07/14] Add changelog
---
changelog/27816.txt | 3 +++
1 file changed, 3 insertions(+)
create mode 100644 changelog/27816.txt
diff --git a/changelog/27816.txt b/changelog/27816.txt
new file mode 100644
index 000000000000..92dd2d7bb90c
--- /dev/null
+++ b/changelog/27816.txt
@@ -0,0 +1,3 @@
+```release-note:improvement
+ui: remove initial start/end parameters on the activity call for client counts dashboard.
+```
\ No newline at end of file
From 7d67067a05748b5f982f85d095ff7eaf53fe1725 Mon Sep 17 00:00:00 2001
From: Chelsea Shaw
Date: Fri, 19 Jul 2024 12:15:59 -0500
Subject: [PATCH 08/14] remove expect
---
ui/tests/acceptance/clients/counts-test.js | 1 -
1 file changed, 1 deletion(-)
diff --git a/ui/tests/acceptance/clients/counts-test.js b/ui/tests/acceptance/clients/counts-test.js
index ab32f0718bb4..6db0217e1074 100644
--- a/ui/tests/acceptance/clients/counts-test.js
+++ b/ui/tests/acceptance/clients/counts-test.js
@@ -83,7 +83,6 @@ module('Acceptance | clients | counts', function (hooks) {
});
test('it should use the first month timestamp from default response rather than response start_time', async function (assert) {
- assert.expect(2);
const getCounts = () => {
return {
acme_clients: 0,
From d93988663eb98c1bb6c7c263cb445c388ec72ee9 Mon Sep 17 00:00:00 2001
From: Chelsea Shaw
Date: Fri, 19 Jul 2024 13:04:31 -0500
Subject: [PATCH 09/14] Remove language that implies CE can use default params
on activity endpoint
---
ui/app/components/clients/date-range.hbs | 2 +-
ui/app/components/clients/date-range.ts | 4 +-
.../components/clients/date-range-test.js | 41 ++++++++++++++++++-
3 files changed, 43 insertions(+), 4 deletions(-)
diff --git a/ui/app/components/clients/date-range.hbs b/ui/app/components/clients/date-range.hbs
index 1298345eb92b..c652c9f9121b 100644
--- a/ui/app/components/clients/date-range.hbs
+++ b/ui/app/components/clients/date-range.hbs
@@ -87,7 +87,7 @@
data-test-date-range-validation
>{{this.validationError}}
{{/if}}
- {{#if this.useDefaultDates}}
+ {{#if (and this.version.isEnterprise this.useDefaultDates)}}
Dashboard will use the default date range from the API.
diff --git a/ui/app/components/clients/date-range.ts b/ui/app/components/clients/date-range.ts
index 4704a7c74589..9e87e413cf8b 100644
--- a/ui/app/components/clients/date-range.ts
+++ b/ui/app/components/clients/date-range.ts
@@ -67,8 +67,8 @@ export default class ClientsDateRangeComponent extends Component {
}
get validationError() {
- if (this.useDefaultDates) {
- // this means we want to reset, which is fine
+ if (this.useDefaultDates && this.version.isEnterprise) {
+ // this means we want to reset, which is fine for ent only
return null;
}
if (!this.startDate || !this.endDate) {
diff --git a/ui/tests/integration/components/clients/date-range-test.js b/ui/tests/integration/components/clients/date-range-test.js
index 2a5c6bb60976..257c5b7ca86e 100644
--- a/ui/tests/integration/components/clients/date-range-test.js
+++ b/ui/tests/integration/components/clients/date-range-test.js
@@ -33,6 +33,8 @@ module('Integration | Component | clients/date-range', function (hooks) {
this.startTime = undefined;
await this.renderComponent();
+ assert.dom(DATE_RANGE.dateDisplay('start')).doesNotExist();
+ assert.dom(DATE_RANGE.dateDisplay('end')).doesNotExist();
assert.dom(DATE_RANGE.edit).hasText('Set date range');
await click(DATE_RANGE.edit);
@@ -50,11 +52,13 @@ module('Integration | Component | clients/date-range', function (hooks) {
assert.dom(DATE_RANGE.editModal).doesNotExist('closes modal');
});
- test('it renders the date range passed and can reset it', async function (assert) {
+ test('it renders the date range passed and can reset it (ent)', async function (assert) {
+ this.owner('service:version').version = 'enterprise';
await this.renderComponent();
assert.dom(DATE_RANGE.dateDisplay('start')).hasText('January 2018');
assert.dom(DATE_RANGE.dateDisplay('end')).hasText('January 2019');
+ assert.dom(DATE_RANGE.edit).hasText('Edit');
await click(DATE_RANGE.edit);
assert.dom(DATE_RANGE.editModal).exists();
@@ -70,7 +74,30 @@ module('Integration | Component | clients/date-range', function (hooks) {
assert.deepEqual(this.onChange.args[0], [{ start_time: undefined, end_time: undefined }]);
});
+ test('it renders the date range passed and cannot reset it when community', async function (assert) {
+ this.owner('service:version').version = 'community';
+ await this.renderComponent();
+
+ assert.dom(DATE_RANGE.dateDisplay('start')).hasText('January 2018');
+ assert.dom(DATE_RANGE.dateDisplay('end')).hasText('January 2019');
+ assert.dom(DATE_RANGE.edit).hasText('Edit');
+
+ await click(DATE_RANGE.edit);
+ assert.dom(DATE_RANGE.editModal).exists();
+ assert.dom(DATE_RANGE.editDate('start')).hasValue('2018-01');
+ assert.dom(DATE_RANGE.editDate('end')).hasValue('2019-01');
+ assert.dom(DATE_RANGE.defaultRangeAlert).doesNotExist();
+
+ await click(DATE_RANGE.editDate('reset'));
+ assert.dom(DATE_RANGE.editDate('start')).hasValue('');
+ assert.dom(DATE_RANGE.editDate('end')).hasValue('');
+ assert.dom(DATE_RANGE.validation).hasText('You must supply both start and end dates.');
+ await click(GENERAL.saveButton);
+ assert.false(this.onChange.called);
+ });
+
test('it does not trigger onChange if date range invalid', async function (assert) {
+ this.owner('service:version').version = 'enterprise';
await this.renderComponent();
await click(DATE_RANGE.edit);
@@ -90,6 +117,18 @@ module('Integration | Component | clients/date-range', function (hooks) {
assert.dom(DATE_RANGE.editModal).doesNotExist();
});
+ test('it does not trigger onChange when reset and CE', async function (assert) {
+ this.owner('service:version').version = 'community';
+ await this.renderComponent();
+
+ await click(DATE_RANGE.edit);
+
+ await click(DATE_RANGE.reset);
+ assert.dom(DATE_RANGE.validation).hasText('You must supply both start and end dates.');
+ await click(GENERAL.saveButton);
+ assert.false(this.onChange.called);
+ });
+
test('it resets the tracked values on close', async function (assert) {
await this.renderComponent();
From ac5277ae79b31f1f16bbaa06a75546b1d8ec3efe Mon Sep 17 00:00:00 2001
From: Chelsea Shaw
Date: Fri, 19 Jul 2024 13:19:08 -0500
Subject: [PATCH 10/14] whoops used this.owner wrong
---
.../integration/components/clients/date-range-test.js | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/ui/tests/integration/components/clients/date-range-test.js b/ui/tests/integration/components/clients/date-range-test.js
index 257c5b7ca86e..668d1147c54c 100644
--- a/ui/tests/integration/components/clients/date-range-test.js
+++ b/ui/tests/integration/components/clients/date-range-test.js
@@ -53,7 +53,7 @@ module('Integration | Component | clients/date-range', function (hooks) {
});
test('it renders the date range passed and can reset it (ent)', async function (assert) {
- this.owner('service:version').version = 'enterprise';
+ this.owner.lookup('service:version').version = 'enterprise';
await this.renderComponent();
assert.dom(DATE_RANGE.dateDisplay('start')).hasText('January 2018');
@@ -75,7 +75,7 @@ module('Integration | Component | clients/date-range', function (hooks) {
});
test('it renders the date range passed and cannot reset it when community', async function (assert) {
- this.owner('service:version').version = 'community';
+ this.owner.lookup('service:version').version = 'community';
await this.renderComponent();
assert.dom(DATE_RANGE.dateDisplay('start')).hasText('January 2018');
@@ -97,7 +97,7 @@ module('Integration | Component | clients/date-range', function (hooks) {
});
test('it does not trigger onChange if date range invalid', async function (assert) {
- this.owner('service:version').version = 'enterprise';
+ this.owner.lookup('service:version').version = 'enterprise';
await this.renderComponent();
await click(DATE_RANGE.edit);
@@ -118,7 +118,7 @@ module('Integration | Component | clients/date-range', function (hooks) {
});
test('it does not trigger onChange when reset and CE', async function (assert) {
- this.owner('service:version').version = 'community';
+ this.owner.lookup('service:version').version = 'community';
await this.renderComponent();
await click(DATE_RANGE.edit);
From 9784e4d6d2dd1a534bb3a3e61c403e2e7a91a602 Mon Sep 17 00:00:00 2001
From: Chelsea Shaw
Date: Tue, 30 Jul 2024 11:44:16 -0500
Subject: [PATCH 11/14] Clarify timestamp logic
---
ui/app/routes/vault/cluster/clients/counts.ts | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/ui/app/routes/vault/cluster/clients/counts.ts b/ui/app/routes/vault/cluster/clients/counts.ts
index 81689bc931f3..4170d02c4fb8 100644
--- a/ui/app/routes/vault/cluster/clients/counts.ts
+++ b/ui/app/routes/vault/cluster/clients/counts.ts
@@ -37,6 +37,9 @@ export default class ClientsCountsRoute extends Route {
return this.flags.fetchActivatedFlags();
}
+ /**
+ * This method returns the query param timestamp if it exists. If not, it returns the activity timestamp value instead.
+ */
paramOrResponseTimestamp(
qpMillisString: string | number | undefined,
activityTimeStamp: string | undefined
@@ -55,14 +58,14 @@ export default class ClientsCountsRoute extends Route {
async getActivity(params: ClientsCountsRouteParams) {
let activity, activityError;
- const query = {
- // start and end params are optional -- if not provided, will fallback to API default
- start_time: this.formatTimeQuery(params?.start_time),
- end_time: this.formatTimeQuery(params?.end_time),
- };
// if CE without start time we want to skip the activity call
// so that the user is forced to choose a date range
if (this.version.isEnterprise || params.start_time) {
+ const query = {
+ // start and end params are optional -- if not provided, will fallback to API default
+ start_time: this.formatTimeQuery(params?.start_time),
+ end_time: this.formatTimeQuery(params?.end_time),
+ };
try {
activity = await this.store.queryRecord('clients/activity', query);
} catch (error) {
@@ -93,6 +96,7 @@ export default class ClientsCountsRoute extends Route {
activity,
activityError,
config,
+ // activity.startTime corresponds to first month with data, but we want first month returned or requested
startTimestamp: this.paramOrResponseTimestamp(params?.start_time, activity?.byMonth[0]?.timestamp),
endTimestamp: this.paramOrResponseTimestamp(params?.end_time, activity?.endTime),
versionHistory,
From 17b680a324c01bb29171c5a394499c7e55429428 Mon Sep 17 00:00:00 2001
From: Chelsea Shaw
Date: Wed, 31 Jul 2024 12:02:47 -0500
Subject: [PATCH 12/14] set version.type instead of version.version
---
.../integration/components/clients/date-range-test.js | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/ui/tests/integration/components/clients/date-range-test.js b/ui/tests/integration/components/clients/date-range-test.js
index 668d1147c54c..2e3765d6a279 100644
--- a/ui/tests/integration/components/clients/date-range-test.js
+++ b/ui/tests/integration/components/clients/date-range-test.js
@@ -53,7 +53,7 @@ module('Integration | Component | clients/date-range', function (hooks) {
});
test('it renders the date range passed and can reset it (ent)', async function (assert) {
- this.owner.lookup('service:version').version = 'enterprise';
+ this.owner.lookup('service:version').type = 'enterprise';
await this.renderComponent();
assert.dom(DATE_RANGE.dateDisplay('start')).hasText('January 2018');
@@ -75,7 +75,7 @@ module('Integration | Component | clients/date-range', function (hooks) {
});
test('it renders the date range passed and cannot reset it when community', async function (assert) {
- this.owner.lookup('service:version').version = 'community';
+ this.owner.lookup('service:version').type = 'community';
await this.renderComponent();
assert.dom(DATE_RANGE.dateDisplay('start')).hasText('January 2018');
@@ -97,7 +97,7 @@ module('Integration | Component | clients/date-range', function (hooks) {
});
test('it does not trigger onChange if date range invalid', async function (assert) {
- this.owner.lookup('service:version').version = 'enterprise';
+ this.owner.lookup('service:version').type = 'enterprise';
await this.renderComponent();
await click(DATE_RANGE.edit);
@@ -118,7 +118,7 @@ module('Integration | Component | clients/date-range', function (hooks) {
});
test('it does not trigger onChange when reset and CE', async function (assert) {
- this.owner.lookup('service:version').version = 'community';
+ this.owner.lookup('service:version').type = 'community';
await this.renderComponent();
await click(DATE_RANGE.edit);
From 7a5c41550591559b95491daf0accc726076a1f10 Mon Sep 17 00:00:00 2001
From: Chelsea Shaw
Date: Wed, 31 Jul 2024 12:23:48 -0500
Subject: [PATCH 13/14] fix page::counts test
---
.../components/clients/page/counts-test.js | 113 +++++++++++-------
1 file changed, 71 insertions(+), 42 deletions(-)
diff --git a/ui/tests/integration/components/clients/page/counts-test.js b/ui/tests/integration/components/clients/page/counts-test.js
index df14cf43f3c9..874de6f82c10 100644
--- a/ui/tests/integration/components/clients/page/counts-test.js
+++ b/ui/tests/integration/components/clients/page/counts-test.js
@@ -96,48 +96,77 @@ module('Integration | Component | clients | Page::Counts', function (hooks) {
.hasText('Tracking is disabled', 'Config disabled alert renders');
});
- test('it should send correct values on start and end date change', async function (assert) {
- assert.expect(3);
- const jan23start = getUnixTime(new Date('2023-01-01T00:00:00Z'));
- const dec23end = getUnixTime(new Date('2023-12-31T00:00:00Z'));
- const jan24end = getUnixTime(new Date('2024-01-31T00:00:00Z'));
-
- const expected = { start_time: START_TIME, end_time: END_TIME };
- this.onFilterChange = (params) => {
- assert.deepEqual(params, expected, 'Correct values sent on filter change');
- // in the app, the timestamp choices trigger a qp refresh as millis from epoch,
- // but in the model they are translated from millis to ISO timestamps before being
- // passed to this component. Mock that behavior here.
- this.set(
- 'startTimestamp',
- params?.start_time ? fromUnixTime(params.start_time).toISOString() : START_ISO
- );
- this.set('endTimestamp', params?.end_time ? fromUnixTime(params.end_time).toISOString() : END_ISO);
- };
- // page starts with default billing dates, which are july 23 - jan 24
- await this.renderComponent();
-
- // First, change only the start date
- expected.start_time = jan23start;
- // the end date which is first set to STATIC_NOW gets recalculated
- // to the end of given month/year on date range change
- expected.end_time = jan24end;
- await click(CLIENT_COUNT.dateRange.edit);
- await fillIn(CLIENT_COUNT.dateRange.editDate('start'), '2023-01');
- await click(GENERAL.saveButton);
-
- // Then change only the end date
- expected.end_time = dec23end;
- await click(CLIENT_COUNT.dateRange.edit);
- await fillIn(CLIENT_COUNT.dateRange.editDate('end'), '2023-12');
- await click(GENERAL.saveButton);
-
- // Then reset to billing which should reset the params
- expected.start_time = undefined;
- expected.end_time = undefined;
- await click(CLIENT_COUNT.dateRange.edit);
- await click(CLIENT_COUNT.dateRange.reset);
- await click(GENERAL.saveButton);
+ const jan23start = getUnixTime(new Date('2023-01-01T00:00:00Z'));
+ // license start is July 2, 2024 but the component defaults to beginning of the month
+ const july23start = getUnixTime(new Date('2023-07-01T00:00:00Z'));
+ const dec23end = getUnixTime(new Date('2023-12-31T00:00:00Z'));
+ const jan24end = getUnixTime(new Date('2024-01-31T00:00:00Z'));
+ [
+ {
+ scenario: 'changing start only',
+ expected: { start_time: jan23start, end_time: jan24end },
+ editStart: '2023-01',
+ expectedStart: 'January 2023',
+ expectedEnd: 'January 2024',
+ },
+ {
+ scenario: 'changing end only',
+ expected: { start_time: july23start, end_time: dec23end },
+ editEnd: '2023-12',
+ expectedStart: 'July 2023',
+ expectedEnd: 'December 2023',
+ },
+ {
+ scenario: 'changing both',
+ expected: { start_time: jan23start, end_time: dec23end },
+ editStart: '2023-01',
+ editEnd: '2023-12',
+ expectedStart: 'January 2023',
+ expectedEnd: 'December 2023',
+ },
+ {
+ scenario: 'reset',
+ expected: { start_time: undefined, end_time: undefined },
+ reset: true,
+ expectedStart: 'July 2023',
+ expectedEnd: 'January 2024',
+ },
+ ].forEach((testCase) => {
+ test(`it should send correct millis value on filter change when ${testCase.scenario}`, async function (assert) {
+ assert.expect(5);
+ // set to enterprise so reset will save correctly
+ this.owner.lookup('service:version').type = 'enterprise';
+ this.onFilterChange = (params) => {
+ assert.deepEqual(params, testCase.expected, 'Correct values sent on filter change');
+ // in the app, the timestamp choices trigger a qp refresh as millis from epoch,
+ // but in the model they are translated from millis to ISO timestamps before being
+ // passed to this component. Mock that behavior here.
+ this.set(
+ 'startTimestamp',
+ params?.start_time ? fromUnixTime(params.start_time).toISOString() : START_ISO
+ );
+ this.set('endTimestamp', params?.end_time ? fromUnixTime(params.end_time).toISOString() : END_ISO);
+ };
+ await this.renderComponent();
+ await click(CLIENT_COUNT.dateRange.edit);
+
+ // page starts with default billing dates, which are july 23 - jan 24
+ assert.dom(CLIENT_COUNT.dateRange.editDate('start')).hasValue('2023-07');
+ assert.dom(CLIENT_COUNT.dateRange.editDate('end')).hasValue('2024-01');
+
+ if (testCase.editStart) {
+ await fillIn(CLIENT_COUNT.dateRange.editDate('start'), testCase.editStart);
+ }
+ if (testCase.editEnd) {
+ await fillIn(CLIENT_COUNT.dateRange.editDate('end'), testCase.editEnd);
+ }
+ if (testCase.reset) {
+ await click(CLIENT_COUNT.dateRange.reset);
+ }
+ await click(GENERAL.saveButton);
+ assert.dom(CLIENT_COUNT.dateRange.dateDisplay('start')).hasText(testCase.expectedStart);
+ assert.dom(CLIENT_COUNT.dateRange.dateDisplay('end')).hasText(testCase.expectedEnd);
+ });
});
test('it should render namespace and auth mount filters', async function (assert) {
From b9cdc779b48ccf891e14c3f36d539804f9160c78 Mon Sep 17 00:00:00 2001
From: Chelsea Shaw
Date: Wed, 31 Jul 2024 12:25:23 -0500
Subject: [PATCH 14/14] clarify comment
---
ui/tests/integration/components/clients/page/counts-test.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ui/tests/integration/components/clients/page/counts-test.js b/ui/tests/integration/components/clients/page/counts-test.js
index 874de6f82c10..b2567cb82632 100644
--- a/ui/tests/integration/components/clients/page/counts-test.js
+++ b/ui/tests/integration/components/clients/page/counts-test.js
@@ -97,7 +97,7 @@ module('Integration | Component | clients | Page::Counts', function (hooks) {
});
const jan23start = getUnixTime(new Date('2023-01-01T00:00:00Z'));
- // license start is July 2, 2024 but the component defaults to beginning of the month
+ // license start is July 2, 2024 on date change it recalculates start to beginning of the month
const july23start = getUnixTime(new Date('2023-07-01T00:00:00Z'));
const dec23end = getUnixTime(new Date('2023-12-31T00:00:00Z'));
const jan24end = getUnixTime(new Date('2024-01-31T00:00:00Z'));