Remove moment.js
Moment.js has a large bundle size and it causes a performance overhead. Change-Id: Ida5c2642006d5018300527cb2b5eaab3c61772d2
This commit is contained in:
@@ -26,7 +26,7 @@ import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mix
|
|||||||
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
|
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
|
||||||
import {htmlTemplate} from './gr-messages-list-experimental_html.js';
|
import {htmlTemplate} from './gr-messages-list-experimental_html.js';
|
||||||
import {KeyboardShortcutBehavior} from '../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.js';
|
import {KeyboardShortcutBehavior} from '../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.js';
|
||||||
import {util} from '../../../scripts/util.js';
|
import {parseDate} from '../../../utils/date-util.js';
|
||||||
import {MessageTag} from '../../../constants/constants.js';
|
import {MessageTag} from '../../../constants/constants.js';
|
||||||
import {appContext} from '../../../services/app-context.js';
|
import {appContext} from '../../../services/app-context.js';
|
||||||
|
|
||||||
@@ -219,8 +219,8 @@ class GrMessagesListExperimental extends mixinBehaviors( [
|
|||||||
combinedMessages = combinedMessages.concat(messages.slice(mi));
|
combinedMessages = combinedMessages.concat(messages.slice(mi));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mDate = mDate || util.parseDate(messages[mi].date);
|
mDate = mDate || parseDate(messages[mi].date);
|
||||||
rDate = rDate || util.parseDate(reviewerUpdates[ri].date);
|
rDate = rDate || parseDate(reviewerUpdates[ri].date);
|
||||||
if (rDate < mDate) {
|
if (rDate < mDate) {
|
||||||
combinedMessages.push(reviewerUpdates[ri++]);
|
combinedMessages.push(reviewerUpdates[ri++]);
|
||||||
rDate = null;
|
rDate = null;
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mix
|
|||||||
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
|
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
|
||||||
import {htmlTemplate} from './gr-messages-list_html.js';
|
import {htmlTemplate} from './gr-messages-list_html.js';
|
||||||
import {KeyboardShortcutBehavior} from '../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.js';
|
import {KeyboardShortcutBehavior} from '../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.js';
|
||||||
import {util} from '../../../scripts/util.js';
|
import {parseDate} from '../../../utils/date-util.js';
|
||||||
import {appContext} from '../../../services/app-context.js';
|
import {appContext} from '../../../services/app-context.js';
|
||||||
|
|
||||||
const MAX_INITIAL_SHOWN_MESSAGES = 20;
|
const MAX_INITIAL_SHOWN_MESSAGES = 20;
|
||||||
@@ -191,8 +191,8 @@ class GrMessagesList extends mixinBehaviors( [
|
|||||||
result = result.concat(messages.slice(mi));
|
result = result.concat(messages.slice(mi));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mDate = mDate || util.parseDate(messages[mi].date);
|
mDate = mDate || parseDate(messages[mi].date);
|
||||||
rDate = rDate || util.parseDate(reviewerUpdates[ri].date);
|
rDate = rDate || parseDate(reviewerUpdates[ri].date);
|
||||||
if (rDate < mDate) {
|
if (rDate < mDate) {
|
||||||
result.push(reviewerUpdates[ri++]);
|
result.push(reviewerUpdates[ri++]);
|
||||||
rDate = null;
|
rDate = null;
|
||||||
@@ -303,14 +303,14 @@ class GrMessagesList extends mixinBehaviors( [
|
|||||||
const messages = this.messages || [];
|
const messages = this.messages || [];
|
||||||
const index = message._index;
|
const index = message._index;
|
||||||
const authorId = message.author && message.author._account_id;
|
const authorId = message.author && message.author._account_id;
|
||||||
const mDate = util.parseDate(message.date).getTime();
|
const mDate = parseDate(message.date).getTime();
|
||||||
// NB: Messages array has oldest messages first.
|
// NB: Messages array has oldest messages first.
|
||||||
let nextMDate;
|
let nextMDate;
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
for (let i = index - 1; i >= 0; i--) {
|
for (let i = index - 1; i >= 0; i--) {
|
||||||
if (messages[i] && messages[i].author &&
|
if (messages[i] && messages[i].author &&
|
||||||
messages[i].author._account_id === authorId) {
|
messages[i].author._account_id === authorId) {
|
||||||
nextMDate = util.parseDate(messages[i].date).getTime();
|
nextMDate = parseDate(messages[i].date).getTime();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -324,7 +324,7 @@ class GrMessagesList extends mixinBehaviors( [
|
|||||||
fileComments[i].author._account_id !== authorId) {
|
fileComments[i].author._account_id !== authorId) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const cDate = util.parseDate(fileComments[i].updated).getTime();
|
const cDate = parseDate(fileComments[i].updated).getTime();
|
||||||
if (cDate <= mDate) {
|
if (cDate <= mDate) {
|
||||||
if (nextMDate && cDate <= nextMDate) {
|
if (nextMDate && cDate <= nextMDate) {
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-l
|
|||||||
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
|
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
|
||||||
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
|
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
|
||||||
import {htmlTemplate} from './gr-thread-list_html.js';
|
import {htmlTemplate} from './gr-thread-list_html.js';
|
||||||
import {util} from '../../../scripts/util.js';
|
import {parseDate} from '../../../utils/date-util.js';
|
||||||
|
|
||||||
import {NO_THREADS_MSG} from '../../../constants/messages.js';
|
import {NO_THREADS_MSG} from '../../../constants/messages.js';
|
||||||
|
|
||||||
@@ -163,8 +163,8 @@ class GrThreadList extends GestureEventListeners(
|
|||||||
return c1.thread.line - c2.thread.line;
|
return c1.thread.line - c2.thread.line;
|
||||||
}
|
}
|
||||||
|
|
||||||
const c1Date = c1.__date || util.parseDate(c1.updated);
|
const c1Date = c1.__date || parseDate(c1.updated);
|
||||||
const c2Date = c2.__date || util.parseDate(c2.updated);
|
const c2Date = c2.__date || parseDate(c2.updated);
|
||||||
const dateCompare = c2Date - c1Date;
|
const dateCompare = c2Date - c1Date;
|
||||||
if (dateCompare === 0 && (!c1.id || !c1.id.localeCompare)) {
|
if (dateCompare === 0 && (!c1.id || !c1.id.localeCompare)) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mix
|
|||||||
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
|
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
|
||||||
import {htmlTemplate} from './gr-comment-api_html.js';
|
import {htmlTemplate} from './gr-comment-api_html.js';
|
||||||
import {PatchSetBehavior} from '../../../behaviors/gr-patch-set-behavior/gr-patch-set-behavior.js';
|
import {PatchSetBehavior} from '../../../behaviors/gr-patch-set-behavior/gr-patch-set-behavior.js';
|
||||||
import {util} from '../../../scripts/util.js';
|
import {parseDate} from '../../../utils/date-util.js';
|
||||||
|
|
||||||
const PARENT = 'PARENT';
|
const PARENT = 'PARENT';
|
||||||
|
|
||||||
@@ -470,7 +470,7 @@ class ChangeComments {
|
|||||||
.sort(
|
.sort(
|
||||||
(c1, c2) => {
|
(c1, c2) => {
|
||||||
const dateDiff =
|
const dateDiff =
|
||||||
util.parseDate(c1.updated) - util.parseDate(c2.updated);
|
parseDate(c1.updated) - parseDate(c2.updated);
|
||||||
if (dateDiff) {
|
if (dateDiff) {
|
||||||
return dateDiff;
|
return dateDiff;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import {PolymerElement} from '@polymer/polymer/polymer-element.js';
|
|||||||
import {htmlTemplate} from './gr-diff-host_html.js';
|
import {htmlTemplate} from './gr-diff-host_html.js';
|
||||||
import {PatchSetBehavior} from '../../../behaviors/gr-patch-set-behavior/gr-patch-set-behavior.js';
|
import {PatchSetBehavior} from '../../../behaviors/gr-patch-set-behavior/gr-patch-set-behavior.js';
|
||||||
import {GrDiffBuilder} from '../gr-diff-builder/gr-diff-builder.js';
|
import {GrDiffBuilder} from '../gr-diff-builder/gr-diff-builder.js';
|
||||||
import {util} from '../../../scripts/util.js';
|
import {parseDate} from '../../../utils/date-util.js';
|
||||||
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
|
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
|
||||||
import {DiffSide, rangesEqual} from '../gr-diff/gr-diff-utils.js';
|
import {DiffSide, rangesEqual} from '../gr-diff/gr-diff-utils.js';
|
||||||
import {appContext} from '../../../services/app-context.js';
|
import {appContext} from '../../../services/app-context.js';
|
||||||
@@ -667,7 +667,7 @@ class GrDiffHost extends mixinBehaviors( [
|
|||||||
return comments.slice(0).sort((a, b) => {
|
return comments.slice(0).sort((a, b) => {
|
||||||
if (b.__draft && !a.__draft ) { return -1; }
|
if (b.__draft && !a.__draft ) { return -1; }
|
||||||
if (a.__draft && !b.__draft ) { return 1; }
|
if (a.__draft && !b.__draft ) { return 1; }
|
||||||
return util.parseDate(a.updated) - util.parseDate(b.updated);
|
return parseDate(a.updated) - parseDate(b.updated);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ import {GrRangeNormalizer} from './diff/gr-diff-highlight/gr-range-normalizer.js
|
|||||||
import {GrCountStringFormatter} from './shared/gr-count-string-formatter/gr-count-string-formatter.js';
|
import {GrCountStringFormatter} from './shared/gr-count-string-formatter/gr-count-string-formatter.js';
|
||||||
import {GrReviewerSuggestionsProvider, SUGGESTIONS_PROVIDERS_USERS_TYPES} from '../scripts/gr-reviewer-suggestions-provider/gr-reviewer-suggestions-provider.js';
|
import {GrReviewerSuggestionsProvider, SUGGESTIONS_PROVIDERS_USERS_TYPES} from '../scripts/gr-reviewer-suggestions-provider/gr-reviewer-suggestions-provider.js';
|
||||||
import {util} from '../scripts/util.js';
|
import {util} from '../scripts/util.js';
|
||||||
import moment from 'moment/src/moment.js';
|
|
||||||
import page from 'page/page.mjs';
|
import page from 'page/page.mjs';
|
||||||
import {Auth} from './shared/gr-rest-api-interface/gr-auth.js';
|
import {Auth} from './shared/gr-rest-api-interface/gr-auth.js';
|
||||||
import {EventEmitter} from './shared/gr-event-interface/gr-event-interface.js';
|
import {EventEmitter} from './shared/gr-event-interface/gr-event-interface.js';
|
||||||
@@ -103,7 +102,6 @@ export function initGlobalVariables() {
|
|||||||
window.GrCountStringFormatter = GrCountStringFormatter;
|
window.GrCountStringFormatter = GrCountStringFormatter;
|
||||||
window.GrReviewerSuggestionsProvider = GrReviewerSuggestionsProvider;
|
window.GrReviewerSuggestionsProvider = GrReviewerSuggestionsProvider;
|
||||||
window.util = util;
|
window.util = util;
|
||||||
window.moment = moment;
|
|
||||||
window.page = page;
|
window.page = page;
|
||||||
window.Auth = Auth;
|
window.Auth = Auth;
|
||||||
window.EventEmitter = EventEmitter;
|
window.EventEmitter = EventEmitter;
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import {PolymerElement} from '@polymer/polymer/polymer-element.js';
|
|||||||
import {htmlTemplate} from './gr-comment-thread_html.js';
|
import {htmlTemplate} from './gr-comment-thread_html.js';
|
||||||
import {PathListBehavior} from '../../../behaviors/gr-path-list-behavior/gr-path-list-behavior.js';
|
import {PathListBehavior} from '../../../behaviors/gr-path-list-behavior/gr-path-list-behavior.js';
|
||||||
import {KeyboardShortcutBehavior} from '../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.js';
|
import {KeyboardShortcutBehavior} from '../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.js';
|
||||||
import {util} from '../../../scripts/util.js';
|
import {parseDate} from '../../../utils/date-util.js';
|
||||||
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
|
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
|
||||||
import {appContext} from '../../../services/app-context.js';
|
import {appContext} from '../../../services/app-context.js';
|
||||||
|
|
||||||
@@ -307,8 +307,8 @@ class GrCommentThread extends mixinBehaviors( [
|
|||||||
|
|
||||||
_sortedComments(comments) {
|
_sortedComments(comments) {
|
||||||
return comments.slice().sort((c1, c2) => {
|
return comments.slice().sort((c1, c2) => {
|
||||||
const c1Date = c1.__date || util.parseDate(c1.updated);
|
const c1Date = c1.__date || parseDate(c1.updated);
|
||||||
const c2Date = c2.__date || util.parseDate(c2.updated);
|
const c2Date = c2.__date || parseDate(c2.updated);
|
||||||
const dateCompare = c1Date - c2Date;
|
const dateCompare = c1Date - c2Date;
|
||||||
// Ensure drafts are at the end. There should only be one but in edge
|
// Ensure drafts are at the end. There should only be one but in edge
|
||||||
// cases could be more. In the unlikely event two drafts are being
|
// cases could be more. In the unlikely event two drafts are being
|
||||||
|
|||||||
@@ -22,13 +22,7 @@ import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mix
|
|||||||
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
|
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
|
||||||
import {htmlTemplate} from './gr-date-formatter_html.js';
|
import {htmlTemplate} from './gr-date-formatter_html.js';
|
||||||
import {TooltipBehavior} from '../../../behaviors/gr-tooltip-behavior/gr-tooltip-behavior.js';
|
import {TooltipBehavior} from '../../../behaviors/gr-tooltip-behavior/gr-tooltip-behavior.js';
|
||||||
import {util} from '../../../scripts/util.js';
|
import {parseDate, fromNow, isValidDate, isWithinDay, isWithinHalfYear, formatDate, utcOffsetString} from '../../../utils/date-util.js';
|
||||||
import moment from 'moment/src/moment.js';
|
|
||||||
|
|
||||||
const Duration = {
|
|
||||||
HOUR: 1000 * 60 * 60,
|
|
||||||
DAY: 1000 * 60 * 60 * 24,
|
|
||||||
};
|
|
||||||
|
|
||||||
const TimeFormats = {
|
const TimeFormats = {
|
||||||
TIME_12: 'h:mm A', // 2:14 PM
|
TIME_12: 'h:mm A', // 2:14 PM
|
||||||
@@ -106,6 +100,10 @@ class GrDateFormatter extends mixinBehaviors( [
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
attached() {
|
attached() {
|
||||||
super.attached();
|
super.attached();
|
||||||
@@ -113,7 +111,7 @@ class GrDateFormatter extends mixinBehaviors( [
|
|||||||
}
|
}
|
||||||
|
|
||||||
_getUtcOffsetString() {
|
_getUtcOffsetString() {
|
||||||
return ' UTC' + moment().format('Z');
|
return utcOffsetString();
|
||||||
}
|
}
|
||||||
|
|
||||||
_loadPreferences() {
|
_loadPreferences() {
|
||||||
@@ -190,50 +188,28 @@ class GrDateFormatter extends mixinBehaviors( [
|
|||||||
return this.$.restAPI.getPreferences();
|
return this.$.restAPI.getPreferences();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return true if date is within 24 hours and on the same day.
|
|
||||||
*/
|
|
||||||
_isWithinDay(now, date) {
|
|
||||||
const diff = -date.diff(now);
|
|
||||||
return diff < Duration.DAY && date.day() === now.getDay();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if date is from one to six months.
|
|
||||||
*/
|
|
||||||
_isWithinHalfYear(now, date) {
|
|
||||||
const diff = -date.diff(now);
|
|
||||||
return (date.day() !== now.getDay() || diff >= Duration.DAY) &&
|
|
||||||
diff < 180 * Duration.DAY;
|
|
||||||
}
|
|
||||||
|
|
||||||
_computeDateStr(
|
_computeDateStr(
|
||||||
dateStr, timeFormat, dateFormat, relative, showDateAndTime
|
dateStr, timeFormat, dateFormat, relative, showDateAndTime
|
||||||
) {
|
) {
|
||||||
if (!dateStr || !timeFormat || !dateFormat) { return ''; }
|
if (!dateStr || !timeFormat || !dateFormat) { return ''; }
|
||||||
const date = moment(util.parseDate(dateStr));
|
const date = parseDate(dateStr);
|
||||||
if (!date.isValid()) { return ''; }
|
if (!isValidDate(date)) { return ''; }
|
||||||
if (relative) {
|
if (relative) {
|
||||||
const dateFromNow = date.fromNow();
|
return fromNow(date);
|
||||||
if (dateFromNow === 'a few seconds ago') {
|
|
||||||
return 'just now';
|
|
||||||
} else {
|
|
||||||
return dateFromNow;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
let format = dateFormat.full;
|
let format = dateFormat.full;
|
||||||
if (this._isWithinDay(now, date)) {
|
if (isWithinDay(now, date)) {
|
||||||
format = timeFormat;
|
format = timeFormat;
|
||||||
} else {
|
} else {
|
||||||
if (this._isWithinHalfYear(now, date)) {
|
if (isWithinHalfYear(now, date)) {
|
||||||
format = dateFormat.short;
|
format = dateFormat.short;
|
||||||
}
|
}
|
||||||
if (this.showDateAndTime) {
|
if (this.showDateAndTime) {
|
||||||
format = `${format} ${timeFormat}`;
|
format = `${format} ${timeFormat}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return date.format(format);
|
return formatDate(date, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
_timeToSecondsFormat(timeFormat) {
|
_timeToSecondsFormat(timeFormat) {
|
||||||
@@ -253,11 +229,11 @@ class GrDateFormatter extends mixinBehaviors( [
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!dateStr) { return ''; }
|
if (!dateStr) { return ''; }
|
||||||
const date = moment(util.parseDate(dateStr));
|
const date = parseDate(dateStr);
|
||||||
if (!date.isValid()) { return ''; }
|
if (!isValidDate(date)) { return ''; }
|
||||||
let format = dateFormat.full + ', ';
|
let format = dateFormat.full + ', ';
|
||||||
format += this._timeToSecondsFormat(timeFormat);
|
format += this._timeToSecondsFormat(timeFormat);
|
||||||
return date.format(format) + this._getUtcOffsetString();
|
return formatDate(date, format) + this._getUtcOffsetString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ limitations under the License.
|
|||||||
<script type="module">
|
<script type="module">
|
||||||
import '../../../test/common-test-setup.js';
|
import '../../../test/common-test-setup.js';
|
||||||
import './gr-date-formatter.js';
|
import './gr-date-formatter.js';
|
||||||
import {util} from '../../../scripts/util.js';
|
import {parseDate} from '../../../utils/date-util.js';
|
||||||
suite('gr-date-formatter tests', () => {
|
suite('gr-date-formatter tests', () => {
|
||||||
let element;
|
let element;
|
||||||
let sandbox;
|
let sandbox;
|
||||||
@@ -51,7 +51,7 @@ suite('gr-date-formatter tests', () => {
|
|||||||
* Parse server-formatter date and normalize into current timezone.
|
* Parse server-formatter date and normalize into current timezone.
|
||||||
*/
|
*/
|
||||||
function normalizedDate(dateStr) {
|
function normalizedDate(dateStr) {
|
||||||
const d = util.parseDate(dateStr);
|
const d = parseDate(dateStr);
|
||||||
d.setMinutes(d.getMinutes() + d.getTimezoneOffset());
|
d.setMinutes(d.getMinutes() + d.getTimezoneOffset());
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import {RESTClientBehavior} from '../../../behaviors/rest-client-behavior/rest-c
|
|||||||
import {GrEtagDecorator} from './gr-etag-decorator.js';
|
import {GrEtagDecorator} from './gr-etag-decorator.js';
|
||||||
import {SiteBasedCache, FetchPromisesCache, GrRestApiHelper} from './gr-rest-apis/gr-rest-api-helper.js';
|
import {SiteBasedCache, FetchPromisesCache, GrRestApiHelper} from './gr-rest-apis/gr-rest-api-helper.js';
|
||||||
import {GrReviewerUpdatesParser} from './gr-reviewer-updates-parser.js';
|
import {GrReviewerUpdatesParser} from './gr-reviewer-updates-parser.js';
|
||||||
import {util} from '../../../scripts/util.js';
|
import {parseDate} from '../../../utils/date-util.js';
|
||||||
import {authService} from './gr-auth.js';
|
import {authService} from './gr-auth.js';
|
||||||
|
|
||||||
const DiffViewMode = {
|
const DiffViewMode = {
|
||||||
@@ -2075,7 +2075,7 @@ class GrRestApiInterface extends mixinBehaviors( [
|
|||||||
_setRanges(comments) {
|
_setRanges(comments) {
|
||||||
comments = comments || [];
|
comments = comments || [];
|
||||||
comments.sort(
|
comments.sort(
|
||||||
(a, b) => util.parseDate(a.updated) - util.parseDate(b.updated)
|
(a, b) => parseDate(a.updated) - parseDate(b.updated)
|
||||||
);
|
);
|
||||||
for (const comment of comments) {
|
for (const comment of comments) {
|
||||||
this._setRange(comments, comment);
|
this._setRange(comments, comment);
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {util} from '../../../scripts/util.js';
|
import {parseDate} from '../../../utils/date-util.js';
|
||||||
import {MessageTag} from '../../../constants/constants.js';
|
import {MessageTag} from '../../../constants/constants.js';
|
||||||
|
|
||||||
/** @constructor */
|
/** @constructor */
|
||||||
@@ -106,8 +106,8 @@ GrReviewerUpdatesParser.prototype._groupUpdates = function() {
|
|||||||
if (!this._batch) {
|
if (!this._batch) {
|
||||||
this._batch = this._startBatch(update);
|
this._batch = this._startBatch(update);
|
||||||
}
|
}
|
||||||
const updateDate = util.parseDate(update.updated).getTime();
|
const updateDate = parseDate(update.updated).getTime();
|
||||||
const batchUpdateDate = util.parseDate(this._batch.date).getTime();
|
const batchUpdateDate = parseDate(this._batch.date).getTime();
|
||||||
const reviewerId = update.reviewer._account_id.toString();
|
const reviewerId = update.reviewer._account_id.toString();
|
||||||
if (updateDate - batchUpdateDate >
|
if (updateDate - batchUpdateDate >
|
||||||
GrReviewerUpdatesParser.REVIEWER_UPDATE_THRESHOLD_MILLIS ||
|
GrReviewerUpdatesParser.REVIEWER_UPDATE_THRESHOLD_MILLIS ||
|
||||||
@@ -206,14 +206,14 @@ GrReviewerUpdatesParser.prototype._advanceUpdates = function() {
|
|||||||
const updates = this.result.reviewer_updates;
|
const updates = this.result.reviewer_updates;
|
||||||
const messages = this.result.messages;
|
const messages = this.result.messages;
|
||||||
messages.forEach((message, index) => {
|
messages.forEach((message, index) => {
|
||||||
const messageDate = util.parseDate(message.date).getTime();
|
const messageDate = parseDate(message.date).getTime();
|
||||||
const nextMessageDate = index === messages.length - 1 ? null :
|
const nextMessageDate = index === messages.length - 1 ? null :
|
||||||
util.parseDate(messages[index + 1].date).getTime();
|
parseDate(messages[index + 1].date).getTime();
|
||||||
for (const update of updates) {
|
for (const update of updates) {
|
||||||
const date = util.parseDate(update.date).getTime();
|
const date = parseDate(update.date).getTime();
|
||||||
if (date >= messageDate &&
|
if (date >= messageDate &&
|
||||||
(!nextMessageDate || date < nextMessageDate)) {
|
(!nextMessageDate || date < nextMessageDate)) {
|
||||||
const timestamp = util.parseDate(update.date).getTime() -
|
const timestamp = parseDate(update.date).getTime() -
|
||||||
GrReviewerUpdatesParser.MESSAGE_REVIEWERS_THRESHOLD_MILLIS;
|
GrReviewerUpdatesParser.MESSAGE_REVIEWERS_THRESHOLD_MILLIS;
|
||||||
update.date = new Date(timestamp)
|
update.date = new Date(timestamp)
|
||||||
.toISOString()
|
.toISOString()
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ limitations under the License.
|
|||||||
<script type="module">
|
<script type="module">
|
||||||
import '../../../test/common-test-setup.js';
|
import '../../../test/common-test-setup.js';
|
||||||
import {GrReviewerUpdatesParser} from './gr-reviewer-updates-parser.js';
|
import {GrReviewerUpdatesParser} from './gr-reviewer-updates-parser.js';
|
||||||
import {util} from '../../../scripts/util.js';
|
import {parseDate} from '../../../utils/date-util.js';
|
||||||
|
|
||||||
suite('gr-reviewer-updates-parser tests', () => {
|
suite('gr-reviewer-updates-parser tests', () => {
|
||||||
let sandbox;
|
let sandbox;
|
||||||
@@ -253,7 +253,7 @@ suite('gr-reviewer-updates-parser tests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('_advanceUpdates', () => {
|
test('_advanceUpdates', () => {
|
||||||
const T0 = util.parseDate('2017-02-17 19:04:18.000000000').getTime();
|
const T0 = parseDate('2017-02-17 19:04:18.000000000').getTime();
|
||||||
const tplus = delta => new Date(T0 + delta)
|
const tplus = delta => new Date(T0 + delta)
|
||||||
.toISOString()
|
.toISOString()
|
||||||
.replace('T', ' ')
|
.replace('T', ' ')
|
||||||
@@ -297,8 +297,8 @@ suite('gr-reviewer-updates-parser tests', () => {
|
|||||||
instance = new GrReviewerUpdatesParser(change);
|
instance = new GrReviewerUpdatesParser(change);
|
||||||
instance._advanceUpdates();
|
instance._advanceUpdates();
|
||||||
const updates = instance.result.reviewer_updates;
|
const updates = instance.result.reviewer_updates;
|
||||||
assert.isBelow(util.parseDate(updates[0].date).getTime(), T0);
|
assert.isBelow(parseDate(updates[0].date).getTime(), T0);
|
||||||
assert.isBelow(util.parseDate(updates[1].date).getTime(), T0);
|
assert.isBelow(parseDate(updates[1].date).getTime(), T0);
|
||||||
assert.equal(updates[2].date, tplus(100));
|
assert.equal(updates[2].date, tplus(100));
|
||||||
assert.equal(updates[3].date, tplus(500));
|
assert.equal(updates[3].date, tplus(500));
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -272,14 +272,6 @@ const packages: PackageInfo[] = [
|
|||||||
name: "isarray",
|
name: "isarray",
|
||||||
license: SharedLicenses.IsArray
|
license: SharedLicenses.IsArray
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "moment",
|
|
||||||
license: {
|
|
||||||
name: "moment",
|
|
||||||
type: LicenseTypes.Mit,
|
|
||||||
packageLicenseFile: "LICENSE"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "page",
|
name: "page",
|
||||||
license: SharedLicenses.Page
|
license: SharedLicenses.Page
|
||||||
|
|||||||
@@ -26,7 +26,6 @@
|
|||||||
"@webcomponents/shadycss": "^1.9.2",
|
"@webcomponents/shadycss": "^1.9.2",
|
||||||
"@webcomponents/webcomponentsjs": "^1.3.3",
|
"@webcomponents/webcomponentsjs": "^1.3.3",
|
||||||
"es6-promise": "^3.3.1",
|
"es6-promise": "^3.3.1",
|
||||||
"moment": "^2.24.0",
|
|
||||||
"page": "^1.11.5",
|
"page": "^1.11.5",
|
||||||
"polymer-bridges": "file:../../polymer-bridges/",
|
"polymer-bridges": "file:../../polymer-bridges/",
|
||||||
"ba-linkify": "file:../../lib/ba-linkify/src/",
|
"ba-linkify": "file:../../lib/ba-linkify/src/",
|
||||||
|
|||||||
@@ -29,14 +29,6 @@ function getPathFromNode(el) {
|
|||||||
// TODO (dmfilippov): Each function must be exported separately. According to
|
// TODO (dmfilippov): Each function must be exported separately. According to
|
||||||
// the code style guide, a namespacing is not allowed.
|
// the code style guide, a namespacing is not allowed.
|
||||||
export const util = {
|
export const util = {
|
||||||
parseDate(dateStr) {
|
|
||||||
// Timestamps are given in UTC and have the format
|
|
||||||
// "'yyyy-mm-dd hh:mm:ss.fffffffff'" where "'ffffffffff'" represents
|
|
||||||
// nanoseconds.
|
|
||||||
// Munge the date into an ISO 8061 format and parse that.
|
|
||||||
return new Date(dateStr.replace(' ', 'T') + 'Z');
|
|
||||||
},
|
|
||||||
|
|
||||||
getCookie(name) {
|
getCookie(name) {
|
||||||
const key = name + '=';
|
const key = name + '=';
|
||||||
const cookies = document.cookie.split(';');
|
const cookies = document.cookie.split(';');
|
||||||
|
|||||||
@@ -58,6 +58,5 @@ var FetchPromisesCache;
|
|||||||
var GrRestApiHelper;
|
var GrRestApiHelper;
|
||||||
var GrDisplayNameUtils;
|
var GrDisplayNameUtils;
|
||||||
var GrReviewerSuggestionsProvider;
|
var GrReviewerSuggestionsProvider;
|
||||||
var moment;
|
|
||||||
var page;
|
var page;
|
||||||
var util;
|
var util;
|
||||||
172
polygerrit-ui/app/utils/date-util.js
Normal file
172
polygerrit-ui/app/utils/date-util.js
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright (C) 2020 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const Duration = {
|
||||||
|
HOUR: 1000 * 60 * 60,
|
||||||
|
DAY: 1000 * 60 * 60 * 24,
|
||||||
|
};
|
||||||
|
|
||||||
|
export function parseDate(dateStr) {
|
||||||
|
// Timestamps are given in UTC and have the format
|
||||||
|
// "'yyyy-mm-dd hh:mm:ss.fffffffff'" where "'ffffffffff'" represents
|
||||||
|
// nanoseconds.
|
||||||
|
// Munge the date into an ISO 8061 format and parse that.
|
||||||
|
return new Date(dateStr.replace(' ', 'T') + 'Z');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isValidDate(date) {
|
||||||
|
return date instanceof Date && !isNaN(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
// similar to fromNow from moment.js
|
||||||
|
export function fromNow(date) {
|
||||||
|
const now = new Date();
|
||||||
|
const secondsAgo = Math.round((now - date) / 1000);
|
||||||
|
if (secondsAgo <= 44) return 'just now';
|
||||||
|
if (secondsAgo <= 89) return 'a minute ago';
|
||||||
|
const minutesAgo = Math.round(secondsAgo / 60);
|
||||||
|
if (minutesAgo <= 44) return `${minutesAgo} minutes ago`;
|
||||||
|
if (minutesAgo <= 89) return 'an hour ago';
|
||||||
|
const hoursAgo = Math.round(minutesAgo / 60);
|
||||||
|
if (hoursAgo <= 21) return `${hoursAgo} hours ago`;
|
||||||
|
if (hoursAgo <= 35) return 'a day ago';
|
||||||
|
const daysAgo = Math.round(hoursAgo / 24);
|
||||||
|
if (daysAgo <= 25) return `${daysAgo} days ago`;
|
||||||
|
if (daysAgo <= 45) return `a month ago`;
|
||||||
|
const monthsAgo = Math.round(daysAgo / 30);
|
||||||
|
if (daysAgo <= 319) return `${monthsAgo} months ago`;
|
||||||
|
if (daysAgo <= 547) return `a year ago`;
|
||||||
|
const yearsAgo = Math.round(daysAgo / 365);
|
||||||
|
return `${yearsAgo} years ago`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if date is within 24 hours and on the same day.
|
||||||
|
*/
|
||||||
|
export function isWithinDay(now, date) {
|
||||||
|
const diff = now - date;
|
||||||
|
return diff < Duration.DAY && date.getDay() == now.getDay();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if date is from one to six months.
|
||||||
|
*/
|
||||||
|
export function isWithinHalfYear(now, date) {
|
||||||
|
const diff = now - date;
|
||||||
|
return diff < 180 * Duration.DAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatDate(date, format) {
|
||||||
|
const options = {};
|
||||||
|
if (format.includes('MM')) {
|
||||||
|
if (format.includes('MMM')) {
|
||||||
|
options.month = 'short';
|
||||||
|
} else {
|
||||||
|
options.month = '2-digit';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (format.includes('YY')) {
|
||||||
|
if (format.includes('YYYY')) {
|
||||||
|
options.year = 'numeric';
|
||||||
|
} else {
|
||||||
|
options.year = '2-digit';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format.includes('DD')) {
|
||||||
|
options.day = '2-digit';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format.includes('HH')) {
|
||||||
|
options.hour = '2-digit';
|
||||||
|
options.hour12 = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format.includes('h')) {
|
||||||
|
options.hour = 'numeric';
|
||||||
|
options.hour12 = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format.includes('mm')) {
|
||||||
|
options.minute = '2-digit';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format.includes('ss')) {
|
||||||
|
options.second = '2-digit';
|
||||||
|
}
|
||||||
|
// en-GB is using h23 on Chrome 80, en-US is using h24 (midnight is 24:00)
|
||||||
|
const dtf = new Intl.DateTimeFormat('en-GB', options);
|
||||||
|
const parts = dtf.formatToParts(date).filter(o => o.type != 'literal')
|
||||||
|
.reduce((acc, o) => {
|
||||||
|
acc[o.type] = o.value;
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
if (format.includes('YY')) {
|
||||||
|
if (format.includes('YYYY')) {
|
||||||
|
format = format.replace('YYYY', parts.year);
|
||||||
|
} else {
|
||||||
|
format = format.replace('YY', parts.year);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format.includes('DD')) {
|
||||||
|
format = format.replace('DD', parts.day);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format.includes('HH')) {
|
||||||
|
format = format.replace('HH', parts.hour);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format.includes('h')) {
|
||||||
|
format = format.replace('h', parts.hour);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format.includes('mm')) {
|
||||||
|
format = format.replace('mm', parts.minute);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format.includes('ss')) {
|
||||||
|
format = format.replace('ss', parts.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format.includes('A')) {
|
||||||
|
if (parts.dayperiod) {
|
||||||
|
// Workaround for chrome 70 and below
|
||||||
|
format = format.replace('A', parts.dayperiod.toUpperCase());
|
||||||
|
} else {
|
||||||
|
format = format.replace('A', parts.dayPeriod.toUpperCase());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (format.includes('MM')) {
|
||||||
|
if (format.includes('MMM')) {
|
||||||
|
format = format.replace('MMM', parts.month);
|
||||||
|
} else {
|
||||||
|
format = format.replace('MM', parts.month);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function utcOffsetString() {
|
||||||
|
const now = new Date();
|
||||||
|
const tzo = -now.getTimezoneOffset();
|
||||||
|
const pad = num => {
|
||||||
|
const norm = Math.floor(Math.abs(num));
|
||||||
|
return (norm < 10 ? '0' : '') + norm;
|
||||||
|
};
|
||||||
|
return ` UTC${tzo >= 0 ? '+' : '-'}${pad(tzo / 60)}:${pad(tzo%60)}`;
|
||||||
|
}
|
||||||
114
polygerrit-ui/app/utils/date-util_test.js
Normal file
114
polygerrit-ui/app/utils/date-util_test.js
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright (C) 2020 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import '../test/common-test-setup-karma.js';
|
||||||
|
import {isValidDate, parseDate, fromNow, isWithinDay, isWithinHalfYear, formatDate} from './date-util.js';
|
||||||
|
|
||||||
|
suite('date-util tests', () => {
|
||||||
|
suite('parseDate', () => {
|
||||||
|
test('parseDate server date', () => {
|
||||||
|
const parsed = parseDate('2015-09-15 20:34:00.000000000');
|
||||||
|
assert.equal('2015-09-15T20:34:00.000Z', parsed.toISOString());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
suite('isValidDate', () => {
|
||||||
|
test('date is valid', () => {
|
||||||
|
assert.isTrue(isValidDate(new Date()));
|
||||||
|
});
|
||||||
|
test('broken date is invalid', () => {
|
||||||
|
assert.isFalse(isValidDate(new Date('xxx')));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
suite('fromNow', () => {
|
||||||
|
test('test all variants', () => {
|
||||||
|
const fakeNow = new Date('May 08 2020 12:00:00');
|
||||||
|
sinon.useFakeTimers(fakeNow.getTime());
|
||||||
|
assert.equal('just now', fromNow(new Date('May 08 2020 11:59:30')));
|
||||||
|
assert.equal('a minute ago', fromNow(new Date('May 08 2020 11:59:00')));
|
||||||
|
assert.equal('5 minutes ago', fromNow(new Date('May 08 2020 11:55:00')));
|
||||||
|
assert.equal('an hour ago', fromNow(new Date('May 08 2020 11:00:00')));
|
||||||
|
assert.equal('3 hours ago', fromNow(new Date('May 08 2020 9:00:00')));
|
||||||
|
assert.equal('a day ago', fromNow(new Date('May 07 2020 12:00:00')));
|
||||||
|
assert.equal('3 days ago', fromNow(new Date('May 05 2020 12:00:00')));
|
||||||
|
assert.equal('a month ago', fromNow(new Date('Apr 05 2020 12:00:00')));
|
||||||
|
assert.equal('2 months ago', fromNow(new Date('Mar 05 2020 12:00:00')));
|
||||||
|
assert.equal('a year ago', fromNow(new Date('May 05 2019 12:00:00')));
|
||||||
|
assert.equal('10 years ago', fromNow(new Date('May 05 2010 12:00:00')));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
suite('isWithinDay', () => {
|
||||||
|
test('basics works', () => {
|
||||||
|
assert.isTrue(isWithinDay(new Date('May 08 2020 12:00:00'),
|
||||||
|
new Date('May 08 2020 02:00:00')));
|
||||||
|
assert.isFalse(isWithinDay(new Date('May 08 2020 12:00:00'),
|
||||||
|
new Date('May 07 2020 12:00:00')));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
suite('isWithinHalfYear', () => {
|
||||||
|
test('basics works', () => {
|
||||||
|
assert.isTrue(isWithinHalfYear(new Date('May 08 2020 12:00:00'),
|
||||||
|
new Date('Feb 08 2020 12:00:00')));
|
||||||
|
assert.isFalse(isWithinHalfYear(new Date('May 08 2020 12:00:00'),
|
||||||
|
new Date('Nov 07 2019 12:00:00')));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
suite('formatDate', () => {
|
||||||
|
test('works for standard format', () => {
|
||||||
|
const stdFormat = 'MMM DD, YYYY';
|
||||||
|
assert.equal('May 08, 2020',
|
||||||
|
formatDate(new Date('May 08 2020 12:00:00'), stdFormat));
|
||||||
|
assert.equal('Feb 28, 2020',
|
||||||
|
formatDate(new Date('Feb 28 2020 12:00:00'), stdFormat));
|
||||||
|
|
||||||
|
const time24Format = 'HH:mm:ss';
|
||||||
|
assert.equal('Feb 28, 2020 12:01:12',
|
||||||
|
formatDate(new Date('Feb 28 2020 12:01:12'), stdFormat + ' '
|
||||||
|
+ time24Format));
|
||||||
|
});
|
||||||
|
test('works for euro format', () => {
|
||||||
|
const euroFormat = 'DD.MM.YYYY';
|
||||||
|
assert.equal('01.12.2019',
|
||||||
|
formatDate(new Date('Dec 01 2019 12:00:00'), euroFormat));
|
||||||
|
assert.equal('20.01.2002',
|
||||||
|
formatDate(new Date('Jan 20 2002 12:00:00'), euroFormat));
|
||||||
|
|
||||||
|
const time24Format = 'HH:mm:ss';
|
||||||
|
assert.equal('28.02.2020 00:01:12',
|
||||||
|
formatDate(new Date('Feb 28 2020 00:01:12'), euroFormat + ' '
|
||||||
|
+ time24Format));
|
||||||
|
});
|
||||||
|
test('works for iso format', () => {
|
||||||
|
const isoFormat = 'YYYY-MM-DD';
|
||||||
|
assert.equal('2015-01-01',
|
||||||
|
formatDate(new Date('Jan 01 2015 12:00:00'), isoFormat));
|
||||||
|
assert.equal('2013-07-03',
|
||||||
|
formatDate(new Date('Jul 03 2013 12:00:00'), isoFormat));
|
||||||
|
|
||||||
|
const timeFormat = 'h:mm:ss A';
|
||||||
|
assert.equal('2013-07-03 5:00:00 AM',
|
||||||
|
formatDate(new Date('Jul 03 2013 05:00:00'), isoFormat + ' '
|
||||||
|
+ timeFormat));
|
||||||
|
assert.equal('2013-07-03 5:00:00 PM',
|
||||||
|
formatDate(new Date('Jul 03 2013 17:00:00'), isoFormat + ' '
|
||||||
|
+ timeFormat));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -338,11 +338,6 @@ isarray@0.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
|
resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
|
||||||
integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=
|
integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=
|
||||||
|
|
||||||
moment@^2.24.0:
|
|
||||||
version "2.24.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
|
|
||||||
integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==
|
|
||||||
|
|
||||||
page@^1.11.5:
|
page@^1.11.5:
|
||||||
version "1.11.5"
|
version "1.11.5"
|
||||||
resolved "https://registry.yarnpkg.com/page/-/page-1.11.5.tgz#0cfc8608be337f26f4377f31df0787aef0ca1af7"
|
resolved "https://registry.yarnpkg.com/page/-/page-1.11.5.tgz#0cfc8608be337f26f4377f31df0787aef0ca1af7"
|
||||||
|
|||||||
Reference in New Issue
Block a user