diff --git a/ui/app/adapters/clients/activity.js b/ui/app/adapters/clients/activity.js
index 72b6d9f28..adbf9f915 100644
--- a/ui/app/adapters/clients/activity.js
+++ b/ui/app/adapters/clients/activity.js
@@ -1,30 +1,53 @@
import Application from '../application';
+import { formatRFC3339 } from 'date-fns';
export default Application.extend({
- queryRecord(store, type, query) {
- let url = `${this.buildURL()}/internal/counters/activity`;
- // Query has startTime defined. The API will return the endTime if none is provided.
- return this.ajax(url, 'GET', { data: query }).then((resp) => {
- let response = resp || {};
- // if the response is a 204 it has no request id (ARG TODO test that it returns a 204)
- response.id = response.request_id || 'no-data';
- return response;
- });
- },
- // called from components
- queryClientActivity(start_time, end_time) {
+ formatTimeParams(query) {
+ let { start_time, end_time } = query;
// do not query without start_time. Otherwise returns last year data, which is not reflective of billing data.
if (start_time) {
- let url = `${this.buildURL()}/internal/counters/activity`;
- let queryParams = {};
- if (!end_time) {
- queryParams = { data: { start_time } };
- } else {
- queryParams = { data: { start_time, end_time } };
+ // check if it's an array, if it is, it's coming from an action like selecting a new startTime or new EndTime
+ if (Array.isArray(start_time)) {
+ let startYear = Number(start_time[0]);
+ let startMonth = Number(start_time[1]);
+ start_time = formatRFC3339(new Date(startYear, startMonth));
}
- return this.ajax(url, 'GET', queryParams).then((resp) => {
- return resp;
+ if (end_time) {
+ if (Array.isArray(end_time)) {
+ let endYear = Number(end_time[0]);
+ let endMonth = Number(end_time[1]);
+ end_time = formatRFC3339(new Date(endYear, endMonth));
+ }
+
+ return { start_time, end_time };
+ } else {
+ return { start_time };
+ }
+ } else {
+ // did not have a start time, return null through to component.
+ return null;
+ }
+ },
+
+ // ARG TODO current Month tab is hitting this endpoint. Need to amend so only hit on Monthly history (large payload)
+ // query comes in as either: {start_time: '2021-03-17T00:00:00Z'} or
+ // {start_time: Array(2), end_time: Array(2)}
+ // end_time: (2) ['2022', 0]
+ // start_time: (2) ['2021', 2]
+ queryRecord(store, type, query) {
+ let url = `${this.buildURL()}/internal/counters/activity`;
+ // check if start and/or end times are in RFC3395 format, if not convert with timezone UTC/zulu.
+ let queryParams = this.formatTimeParams(query);
+ if (queryParams) {
+ return this.ajax(url, 'GET', { data: queryParams }).then((resp) => {
+ let response = resp || {};
+ // if the response is a 204 it has no request id (ARG TODO test that it returns a 204)
+ response.id = response.request_id || 'no-data';
+ return response;
});
+ } else {
+ // did not have a start time, return null through to component.
+ return null;
}
},
});
diff --git a/ui/app/adapters/clients/monthly.js b/ui/app/adapters/clients/monthly.js
index 8d17bada2..fa299a0b5 100644
--- a/ui/app/adapters/clients/monthly.js
+++ b/ui/app/adapters/clients/monthly.js
@@ -1,6 +1,6 @@
-import Application from '../application';
+import ApplicationAdapter from '../application';
-export default Application.extend({
+export default class MonthlyAdapter extends ApplicationAdapter {
queryRecord() {
let url = `${this.buildURL()}/internal/counters/activity/monthly`;
// Query has startTime defined. The API will return the endTime if none is provided.
@@ -10,5 +10,5 @@ export default Application.extend({
response.id = response.request_id || 'no-data';
return response;
});
- },
-});
+ }
+}
diff --git a/ui/app/components/calendar-widget.js b/ui/app/components/calendar-widget.js
index d2345b750..1adba5976 100644
--- a/ui/app/components/calendar-widget.js
+++ b/ui/app/components/calendar-widget.js
@@ -11,28 +11,17 @@ import { tracked } from '@glimmer/tracking';
* @example
* ```js
*
*
* ```
*/
class CalendarWidget extends Component {
- arrayOfMonths = [
- 'January',
- 'February',
- 'March',
- 'April',
- 'May',
- 'June',
- 'July',
- 'August',
- 'September',
- 'October',
- 'November',
- 'December',
- ];
currentDate = new Date();
currentYear = this.currentDate.getFullYear(); // integer
currentMonth = parseInt(this.currentDate.getMonth()); // integer and zero index
@@ -42,7 +31,6 @@ class CalendarWidget extends Component {
@tracked disablePastYear = this.isObsoleteYear(); // if obsolete year, disable left chevron
@tracked disableFutureYear = this.isCurrentYear(); // if current year, disable right chevron
@tracked showCalendar = false;
- @tracked showSingleMonth = false;
// HELPER FUNCTIONS (alphabetically) //
addClass(element, classString) {
@@ -54,7 +42,7 @@ class CalendarWidget extends Component {
}
isObsoleteYear() {
- // do not allow them to choose a end year before the this.args.startTimeDisplay
+ // do not allow them to choose a year before the this.args.startTimeDisplay
let startYear = this.args.startTimeDisplay.split(' ')[1];
return this.displayYear.toString() === startYear; // if on startYear then don't let them click back to the year prior
}
@@ -81,6 +69,7 @@ class CalendarWidget extends Component {
let elementMonthId = parseInt(e.id.split('-')[0]); // dependent on the shape of the element id
// for current year
+
if (this.currentMonth <= elementMonthId) {
// only disable months when current year is selected
if (this.isCurrentYear()) {
@@ -92,35 +81,35 @@ class CalendarWidget extends Component {
// if they are on the view where the start year equals the display year, check which months should not show.
let startMonth = this.args.startTimeDisplay.split(' ')[0]; // returns month name e.g. January
// return the index of the startMonth
- let startMonthIndex = this.arrayOfMonths.indexOf(startMonth);
+ let startMonthIndex = this.args.arrayOfMonths.indexOf(startMonth);
// then add readOnly class to any month less than the startMonth index.
if (startMonthIndex > elementMonthId) {
e.classList.add('is-readOnly');
}
}
+ // Compare values so the user cannot select an endTime after the endTime returned from counters/activity response on page load.
+ // ARG TODO will need to test if no data is returned on page load.
+ if (this.displayYear.toString() === this.args.endTimeFromResponse[0]) {
+ let endMonth = this.args.endTimeFromResponse[1];
+ // add readOnly class to any month that is older (higher) than the endMonth index. (e.g. if nov is the endMonth of the endTimeDisplay, then 11 and 12 should not be displayed 10 < 11 and 10 < 12.)
+ if (endMonth < elementMonthId) {
+ e.classList.add('is-readOnly');
+ }
+ }
});
}
@action
- selectCurrentBillingPeriod() {
- // ARG TOOD send to dashboard the select current billing period. The parent may know this it's just a boolean.
- // Turn the calendars off if they are showing.
+ selectCurrentBillingPeriod(D) {
+ this.args.handleCurrentBillingPeriod(); // resets the billing startTime and endTime to what it is on init via the parent.
this.showCalendar = false;
- this.showSingleMonth = false;
+ D.actions.close(); // close the dropdown.
}
@action
- selectEndMonth(month, year, element) {
- this.addClass(element.target, 'is-selected');
+ selectEndMonth(month, year, D) {
this.toggleShowCalendar();
this.args.handleClientActivityQuery(month, year, 'endTime');
- }
-
- @action
- selectSingleMonth(month, year, element) {
- // select month
- this.addClass(element.target, 'is-selected');
- this.toggleSingleMonth();
- // ARG TODO similar to selectEndMonth
+ D.actions.close(); // close the dropdown.
}
@action
@@ -134,13 +123,6 @@ class CalendarWidget extends Component {
@action
toggleShowCalendar() {
this.showCalendar = !this.showCalendar;
- this.showSingleMonth = false;
- }
-
- @action
- toggleSingleMonth() {
- this.showSingleMonth = !this.showSingleMonth;
- this.showCalendar = false;
}
}
export default setComponentTemplate(layout, CalendarWidget);
diff --git a/ui/app/components/clients/dashboard.js b/ui/app/components/clients/dashboard.js
index e1e890c7e..cc747980d 100644
--- a/ui/app/components/clients/dashboard.js
+++ b/ui/app/components/clients/dashboard.js
@@ -2,7 +2,7 @@ import Component from '@glimmer/component';
import { action } from '@ember/object';
import { inject as service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
-import { format, formatRFC3339, isSameMonth } from 'date-fns';
+import { isSameMonth } from 'date-fns';
export default class Dashboard extends Component {
arrayOfMonths = [
@@ -24,40 +24,53 @@ export default class Dashboard extends Component {
{ key: 'entity_clients', label: 'entity clients' },
{ key: 'non_entity_clients', label: 'non-entity clients' },
];
- // TODO remove this adapter variable? or set to /clients/activity ?
- adapter = this.store.adapterFor('clients/new-init-activity');
+
+ // needed for startTime modal picker
+ months = Array.from({ length: 12 }, (item, i) => {
+ return new Date(0, i).toLocaleString('en-US', { month: 'long' });
+ });
+ years = Array.from({ length: 5 }, (item, i) => {
+ return new Date().getFullYear() - i;
+ });
@service store;
@tracked barChartSelection = false;
@tracked isEditStartMonthOpen = false;
- @tracked startTime = this.args.model.startTime;
- @tracked endTime = this.args.model.endTime;
+ @tracked responseRangeDiffMessage = null;
+ @tracked startTimeRequested = null;
+ @tracked startTimeFromResponse = this.args.model.startTimeFromLicense; // ex: ['2021', 3] is April 2021 (0 indexed)
+ @tracked endTimeFromResponse = this.args.model.endTimeFromLicense;
@tracked startMonth = null;
@tracked startYear = null;
@tracked selectedNamespace = null;
// @tracked selectedNamespace = 'namespacelonglonglong4/'; // for testing namespace selection view
get startTimeDisplay() {
- if (!this.startTime) {
+ if (!this.startTimeFromResponse) {
// otherwise will return date of new Date(null)
return null;
}
- let formattedAsDate = new Date(this.startTime); // on init it's formatted as a Date object, but when modified by modal it's formatted as RFC3339
- return format(formattedAsDate, 'MMMM yyyy');
+ let month = this.startTimeFromResponse[1];
+ let year = this.startTimeFromResponse[0];
+ return `${this.arrayOfMonths[month]} ${year}`;
}
get endTimeDisplay() {
- if (!this.endTime) {
+ if (!this.endTimeFromResponse) {
// otherwise will return date of new Date(null)
return null;
}
- let formattedAsDate = new Date(this.endTime);
- return format(formattedAsDate, 'MMMM yyyy');
+ let month = this.endTimeFromResponse[1];
+ let year = this.endTimeFromResponse[0];
+ return `${this.arrayOfMonths[month]} ${year}`;
}
get isDateRange() {
- return !isSameMonth(new Date(this.startTime), new Date(this.endTime));
+ return !isSameMonth(
+ new Date(this.args.model.activity.startTime),
+ new Date(this.args.model.activity.endTime)
+ );
}
// Determine if we have client count data based on the current tab
@@ -91,39 +104,75 @@ export default class Dashboard extends Component {
}
return this.args.model.activity.responseTimestamp;
}
+ // HELPERS
+ areArraysTheSame(a1, a2) {
+ return (
+ a1 === a2 ||
+ (a1 !== null &&
+ a2 !== null &&
+ a1.length === a2.length &&
+ a1
+ .map(function (val, idx) {
+ return val === a2[idx];
+ })
+ .reduce(function (prev, cur) {
+ return prev && cur;
+ }, true))
+ );
+ }
+ // ACTIONS
@action
async handleClientActivityQuery(month, year, dateType) {
if (dateType === 'cancel') {
return;
}
- // dateType is either startTime or endTime
- let monthIndex = this.arrayOfMonths.indexOf(month);
+ // clicked "Current Billing period" in the calendar widget
+ if (dateType === 'reset') {
+ this.startTimeRequested = this.args.model.startTimeFromLicense;
+ this.endTimeRequested = null;
+ }
+ // clicked "Edit" Billing start month in Dashboard which opens a modal.
if (dateType === 'startTime') {
- this.startTime = formatRFC3339(new Date(year, monthIndex));
- this.endTime = null;
+ let monthIndex = this.arrayOfMonths.indexOf(month);
+ this.startTimeRequested = [year.toString(), monthIndex]; // ['2021', 0] (e.g. January 2021) // TODO CHANGE TO ARRAY
+ this.endTimeRequested = null;
}
+ // clicked "Custom End Month" from the calendar-widget
if (dateType === 'endTime') {
- // this month comes in as an index
- this.endTime = formatRFC3339(new Date(year, month));
+ // use the currently selected startTime for your startTimeRequested.
+ this.startTimeRequested = this.startTimeFromResponse;
+ this.endTimeRequested = [year.toString(), month]; // endTime comes in as a number/index whereas startTime comes in as a month name. Hence the difference between monthIndex and month.
}
- try {
- let response = await this.adapter.queryClientActivity(this.startTime, this.endTime);
- // resets the endTime to what is returned on the response
- this.endTime = response.data.end_time;
+ try {
+ let response = await this.store.queryRecord('clients/activity', {
+ start_time: this.startTimeRequested,
+ end_time: this.endTimeRequested,
+ });
+ if (!response) {
+ // this.endTime will be null and use this to show EmptyState message on the template.
+ return;
+ }
+ // note: this.startTimeDisplay (at getter) is updated by this.startTimeFromResponse
+ this.startTimeFromResponse = response.formattedStartTime;
+ this.endTimeFromResponse = response.formattedEndTime;
+ // compare if the response and what you requested are the same. If they are not throw a warning.
+ // this only gets triggered if the data was returned, which does not happen if the user selects a startTime after for which we have data. That's an adapter error and is captured differently.
+ if (!this.areArraysTheSame(this.startTimeFromResponse, this.startTimeRequested)) {
+ this.responseRangeDiffMessage = `You requested data from ${month} ${year}. We only have data from ${this.startTimeDisplay}, and that is what is being shown here.`;
+ } else {
+ this.responseRangeDiffMessage = null;
+ }
return response;
- // ARG TODO this is the response you need to use to repopulate the chart data
} catch (e) {
// ARG TODO handle error
}
}
- // ARG TODO this might be a carry over from history, will need to confirm
@action
- resetData() {
- this.barChartSelection = false;
- this.selectedNamespace = null;
+ handleCurrentBillingPeriod() {
+ this.handleClientActivityQuery(0, 0, 'reset');
}
@action
diff --git a/ui/app/models/clients/activity.js b/ui/app/models/clients/activity.js
index d2cee5b50..4d0545c04 100644
--- a/ui/app/models/clients/activity.js
+++ b/ui/app/models/clients/activity.js
@@ -3,6 +3,8 @@ export default class Activity extends Model {
@attr('string') responseTimestamp;
@attr('array') byNamespace;
@attr('string') endTime;
+ @attr('array') formattedEndTime;
+ @attr('array') formattedStartTime;
@attr('string') startTime;
@attr('object') total;
}
diff --git a/ui/app/models/clients/monthly.js b/ui/app/models/clients/monthly.js
index 0c9c15af7..6b624ceb0 100644
--- a/ui/app/models/clients/monthly.js
+++ b/ui/app/models/clients/monthly.js
@@ -1,6 +1,5 @@
import Model, { attr } from '@ember-data/model';
-// ARG TODO copied from before, modify for what you need
-export default class Monthly extends Model {
+export default class MonthlyModel extends Model {
@attr('string') responseTimestamp;
@attr('array') byNamespace;
@attr('object') total;
diff --git a/ui/app/routes/vault/cluster/clients/index.js b/ui/app/routes/vault/cluster/clients/index.js
index 8b56af6f6..9f1e7a726 100644
--- a/ui/app/routes/vault/cluster/clients/index.js
+++ b/ui/app/routes/vault/cluster/clients/index.js
@@ -42,6 +42,11 @@ export default Route.extend(ClusterRoute, {
}
},
+ rfc33395ToMonthYear(timestamp) {
+ // return [2021, 04 (e.g. 2021 March, make 0-indexed)
+ return [timestamp.split('-')[0], Number(timestamp.split('-')[1].replace(/^0+/, '')) - 1];
+ },
+
async model() {
let config = this.store.queryRecord('clients/config', {}).catch((e) => {
console.debug(e);
@@ -52,14 +57,16 @@ export default Route.extend(ClusterRoute, {
let license = await this.getLicense(); // get default start_time
let activity = await this.getActivity(license.startTime); // returns client counts using license start_time.
let monthly = await this.getMonthly(); // returns the partial month endpoint
+ let endTimeFromLicense = this.rfc33395ToMonthYear(activity.endTime);
+ let startTimeFromLicense = this.rfc33395ToMonthYear(license.startTime);
return hash({
// ARG TODO will remove "hash" once remove "activity," which currently relies on it.
activity,
monthly,
config,
- endTime: activity.endTime,
- startTime: license.startTime,
+ endTimeFromLicense,
+ startTimeFromLicense,
});
},
diff --git a/ui/app/serializers/clients/activity.js b/ui/app/serializers/clients/activity.js
index e1f561d6c..49d3f3a61 100644
--- a/ui/app/serializers/clients/activity.js
+++ b/ui/app/serializers/clients/activity.js
@@ -46,7 +46,7 @@ transformedPayload.by_namespace = [
]
*/
-export default ApplicationSerializer.extend({
+export default class ActivitySerializer extends ApplicationSerializer {
flattenDataset(payload) {
let topTen = payload.slice(0, 10);
@@ -79,7 +79,7 @@ export default ApplicationSerializer.extend({
...flattenedNs,
};
});
- },
+ }
// TODO CMB remove and use abstracted function above
// prior to 1.10, client count key names are "distinct_entities" and "non_entity_tokens" so mapping below wouldn't work
@@ -107,7 +107,12 @@ export default ApplicationSerializer.extend({
mounts: namespaceMounts,
};
});
- },
+ }
+
+ rfc33395ToMonthYear(timestamp) {
+ // return ['2021,' 04 (e.g. 2021 March, make 0-indexed)
+ return [timestamp.split('-')[0], Number(timestamp.split('-')[1].replace(/^0+/, '')) - 1];
+ }
normalizeResponse(store, primaryModelClass, payload, id, requestType) {
let response_timestamp = formatISO(new Date());
@@ -115,8 +120,10 @@ export default ApplicationSerializer.extend({
...payload,
response_timestamp,
by_namespace: this.flattenDataset(payload.data.by_namespace),
+ formatted_end_time: this.rfc33395ToMonthYear(payload.data.end_time),
+ formatted_start_time: this.rfc33395ToMonthYear(payload.data.start_time),
};
delete payload.data.by_namespace;
- return this._super(store, primaryModelClass, transformedPayload, id, requestType);
- },
-});
+ return super.normalizeResponse(store, primaryModelClass, transformedPayload, id, requestType);
+ }
+}
diff --git a/ui/app/serializers/clients/monthly.js b/ui/app/serializers/clients/monthly.js
index 67e8cd03a..f628c21f5 100644
--- a/ui/app/serializers/clients/monthly.js
+++ b/ui/app/serializers/clients/monthly.js
@@ -1,7 +1,7 @@
import ApplicationSerializer from '../application';
import { formatISO } from 'date-fns';
-export default ApplicationSerializer.extend({
+export default class MonthlySerializer extends ApplicationSerializer {
flattenDataset(payload) {
let topTen = payload ? payload.slice(0, 10) : [];
@@ -34,7 +34,7 @@ export default ApplicationSerializer.extend({
...flattenedNs,
};
});
- },
+ }
normalizeResponse(store, primaryModelClass, payload, id, requestType) {
let { data } = payload;
@@ -52,6 +52,6 @@ export default ApplicationSerializer.extend({
},
};
delete payload.data.by_namespace;
- return this._super(store, primaryModelClass, transformedPayload, id, requestType);
- },
-});
+ return super.normalizeResponse(store, primaryModelClass, transformedPayload, id, requestType);
+ }
+}
diff --git a/ui/app/styles/components/calendar-widget.scss b/ui/app/styles/components/calendar-widget.scss
index 4c672d170..0f155594a 100644
--- a/ui/app/styles/components/calendar-widget.scss
+++ b/ui/app/styles/components/calendar-widget.scss
@@ -79,11 +79,6 @@ $dark-gray: #535f73;
color: lighten($dark-gray, 30%);
pointer-events: none;
}
- &.is-selected {
- background-color: $blue-500;
- color: white;
- text-align: center;
- }
}
}
diff --git a/ui/app/templates/components/calendar-widget.hbs b/ui/app/templates/components/calendar-widget.hbs
index af31fed32..595cd0ce2 100644
--- a/ui/app/templates/components/calendar-widget.hbs
+++ b/ui/app/templates/components/calendar-widget.hbs
@@ -17,7 +17,7 @@
@@ -34,18 +34,6 @@
-
-
-
{{#if this.showCalendar}}
@@ -65,10 +53,10 @@
- {{#each this.arrayOfMonths as |month index|}}
+ {{#each @arrayOfMonths as |month index|}}
{{/if}}
-
- {{#if this.showSingleMonth}}
-
-
-
-
{{this.displayYear}}
-
-
-
- {{#each this.arrayOfMonths as |month index|}}
-
- {{/each}}
-
-
- {{/if}}
\ No newline at end of file
diff --git a/ui/app/templates/components/clients/dashboard.hbs b/ui/app/templates/components/clients/dashboard.hbs
index 38336dad0..ecf0afc65 100644
--- a/ui/app/templates/components/clients/dashboard.hbs
+++ b/ui/app/templates/components/clients/dashboard.hbs
@@ -37,7 +37,8 @@
- This date is when client counting starts. Without this starting point, the data shown is not reliable.
+ This date comes from your license, and defines when client counting starts. Without this starting point, the data
+ shown is not reliable.
{{#if (eq @model.config.enabled "Off")}}
@@ -49,19 +50,25 @@
to enable tracking again.
{{/if}}
- {{! check for @startTime otherwise emptyState}}
- {{#if @model.startTime}}
+ {{! check for startTimeFromLicense or startTimeFromResponse otherwise emptyState}}
+ {{#if (or @model.startTimeFromLicense this.startTimeFromResponse)}}
Filters
{{! ARG TODO more filters for namespace here }}
+ {{#if this.responseRangeDiffMessage}}
+
+ {{/if}}
{{#if @isLoading}}
{{else if this.topTenNamespaces}}
@@ -76,15 +83,15 @@
@isDateRange={{this.isDateRange}}
@timestamp={{this.responseTimestamp}}
/>
+ {{! If no endTime that means the counters/activity request did not return a payload. }}
+ {{else if this.endTime}}
+
{{else}}
- {{! ARG TODO remove once we have this dialed }}
{{/if}}
- {{else}}
-
{{/if}}
{{! Modal for startTime picker }}
diff --git a/ui/mirage/handlers/activity.js b/ui/mirage/handlers/activity.js
index a3bd600f3..9a7dba7c4 100644
--- a/ui/mirage/handlers/activity.js
+++ b/ui/mirage/handlers/activity.js
@@ -11,8 +11,8 @@ export default function (server) {
return {
request_id: '26be5ab9-dcac-9237-ec12-269a8ca647d5',
data: {
- start_time: '2021-02-01T00:00:00Z',
- end_time: '2022-01-31T23:59:59Z',
+ start_time: '2021-03-17T00:00:00Z',
+ end_time: '2021-12-31T23:59:59Z',
total: {
_comment1: 'total client counts',
clients: 3637,
diff --git a/ui/package.json b/ui/package.json
index 2e328bd58..a8b2f5180 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -86,6 +86,7 @@
"d3-tip": "^0.9.1",
"d3-transition": "^1.2.0",
"date-fns": "^2.16.1",
+ "date-fns-tz": "^1.2.2",
"deepmerge": "^4.0.0",
"doctoc": "^1.4.0",
"ember-api-actions": "^0.2.8",
diff --git a/ui/yarn.lock b/ui/yarn.lock
index dc022a1ff..963ba661a 100644
--- a/ui/yarn.lock
+++ b/ui/yarn.lock
@@ -8994,6 +8994,11 @@ data-urls@^2.0.0:
whatwg-mimetype "^2.3.0"
whatwg-url "^8.0.0"
+date-fns-tz@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/date-fns-tz/-/date-fns-tz-1.2.2.tgz#89432b54ce3fa7d050a2039e997e5b6a96df35dd"
+ integrity sha512-vWtn44eEqnLbkACb7T5G5gPgKR4nY8NkNMOCyoY49NsRGHrcDmY2aysCyzDeA+u+vcDBn/w6nQqEDyouRs4m8w==
+
date-fns@^2.16.1:
version "2.21.1"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.21.1.tgz#679a4ccaa584c0706ea70b3fa92262ac3009d2b0"
@@ -11729,11 +11734,6 @@ fake-xml-http-request@^2.1.1:
resolved "https://registry.yarnpkg.com/fake-xml-http-request/-/fake-xml-http-request-2.1.2.tgz#f1786720cae50bbb46273035a0173414f3e85e74"
integrity sha512-HaFMBi7r+oEC9iJNpc3bvcW7Z7iLmM26hPDmlb0mFwyANSsOQAtJxbdWsXITKOzZUyMYK0zYCv3h5yDj9TsiXg==
-faker@^5.5.3:
- version "5.5.3"
- resolved "https://registry.yarnpkg.com/faker/-/faker-5.5.3.tgz#c57974ee484431b25205c2c8dc09fda861e51e0e"
- integrity sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g==
-
fast-deep-equal@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"