diff --git a/changelog/10848.txt b/changelog/10848.txt new file mode 100644 index 000000000..9b3c659b4 --- /dev/null +++ b/changelog/10848.txt @@ -0,0 +1,3 @@ +```release-note:improvement +ui: Upgrade date-fns from 1.3.0 to 2.16.1. +``` diff --git a/ui/app/components/pricing-metrics-dates.js b/ui/app/components/pricing-metrics-dates.js index 88af4dd66..a78a93de2 100644 --- a/ui/app/components/pricing-metrics-dates.js +++ b/ui/app/components/pricing-metrics-dates.js @@ -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, diff --git a/ui/app/components/tool-actions-form.js b/ui/app/components/tool-actions-form.js index 606fca66e..fd9f3df9a 100644 --- a/ui/app/components/tool-actions-form.js +++ b/ui/app/components/tool-actions-form.js @@ -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) { diff --git a/ui/app/helpers/date-from-now.js b/ui/app/helpers/date-from-now.js index 79cad4252..2f446fb64 100644 --- a/ui/app/helpers/date-from-now.js +++ b/ui/app/helpers/date-from-now.js @@ -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); diff --git a/ui/app/helpers/parse-date-string.js b/ui/app/helpers/parse-date-string.js index 0e5c4552d..b4780c02c 100644 --- a/ui/app/helpers/parse-date-string.js +++ b/ui/app/helpers/parse-date-string.js @@ -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); diff --git a/ui/app/routes/vault/cluster/metrics/index.js b/ui/app/routes/vault/cluster/metrics/index.js index 39d19c244..59e7b5a3c 100644 --- a/ui/app/routes/vault/cluster/metrics/index.js +++ b/ui/app/routes/vault/cluster/metrics/index.js @@ -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; diff --git a/ui/app/templates/components/auth-info.hbs b/ui/app/templates/components/auth-info.hbs index 032fdb2e0..0c4d0f1fc 100644 --- a/ui/app/templates/components/auth-info.hbs +++ b/ui/app/templates/components/auth-info.hbs @@ -10,7 +10,7 @@
- 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'}}.
{{/if}} {{#if @fileHelpText}} diff --git a/ui/app/templates/components/identity/item-alias/alias-details.hbs b/ui/app/templates/components/identity/item-alias/alias-details.hbs index 225f81d30..841ae229c 100644 --- a/ui/app/templates/components/identity/item-alias/alias-details.hbs +++ b/ui/app/templates/components/identity/item-alias/alias-details.hbs @@ -17,11 +17,11 @@Vault will start tracking data starting from today’s date, {{date-format (now) "D MMMM YYYY"}}. You will not be able to see or query usage until the end of the month.
+Vault will start tracking data starting from today’s date, {{date-format (now) "d MMMM yyyy"}}. You will not be able to see or query usage until the end of the month.
If you’ve previously enabled usage tracking, that historical data will still be available to you.
{{else}}Turning usage tracking off means that all data for the current month will be deleted. You will still be able to query previous months.
diff --git a/ui/app/templates/components/pricing-metrics-dates.hbs b/ui/app/templates/components/pricing-metrics-dates.hbs index 69d2188bd..25a3b28d2 100644 --- a/ui/app/templates/components/pricing-metrics-dates.hbs +++ b/ui/app/templates/components/pricing-metrics-dates.hbs @@ -38,7 +38,7 @@
{{model.issueTime}}
@@ -38,7 +38,7 @@
{{model.lastRenewal}}
@@ -46,7 +46,7 @@
{{model.expireTime}}
diff --git a/ui/lib/core/addon/helpers/changelog-url-for.js b/ui/lib/core/addon/helpers/changelog-url-for.js
index 095862de1..f2efe63c7 100644
--- a/ui/lib/core/addon/helpers/changelog-url-for.js
+++ b/ui/lib/core/addon/helpers/changelog-url-for.js
@@ -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
diff --git a/ui/lib/core/addon/helpers/date-format.js b/ui/lib/core/addon/helpers/date-format.js
index fa0417aee..950e51fae 100644
--- a/ui/lib/core/addon/helpers/date-format.js
+++ b/ui/lib/core/addon/helpers/date-format.js
@@ -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);
diff --git a/ui/lib/replication/addon/templates/mode/secondaries/add.hbs b/ui/lib/replication/addon/templates/mode/secondaries/add.hbs
index 2a46cc1ba..4225455cb 100644
--- a/ui/lib/replication/addon/templates/mode/secondaries/add.hbs
+++ b/ui/lib/replication/addon/templates/mode/secondaries/add.hbs
@@ -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')}}
Date: {{date-format today "YYYY"}}
`); + await render(hbs`Date: {{date-format today "yyyy"}}
`); 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`Date: {{date-format todayString}}
`); + await render(hbs`Date: {{date-format todayString "yyyy"}}
`); assert .dom('[data-test-date-format]') .includesText(todayString, 'it renders the a date if passed in as a string'); diff --git a/ui/tests/integration/helpers/date-from-now-test.js b/ui/tests/integration/helpers/date-from-now-test.js index e8807f372..a89be51d6 100644 --- a/ui/tests/integration/helpers/date-from-now-test.js +++ b/ui/tests/integration/helpers/date-from-now-test.js @@ -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`Date: {{date-from-now 1481022124443 addSuffix=true}}
`); + assert.dom('[data-test-date-from-now]').includesText(' years ago'); + }); }); diff --git a/ui/tests/unit/helpers/parse-date-string-test.js b/ui/tests/unit/helpers/parse-date-string-test.js index 5a094ff4b..8297a2ab9 100644 --- a/ui/tests/unit/helpers/parse-date-string-test.js +++ b/ui/tests/unit/helpers/parse-date-string-test.js @@ -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) { diff --git a/ui/yarn.lock b/ui/yarn.lock index a171c5a25..c6b906f17 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -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"