Updating date-fns library from 1.x to 2.x (#10848)

* first round of fixes and setup

* test fixes

* fix dumb options on new method

* test fix

* clean up

* fixes

* clean up

* handle utc time

* add changelog
This commit is contained in:
Angel Garbarino 2021-02-08 13:13:00 -07:00 committed by GitHub
parent d0994340fb
commit 5ce35d1c52
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 103 additions and 64 deletions

3
changelog/10848.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:improvement
ui: Upgrade date-fns from 1.3.0 to 2.16.1.
```

View File

@ -1,8 +1,8 @@
/**
* @module PricingMetricsDates
* PricingMetricsDates components are used on the Pricing Metrics page to handle queries related to pricing metrics.
* This component assumes that query parameters (as in, from route params) are being passed in with the format MM-YYYY,
* while the inputs expect a format of MM/YYYY.
* This component assumes that query parameters (as in, from route params) are being passed in with the format MM-yyyy,
* while the inputs expect a format of MM/yyyy.
*
* @example
* ```js
@ -10,8 +10,8 @@
* ```
* @param {object} resultStart - resultStart is the start date of the metrics returned. Should be a valid date string that the built-in Date() fn can parse
* @param {object} resultEnd - resultEnd is the end date of the metrics returned. Should be a valid date string that the built-in Date() fn can parse
* @param {string} [queryStart] - queryStart is the route param (formatted MM-YYYY) that the result will be measured against for showing discrepancy warning
* @param {string} [queryEnd] - queryEnd is the route param (formatted MM-YYYY) that the result will be measured against for showing discrepancy warning
* @param {string} [queryStart] - queryStart is the route param (formatted MM-yyyy) that the result will be measured against for showing discrepancy warning
* @param {string} [queryEnd] - queryEnd is the route param (formatted MM-yyyy) that the result will be measured against for showing discrepancy warning
* @param {number} [defaultSpan=12] - setting for default time between start and end input dates
* @param {number} [retentionMonths=24] - setting for the retention months, which informs valid dates to query by
*/
@ -100,10 +100,10 @@ export default Component.extend({
error: computed('end', 'endDate', 'retentionMonths', 'start', 'startDate', function() {
if (!this.startDate) {
return 'Start date is invalid. Please use format MM/YYYY';
return 'Start date is invalid. Please use format MM/yyyy';
}
if (!this.endDate) {
return 'End date is invalid. Please use format MM/YYYY';
return 'End date is invalid. Please use format MM/yyyy';
}
if (isBefore(this.endDate, this.startDate)) {
return 'Start date is after end date';
@ -114,7 +114,7 @@ export default Component.extend({
}
const earliestRetained = startOfMonth(subMonths(lastMonthAvailable, this.retentionMonths));
if (isBefore(this.startDate, earliestRetained)) {
return `No data retained before ${format(earliestRetained, 'MM/YYYY')} due to your settings`;
return `No data retained before ${format(earliestRetained, 'MM/yyyy')} due to your settings`;
}
return null;
@ -130,24 +130,24 @@ export default Component.extend({
initialEnd = parseDateString(this.queryEnd, '-');
} else {
// if query isn't passed in, set it so that showResultsWarning works
this.queryEnd = format(initialEnd, 'MM-YYYY');
this.queryEnd = format(initialEnd, 'MM-yyyy');
}
initialStart = subMonths(initialEnd, this.defaultSpan);
if (this.queryStart) {
initialStart = parseDateString(this.queryStart, '-');
} else {
// if query isn't passed in, set it so that showResultsWarning works
this.queryStart = format(initialStart, 'MM-YYYY');
this.queryStart = format(initialStart, 'MM-yyyy');
}
this.start = format(initialStart, 'MM/YYYY');
this.end = format(initialEnd, 'MM/YYYY');
this.start = format(initialStart, 'MM/yyyy');
this.end = format(initialEnd, 'MM/yyyy');
},
actions: {
handleQuery() {
const start = format(this.startDate, 'MM-YYYY');
const end = format(this.endDate, 'MM-YYYY');
const start = format(this.startDate, 'MM-yyyy');
const end = format(this.endDate, 'MM-yyyy');
this.router.transitionTo('vault.cluster.metrics', {
queryParams: {
start,

View File

@ -3,7 +3,7 @@ import { assign } from '@ember/polyfills';
import { inject as service } from '@ember/service';
import Component from '@ember/component';
import { setProperties, computed, set } from '@ember/object';
import { addSeconds } from 'date-fns';
import { addSeconds, parseISO } from 'date-fns';
const DEFAULTS = {
token: null,
@ -67,8 +67,8 @@ export default Component.extend(DEFAULTS, {
if (!(creation_time && creation_ttl)) {
return null;
}
return addSeconds(creation_time, creation_ttl);
// returns new Date with seconds added.
return addSeconds(parseISO(creation_time), creation_ttl);
}),
handleError(e) {

View File

@ -1,8 +1,11 @@
import { helper } from '@ember/component/helper';
import { distanceInWordsToNow } from 'date-fns';
import { formatDistanceToNow } from 'date-fns';
export function dateFromNow([date], options = {}) {
return distanceInWordsToNow(date, options);
// check first if string. If it is, it could be ISO format or UTC, either way create a new date object
// otherwise it's a number or object and just return
let newDate = typeof date === 'string' ? new Date(date) : date;
return formatDistanceToNow(newDate, { ...options });
}
export default helper(dateFromNow);

View File

@ -2,7 +2,7 @@ import { helper } from '@ember/component/helper';
import { isValid } from 'date-fns';
export function parseDateString(date, separator = '-') {
// Expects format MM-YYYY by default: no dates
// Expects format MM-yyyy by default: no dates
let datePieces = date.split(separator);
if (datePieces.length === 2) {
if (datePieces[0] < 1 || datePieces[0] > 12) {
@ -14,7 +14,7 @@ export function parseDateString(date, separator = '-') {
}
}
// what to return if not valid?
throw new Error(`Please use format MM${separator}YYYY`);
throw new Error(`Please use format MM${separator}yyyy`);
}
export default helper(parseDateString);

View File

@ -1,25 +1,26 @@
import Route from '@ember/routing/route';
import ClusterRoute from 'vault/mixins/cluster-route';
import { hash } from 'rsvp';
import { format, addDays } from 'date-fns';
import { getTime } from 'date-fns';
import { parseDateString } from 'vault/helpers/parse-date-string';
const getActivityParams = ({ start, end }) => {
// Expects MM-YYYY format
// Expects MM-yyyy format
// TODO: minStart, maxEnd
let params = {};
if (start) {
let startDate = parseDateString(start);
if (startDate) {
// TODO: Replace with formatRFC3339 when date-fns is updated
params.start_time = format(addDays(startDate, 1), 'X');
// converts to milliseconds, divide by 1000 to get epoch
params.start_time = getTime(startDate) / 1000;
}
}
if (end) {
let endDate = parseDateString(end);
if (endDate) {
// TODO: Replace with formatRFC3339 when date-fns is updated
params.end_time = format(addDays(endDate, 10), 'X');
params.end_time = getTime(endDate) / 1000;
}
}
return params;

View File

@ -10,7 +10,7 @@
<li class="action">
<AlertBanner @type="warning" @message="We've stopped auto-renewing your token due to inactivity.
It will expire in {{date-from-now auth.tokenExpirationDate interval=1000 hideSuffix=true}}.
on {{date-format auth.tokenExpirationDate 'MMMM Do YYYY, h:mm:ss a'}}" />
On {{date-format auth.tokenExpirationDate 'MMMM Do yyyy, h:mm:ss a'}}" />
</li>
{{/if}}
<li class="action">

View File

@ -25,7 +25,7 @@
</div>
{{#if this.fileName}}
<p class="help has-text-grey">
This file is {{this.fileSize}} and was created on {{date-format this.fileLastModified 'MMM DD, YYYY hh:mm:ss A'}}.
This file is {{this.fileSize}} and was created on {{date-format this.fileLastModified 'MMM dd, yyyy hh:mm:ss a'}}.
</p>
{{/if}}
{{#if @fileHelpText}}

View File

@ -17,11 +17,11 @@
</InfoTableRow>
<InfoTableRow @label="Created" @value={{@model.creationTime}}>
<time datetime={{@model.creationTime}} title={{@model.creationTime}}>
{{date-format @model.creationTime 'MMM DD, YYYY [at] h:mm a'}}
{{date-format @model.creationTime 'MMM dd, yyyy [at] h:mm a'}}
</time>
</InfoTableRow>
<InfoTableRow @label="Last Updated" @value={{@model.lastUpdateTime}}>
<time datetime={{@model.lastUpdateTime}} title={{@model.lastUpdateTime}}>
{{date-format @model.lastUpdateTime 'MMM DD, YYYY [at] h:mm a'}}
{{date-format @model.lastUpdateTime 'MMM dd, yyyy [at] h:mm a'}}
</time>
</InfoTableRow>

View File

@ -26,12 +26,12 @@
</InfoTableRow>
<InfoTableRow @label="Created" @value={{model.creationTime}}>
<time datetime={{model.creationTime}} title={{model.creationTime}}>
{{date-format model.creationTime 'MMM DD, YYYY [at] h:mm a'}}
{{date-format model.creationTime 'MMM dd, yyyy [at] h:mm a'}}
</time>
</InfoTableRow>
<InfoTableRow @label="Last Updated" @value={{model.lastUpdateTime}}>
<time datetime={{model.lastUpdateTime}} title={{model.lastUpdateTime}}>
{{date-format model.lastUpdateTime 'MMM DD, YYYY [at] h:mm a'}}
{{date-format model.lastUpdateTime 'MMM dd, yyyy [at] h:mm a'}}
</time>
</InfoTableRow>
</div>

View File

@ -54,7 +54,7 @@
<div class="field box is-fullwidth is-shadowless is-paddingless is-marginless">
<InfoTableRow @label="License ID" @value={{licenseId}} />
<InfoTableRow @label="Valid from" @value={{startTime}}>
{{date-format model.startTime 'MMM DD, YYYY hh:mm:ss A'}} to {{date-format expirationTime 'MMM DD, YYYY hh:mm:ss A'}}
{{date-format startTime 'MMM dd, yyyy hh:mm:ss a'}} to {{date-format expirationTime 'MMM dd, yyyy hh:mm:ss a'}}
</InfoTableRow>
</div>
<div class="field box is-fullwidth is-shadowless is-paddingless is-marginless">

View File

@ -38,7 +38,7 @@
>
<section class="modal-card-body">
{{#if (eq model.enabled "On")}}
<p class="has-bottom-margin-s">Vault will start tracking data starting from todays date, {{date-format (now) "D MMMM YYYY"}}. You will not be able to see or query usage until the end of the month.</p>
<p class="has-bottom-margin-s">Vault will start tracking data starting from todays date, {{date-format (now) "d MMMM yyyy"}}. You will not be able to see or query usage until the end of the month.</p>
<p>If youve previously enabled usage tracking, that historical data will still be available to you.</p>
{{else}}
<p class="has-bottom-margin-s">Turning usage tracking off means that all data for the current month will be deleted. You will still be able to query previous months.</p>

View File

@ -38,7 +38,7 @@
<div class="box is-fullwidth is-shadowless">
{{#if (and resultStart resultEnd)}}
<h2 class="title is-4" data-test-pricing-result-dates>
{{date-format resultStart "MMM DD, YYYY"}} through {{date-format resultEnd "MMM DD, YYYY"}}
{{date-format resultStart "MMM dd, yyyy"}} through {{date-format resultEnd "MMM dd, yyyy"}}
</h2>
{{/if}}
{{#if showResultsWarning}}

View File

@ -3,7 +3,7 @@
<AlertBanner
@type="danger"
@message="Your auth token expired on
{{date-format expirationDate "MMMM Do YYYY, h:mm:ss a"}}
{{date-format expirationDate "MMMM Do yyyy, h:mm:ss a"}}
. You will need to re-authenticate."
>
<LinkTo @route="vault.cluster.logout" class="button link">

View File

@ -7,7 +7,7 @@
@size="l"
aria-hidden="true"
class="has-text-grey-light" />
&copy; {{date-format (now) "YYYY"}} HashiCorp
&copy; {{date-format (now) "yyyy"}} HashiCorp
</span>
<span>
<a href={{changelog-url-for activeCluster.leaderNode.version}}

View File

@ -30,7 +30,7 @@
<div class="field box is-fullwidth is-sideless is-paddingless is-marginless">
<InfoTableRow @label="Issue time" @value={{model.issueTime}}>
{{date-format model.issueTime 'MMM DD, YYYY hh:mm:ss A'}}
{{date-format model.issueTime 'MMM dd, yyyy hh:mm:ss a'}}
<br/>
<code>
{{model.issueTime}}
@ -38,7 +38,7 @@
</InfoTableRow>
<InfoTableRow @label="Renewable" @value={{model.renewable}} />
<InfoTableRow @label="Last renewal" @value={{model.lastRenewal}}>
{{date-format model.lastRenewal 'MMM DD, YYYY hh:mm:ss A'}}
{{date-format model.lastRenewal 'MMM dd, yyyy hh:mm:ss a'}}
<br/>
<code>
{{model.lastRenewal}}
@ -46,7 +46,7 @@
</InfoTableRow>
{{#if model.expireTime}}
<InfoTableRow @label="Expiration time" @value={{model.expireTime}}>
{{date-format model.expireTime 'MMM DD, YYYY hh:mm:ss A'}}
{{date-format model.expireTime 'MMM dd, yyyy hh:mm:ss a'}}
<br/>
<code>
{{model.expireTime}}

View File

@ -5,7 +5,7 @@ This helper returns a url to the changelog for the specified version.
It assumes that Changelog headers for Vault versions >= 1.4.3 are structured as:
## 1.5.0
### Month, DD, YYYY
### Month, DD, yyyy
## 1.4.5
### Month, DD, YYY

View File

@ -1,8 +1,10 @@
import { helper } from '@ember/component/helper';
import formatDate from 'date-fns/format';
import { format, parseISO } from 'date-fns';
export function dateFormat([date, format]) {
return formatDate(date, format);
export function dateFormat([date, style]) {
// see format breaking in upgrade to date-fns 2.x https://github.com/date-fns/date-fns/blob/master/CHANGELOG.md#changed-5
let number = typeof date === 'string' ? parseISO(date) : date;
return format(number, style);
}
export default helper(dateFormat);

View File

@ -69,7 +69,7 @@
value=ttl}}
{{info-table-row
label="Expires"
value=(date-format expirationDate 'MMM DD, YYYY hh:mm:ss A')}}
value=(date-format expirationDate 'MMM dd, yyyy hh:mm:ss a')}}
</div>
</div>
</section>

View File

@ -64,7 +64,7 @@
"d3-time-format": "^2.1.1",
"d3-tip": "^0.9.1",
"d3-transition": "^1.2.0",
"date-fns": "^1.30.0",
"date-fns": "^2.16.1",
"deepmerge": "^4.0.0",
"doctoc": "^1.4.0",
"ember-api-actions": "^0.2.8",

View File

@ -13,10 +13,10 @@ module('Integration | Component | pricing-metrics-dates', function(hooks) {
await render(hbs`
<PricingMetricsDates />
`);
assert.dom('[data-test-end-input]').hasValue(format(expectedEnd, 'MM/YYYY'), 'End input is last month');
assert.dom('[data-test-end-input]').hasValue(format(expectedEnd, 'MM/yyyy'), 'End input is last month');
assert
.dom('[data-test-start-input]')
.hasValue(format(expectedStart, 'MM/YYYY'), 'Start input is 12 months before last month');
.hasValue(format(expectedStart, 'MM/yyyy'), 'Start input is 12 months before last month');
});
test('On init if end date passed, start is calculated', async function(assert) {
@ -28,7 +28,7 @@ module('Integration | Component | pricing-metrics-dates', function(hooks) {
assert.dom('[data-test-end-input]').hasValue('09/2020', 'End input matches query');
assert
.dom('[data-test-start-input]')
.hasValue(format(expectedStart, 'MM/YYYY'), 'Start input is 12 months before end input');
.hasValue(format(expectedStart, 'MM/yyyy'), 'Start input is 12 months before end input');
});
test('On init if query start date passed, end is default', async function(assert) {
@ -37,7 +37,7 @@ module('Integration | Component | pricing-metrics-dates', function(hooks) {
await render(hbs`
<PricingMetricsDates @queryStart={{queryStart}} />
`);
assert.dom('[data-test-end-input]').hasValue(format(expectedEnd, 'MM/YYYY'), 'End input is last month');
assert.dom('[data-test-end-input]').hasValue(format(expectedEnd, 'MM/yyyy'), 'End input is last month');
assert.dom('[data-test-start-input]').hasValue('01/2020', 'Start input matches query');
});
@ -91,15 +91,15 @@ module('Integration | Component | pricing-metrics-dates', function(hooks) {
`);
assert.dom('[data-test-form-error]').doesNotExist('No form error shows by default');
await fillIn('[data-test-start-input]', format(subMonths(firstAvailable, 1), 'MM/YYYY'));
await fillIn('[data-test-start-input]', format(subMonths(firstAvailable, 1), 'MM/yyyy'));
assert
.dom('[data-test-form-error]')
.includesText(
`No data retained before ${format(firstAvailable, 'MM/YYYY')}`,
`No data retained before ${format(firstAvailable, 'MM/yyyy')}`,
'shows the correct error message for starting before the configured retainment period'
);
await fillIn('[data-test-end-input]', format(subMonths(lastAvailable, -1), 'MM/YYYY'));
await fillIn('[data-test-end-input]', format(subMonths(lastAvailable, -1), 'MM/yyyy'));
assert
.dom('[data-test-form-error]')
.includesText(
@ -111,15 +111,15 @@ module('Integration | Component | pricing-metrics-dates', function(hooks) {
assert
.dom('[data-test-form-error]')
.includesText(
'End date is invalid. Please use format MM/YYYY',
'End date is invalid. Please use format MM/yyyy',
'shows the correct error message for non-date input'
);
await fillIn('[data-test-start-input]', `13/${format(lastAvailable, 'YYYY')}`);
await fillIn('[data-test-start-input]', `13/${format(lastAvailable, 'yyyy')}`);
assert
.dom('[data-test-form-error]')
.includesText(
'Start date is invalid. Please use format MM/YYYY',
'Start date is invalid. Please use format MM/yyyy',
'shows the correct error message for an invalid month'
);
});

View File

@ -10,7 +10,7 @@ module('Integration | Helper | date-format', function(hooks) {
let today = new Date();
this.set('today', today);
await render(hbs`<p data-test-date-format>Date: {{date-format today "YYYY"}}</p>`);
await render(hbs`<p data-test-date-format>Date: {{date-format today "yyyy"}}</p>`);
assert
.dom('[data-test-date-format]')
.includesText(today.getFullYear(), 'it renders the date in the year format');
@ -29,7 +29,7 @@ module('Integration | Helper | date-format', function(hooks) {
let todayString = new Date().getFullYear().toString();
this.set('todayString', todayString);
await render(hbs`<p data-test-date-format>Date: {{date-format todayString}}</p>`);
await render(hbs`<p data-test-date-format>Date: {{date-format todayString "yyyy"}}</p>`);
assert
.dom('[data-test-date-format]')
.includesText(todayString, 'it renders the a date if passed in as a string');

View File

@ -1,6 +1,9 @@
import { module, test } from 'qunit';
import { subMinutes } from 'date-fns';
import { setupRenderingTest } from 'ember-qunit';
import { dateFromNow } from '../../../helpers/date-from-now';
import { render } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
module('Integration | Helper | date-from-now', function(hooks) {
setupRenderingTest(hooks);
@ -14,4 +17,31 @@ module('Integration | Helper | date-from-now', function(hooks) {
let result = dateFromNow([1481022124443], { addSuffix: true });
assert.ok(result.includes(' ago'));
});
test('you can pass in UTC timestamp', function(assert) {
let result = dateFromNow(['Fri, 11 Oct 2019 18:56:08 GMT'], { addSuffix: true });
assert.ok(result.includes(' ago'));
});
test('you can pass in ISO timestamp', function(assert) {
let result = dateFromNow(['2019-10-11T18:56:08.984Z'], { addSuffix: true });
assert.ok(result.includes(' ago'));
});
test('you can include a suffix using date class', function(assert) {
let now = Date.now();
let pastDate = subMinutes(now, 30);
let result = dateFromNow([pastDate], { addSuffix: true });
assert.ok(result.includes(' ago'));
});
test('you can include a suffix using ISO 8601 format', function(assert) {
let result = dateFromNow(['2021-02-05T20:43:09+00:00'], { addSuffix: true });
assert.ok(result.includes(' ago'));
});
test('you can include a suffix in the helper', async function(assert) {
await render(hbs`<p data-test-date-from-now>Date: {{date-from-now 1481022124443 addSuffix=true}}</p>`);
assert.dom('[data-test-date-from-now]').includesText(' years ago');
});
});

View File

@ -3,13 +3,13 @@ import { module, test } from 'qunit';
import { compareAsc } from 'date-fns';
module('Unit | Helpers | parse-date-string', function() {
test('it returns the first of the month when date like MM-YYYY passed in', function(assert) {
test('it returns the first of the month when date like MM-yyyy passed in', function(assert) {
let expected = new Date(2020, 3, 1);
let result = parseDateString('04-2020');
assert.equal(compareAsc(expected, result), 0);
});
test('it can handle a date format like MM/YYYY', function(assert) {
test('it can handle a date format like MM/yyyy', function(assert) {
let expected = new Date(2020, 11, 1);
let result = parseDateString('12/2020', '/');
assert.equal(compareAsc(expected, result), 0);
@ -22,7 +22,7 @@ module('Unit | Helpers | parse-date-string', function() {
} catch (e) {
result = e.message;
}
assert.equal('Please use format MM-YYYY', result);
assert.equal('Please use format MM-yyyy', result);
});
test('it throws an error with wrong separator', function(assert) {
@ -32,7 +32,7 @@ module('Unit | Helpers | parse-date-string', function() {
} catch (e) {
result = e.message;
}
assert.equal('Please use format MM.YYYY', result);
assert.equal('Please use format MM.yyyy', result);
});
test('it throws an error if month is invalid', function(assert) {

View File

@ -7278,10 +7278,10 @@ data-urls@^1.0.1:
whatwg-mimetype "^2.2.0"
whatwg-url "^7.0.0"
date-fns@^1.30.0:
version "1.30.1"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c"
integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==
date-fns@^2.16.1:
version "2.16.1"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.16.1.tgz#05775792c3f3331da812af253e1a935851d3834b"
integrity sha512-sAJVKx/FqrLYHAQeN7VpJrPhagZc9R4ImZIWYRFZaaohR3KzmuK88touwsSwSVT8Qcbd4zoDsnGfX4GFB4imyQ==
date-time@^2.1.0:
version "2.1.0"