"d3-scale": "1.0.5",
"d3-selection": "1.0.5",
"d3-shape": "1.0.6",
+ "date-fns": "1.28.5",
"escape-html": "1.0.3",
"handlebars": "2.0.0",
"history": "3.3.0",
},
"devDependencies": {
"@types/classnames": "2.2.0",
+ "@types/date-fns": "2.6.0",
"@types/enzyme": "2.8.6",
"@types/escape-html": "0.0.19",
"@types/jest": "20.0.7",
],
"jest": {
"coverageDirectory": "<rootDir>/target/coverage",
- "coveragePathIgnorePatterns": [
- "<rootDir>/node_modules",
- "<rootDir>/tests"
- ],
- "moduleFileExtensions": [
- "ts",
- "tsx",
- "js",
- "json"
- ],
+ "coveragePathIgnorePatterns": ["<rootDir>/node_modules", "<rootDir>/tests"],
+ "moduleFileExtensions": ["ts", "tsx", "js", "json"],
"moduleNameMapper": {
"^.+\\.(hbs|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/config/jest/FileStub.js",
"^.+\\.css$": "<rootDir>/config/jest/CSSStub.js"
"<rootDir>/config/polyfills.js",
"<rootDir>/config/jest/SetupTestEnvironment.js"
],
- "snapshotSerializers": [
- "enzyme-to-json/serializer"
- ],
+ "snapshotSerializers": ["enzyme-to-json/serializer"],
"testPathIgnorePatterns": [
"<rootDir>/node_modules",
"<rootDir>/src/main/webapp",
}
bundleLoaded = (lang: string) => {
- import('react-intl/locale-data/' + (lang || DEFAULT_LANGUAGE)).then(
- i => this.updateLang(lang, i),
- () => {
- import('react-intl/locale-data/en').then(i => this.updateLang(lang, i));
- }
- );
+ const langToLoad = lang || DEFAULT_LANGUAGE;
+
+ // No need to load english bundle, it's coming wiht react-intl
+ if (langToLoad !== 'en') {
+ import('react-intl/locale-data/' + langToLoad).then(i => this.updateLang(langToLoad, i));
+ } else {
+ this.setState({ loading: false, lang: langToLoad });
+ }
};
updateLang = (lang: string, intlBundle: Locale[]) => {
*/
import * as React from 'react';
import { sortBy } from 'lodash';
-import { FormattedRelative } from 'react-intl';
import { Link } from 'react-router';
import { Project } from './types';
+import DateFromNow from '../../../components/intl/DateFromNow';
import DateTimeFormatter from '../../../components/intl/DateTimeFormatter';
import Level from '../../../components/ui/Level';
import Tooltip from '../../../components/controls/Tooltip';
overlay={<DateTimeFormatter date={project.lastAnalysisDate} />}
placement="right">
<div className="account-project-analysis">
- <FormattedRelative value={project.lastAnalysisDate}>
- {(relativeDate: string) =>
+ <DateFromNow date={project.lastAnalysisDate}>
+ {(fromNow: string) =>
<span>
- {translateWithParameters('my_account.projects.analyzed_x', relativeDate)}
+ {translateWithParameters('my_account.projects.analyzed_x', fromNow)}
</span>}
- </FormattedRelative>
+ </DateFromNow>
</div>
</Tooltip>
: <div className="account-project-analysis">
it('should render analysis date', () => {
const project = { ...BASE, lastAnalysisDate: '2016-05-17' };
const output = shallow(<ProjectCard project={project} />);
- expect(output.find('.account-project-analysis FormattedRelative')).toHaveLength(1);
+ expect(output.find('.account-project-analysis DateFromNow')).toHaveLength(1);
});
it('should not render analysis date', () => {
*/
import $ from 'jquery';
import React, { Component } from 'react';
-import { toShortNotSoISOString, isValidDate } from '../../../helpers/dates';
+import { isValidDate, parseDate, toShortNotSoISOString } from '../../../helpers/dates';
export default class DateFilter extends Component {
componentDidMount() {
handleChange() {
const date = {};
- const minDate = new Date(this.refs.minDate.value);
- const maxDate = new Date(this.refs.maxDate.value);
+ const minDate = parseDate(this.refs.minDate.value);
+ const maxDate = parseDate(this.refs.maxDate.value);
if (isValidDate(minDate)) {
date.minSubmittedAt = toShortNotSoISOString(minDate);
*/
import * as React from 'react';
import TimeFormatter from '../../../components/intl/TimeFormatter';
-import { differenceInDays, isValidDate } from '../../../helpers/dates';
+import { differenceInDays, isValidDate, parseDate } from '../../../helpers/dates';
interface Props {
date: string;
}
export default function TaskDate({ date, baseDate }: Props) {
- const parsedDate = new Date(date);
- const parsedBaseDate = new Date(baseDate);
+ const parsedDate = parseDate(date);
+ const parsedBaseDate = parseDate(baseDate);
const diff =
date && baseDate && isValidDate(parsedDate) && isValidDate(parsedBaseDate)
? differenceInDays(parsedDate, parsedBaseDate)
*/
import * as React from 'react';
import DateFormatter from '../../../components/intl/DateFormatter';
-import { isSameDay } from '../../../helpers/dates';
+import { isSameDay, parseDate } from '../../../helpers/dates';
import { ITask } from '../types';
interface Props {
export default function TaskDay({ task, prevTask }: Props) {
const shouldDisplay =
- !prevTask || !isSameDay(new Date(task.submittedAt), new Date(prevTask.submittedAt));
+ !prevTask || !isSameDay(parseDate(task.submittedAt), parseDate(prevTask.submittedAt));
return (
<td className="thin nowrap text-right">
// @flow
import React from 'react';
import classNames from 'classnames';
-import { FormattedRelative } from 'react-intl';
+import DateFromNow from '../../../components/intl/DateFromNow';
import DateFormatter from '../../../components/intl/DateFormatter';
import Tooltip from '../../../components/controls/Tooltip';
import { getPeriodLabel, getPeriodDate } from '../../../helpers/periods';
const date = getPeriodDate(period);
const tooltip = (
<div>
- <FormattedRelative value={date} />
+ <DateFromNow date={date} />
{', '}
<DateFormatter date={date} long={true} />
</div>
import { enhanceComponent, isFileType, isViewType } from '../utils';
import { getProjectUrl } from '../../../helpers/urls';
import { isDiffMetric } from '../../../helpers/measures';
+import { parseDate } from '../../../helpers/dates';
/*:: import type { Component, ComponentEnhanced, Paging, Period } from '../types'; */
/*:: import type { MeasureEnhanced } from '../../../components/measure/types'; */
/*:: import type { Metric } from '../../../store/metrics/actions'; */
renderCode() {
const { component, leakPeriod } = this.props;
const leakPeriodDate =
- isDiffMetric(this.props.metric.key) && leakPeriod != null ? new Date(leakPeriod.date) : null;
+ isDiffMetric(this.props.metric.key) && leakPeriod != null ? parseDate(leakPeriod.date) : null;
let filterLine;
if (leakPeriodDate != null) {
filterLine = line => {
if (line.scmDate) {
- const scmDate = new Date(line.scmDate);
+ const scmDate = parseDate(line.scmDate);
return scmDate >= leakPeriodDate;
} else {
return false;
<Tooltip
overlay={
<div>
- <FormattedRelative
- updateInterval={10000}
- value={2017-05-16T11:50:02.000Z}
+ <DateFromNow
+ date={2017-05-16T11:50:02.000Z}
/>
,
<DateFormatter
// @flow
import React from 'react';
import { max } from 'lodash';
-import { FormattedRelative, intlShape } from 'react-intl';
-import { formatterOption, longFormatterOption } from '../../../components/intl/DateFormatter';
+import { intlShape } from 'react-intl';
+import DateFromNow from '../../../components/intl/DateFromNow';
+import { longFormatterOption } from '../../../components/intl/DateFormatter';
import DateTimeFormatter from '../../../components/intl/DateTimeFormatter';
import FacetBox from '../../../components/facet/FacetBox';
import FacetHeader from '../../../components/facet/FacetHeader';
import FacetItem from '../../../components/facet/FacetItem';
import { BarChart } from '../../../components/charts/bar-chart';
import DateInput from '../../../components/controls/DateInput';
-import { isSameDay, toShortNotSoISOString } from '../../../helpers/dates';
+import { isSameDay, parseDate, toShortNotSoISOString } from '../../../helpers/dates';
import { translate } from '../../../helpers/l10n';
import { formatMeasure } from '../../../helpers/measures';
/*:: import type { Component } from '../utils'; */
createdAt: undefined,
createdInLast: undefined,
sinceLeakPeriod: undefined,
- [property]: toShortNotSoISOString(new Date(value))
+ [property]: toShortNotSoISOString(parseDate(value))
});
};
const { formatDate } = this.context.intl;
const beforeDate = createdBefore ? createdBefore : undefined;
const data = periods.map((start, index) => {
- const startDate = new Date(start);
+ const startDate = parseDate(start);
let nextStartDate = index < periods.length - 1 ? periods[index + 1] : beforeDate;
let endDate;
if (nextStartDate) {
- nextStartDate = new Date(nextStartDate);
- endDate = new Date(nextStartDate);
+ nextStartDate = parseDate(nextStartDate);
+ endDate = parseDate(nextStartDate);
endDate.setDate(endDate.getDate() - 1);
}
<DateTimeFormatter date={this.props.createdAt} />
<br />
<span className="note">
- <FormattedRelative value={this.props.createdAt} />
+ <DateFromNow date={this.props.createdAt} />
</span>
</div>
);
renderPeriodSelectors() {
const { createdAfter, createdBefore } = this.props;
- const { formatDate } = this.context.intl;
return (
<div className="search-navigator-date-facet-selection">
<DateInput
className="search-navigator-date-facet-selection-dropdown-left"
onChange={this.handlePeriodChangeAfter}
placeholder={translate('from')}
- value={createdAfter ? formatDate(createdAfter, formatterOption) : undefined}
+ value={createdAfter ? toShortNotSoISOString(createdAfter) : undefined}
/>
<DateInput
className="search-navigator-date-facet-selection-dropdown-right"
onChange={this.handlePeriodChangeBefore}
placeholder={translate('to')}
- value={createdBefore ? formatDate(createdBefore, formatterOption) : undefined}
+ value={createdBefore ? toShortNotSoISOString(createdBefore) : undefined}
/>
</div>
);
*/
// @flow
import React from 'react';
-import { FormattedRelative } from 'react-intl';
+import DateFromNow from '../../../components/intl/DateFromNow';
import DateFormatter from '../../../components/intl/DateFormatter';
import Tooltip from '../../../components/controls/Tooltip';
import { getPeriodDate, getPeriodLabel } from '../../../helpers/periods';
<div className="overview-legend">
{translateWithParameters('overview.leak_period_x', leakPeriodLabel)}
<br />
- <FormattedRelative value={leakPeriodDate}>
+ <DateFromNow date={leakPeriodDate}>
{fromNow =>
<span className="note">
{translateWithParameters(
fromNow
)}
</span>}
- </FormattedRelative>
+ </DateFromNow>
</div>
</Tooltip>
);
import throwGlobalError from '../../../app/utils/throwGlobalError';
import { getMeasuresAndMeta } from '../../../api/measures';
import { getAllTimeMachineData } from '../../../api/time-machine';
+import { parseDate } from '../../../helpers/dates';
import { enhanceMeasuresWithMetrics } from '../../../helpers/measures';
import { getLeakPeriod } from '../../../helpers/periods';
import { getCustomGraph, getGraph } from '../../../helpers/storage';
const history /*: History */ = {};
r.measures.forEach(measure => {
const measureHistory = measure.history.map(analysis => ({
- date: new Date(analysis.date),
+ date: parseDate(analysis.date),
value: analysis.value
}));
history[measure.metric] = measureHistory;
mode: 'date',
parameter: '2013-01-01'
};
- expect(
- shallow(<LeakPeriodLegend period={period} />).find('FormattedRelative')
- ).toMatchSnapshot();
+ expect(shallow(<LeakPeriodLegend period={period} />).find('DateFromNow')).toMatchSnapshot();
});
it('version', () => {
mode: 'version',
parameter: '0.1'
};
- expect(
- shallow(<LeakPeriodLegend period={period} />).find('FormattedRelative')
- ).toMatchSnapshot();
+ expect(shallow(<LeakPeriodLegend period={period} />).find('DateFromNow')).toMatchSnapshot();
});
it('previous_version', () => {
date: '2013-09-22T00:00:00+0200',
mode: 'previous_version'
};
- expect(shallow(<LeakPeriodLegend period={period} />).find('FormattedRelative')).toHaveLength(1);
+ expect(shallow(<LeakPeriodLegend period={period} />).find('DateFromNow')).toHaveLength(1);
});
it('previous_analysis', () => {
date: '2013-09-22T00:00:00+0200',
mode: 'previous_analysis'
};
- expect(shallow(<LeakPeriodLegend period={period} />).find('FormattedRelative')).toHaveLength(1);
+ expect(shallow(<LeakPeriodLegend period={period} />).find('DateFromNow')).toHaveLength(1);
});
});
import React from 'react';
import { shallow } from 'enzyme';
import Timeline from '../Timeline';
+import { parseDate } from '../../../../helpers/dates';
-const range = new Date('2017-05-01T00:00:00.000Z');
+const range = parseDate('2017-05-01T00:00:00.000Z');
const history = [
- { date: new Date('2017-04-08T00:00:00.000Z'), value: '29.6' },
- { date: new Date('2017-04-09T00:00:00.000Z'), value: '170.8' },
- { date: new Date('2017-05-08T00:00:00.000Z'), value: '360' },
- { date: new Date('2017-05-09T00:00:00.000Z'), value: '39' }
+ { date: parseDate('2017-04-08T00:00:00.000Z'), value: '29.6' },
+ { date: parseDate('2017-04-09T00:00:00.000Z'), value: '170.8' },
+ { date: parseDate('2017-05-08T00:00:00.000Z'), value: '360' },
+ { date: parseDate('2017-05-09T00:00:00.000Z'), value: '39' }
];
it('should render correctly with an "after" range', () => {
});
it('should have a correct domain with strings or numbers', () => {
- const date = new Date('2017-05-08T00:00:00.000Z');
+ const date = parseDate('2017-05-08T00:00:00.000Z');
const wrapper = shallow(<Timeline after={range} history={history} />);
expect(wrapper.find('LineChart').props().domain).toEqual([0, 360]);
`;
exports[`check note date 1`] = `
-<FormattedRelative
- updateInterval={10000}
- value={2013-09-21T22:00:00.000Z}
+<DateFromNow
+ date={2013-09-21T22:00:00.000Z}
/>
`;
exports[`check note version 1`] = `
-<FormattedRelative
- updateInterval={10000}
- value={2013-09-21T22:00:00.000Z}
+<DateFromNow
+ date={2013-09-21T22:00:00.000Z}
/>
`;
import { shallow } from 'enzyme';
import PreviewGraphTooltips from '../PreviewGraphTooltips';
import { DEFAULT_GRAPH } from '../../../projectActivity/utils';
+import { parseDate } from '../../../../helpers/dates';
const SERIES_ISSUES = [
{
graph: DEFAULT_GRAPH,
graphWidth: 150,
metrics: METRICS,
- selectedDate: new Date('2011-10-01T22:01:00.000Z'),
+ selectedDate: parseDate('2011-10-01T22:01:00.000Z'),
series: SERIES_ISSUES,
tooltipIdx: 0,
tooltipPos: 25
<PreviewGraphTooltips
{...DEFAULT_PROPS}
graph="random"
- selectedDate={new Date('2011-10-25T10:27:41.000Z')}
+ selectedDate={parseDate('2011-10-25T10:27:41.000Z')}
tooltipIdx={1}
/>
)
*/
import React from 'react';
import { Link } from 'react-router';
-import { FormattedRelative } from 'react-intl';
import Tooltip from '../../../components/controls/Tooltip';
+import DateFromNow from '../../../components/intl/DateFromNow';
import DateTimeFormatter from '../../../components/intl/DateTimeFormatter';
import enhance from './enhance';
import { getMetricName } from '../helpers/metrics';
return null;
}
return (
- <FormattedRelative value={this.props.historyStartDate}>
+ <DateFromNow date={this.props.historyStartDate}>
{fromNow =>
<span className="overview-domain-timeline-date">
{translateWithParameters('overview.started_x', fromNow)}
</span>}
- </FormattedRelative>
+ </DateFromNow>
);
}
*/
// @flow
import * as actions from '../actions';
+import { parseDate } from '../../../helpers/dates';
const ANALYSES = [
{
key: 'A1',
- date: new Date('2016-10-27T16:33:50+0200'),
+ date: parseDate('2016-10-27T16:33:50+0200'),
events: [
{
key: 'E1',
},
{
key: 'A2',
- date: new Date('2016-10-27T12:21:15+0200'),
+ date: parseDate('2016-10-27T12:21:15+0200'),
events: []
},
{
key: 'A3',
- date: new Date('2016-10-26T12:17:29+0200'),
+ date: parseDate('2016-10-26T12:17:29+0200'),
events: [
{
key: 'E2',
const ANALYSES = [
{
key: 'AVyMjlK1HjR_PLDzRbB9',
- date: new Date('2017-06-09T13:06:10.000Z'),
+ date: dates.parseDate('2017-06-09T13:06:10.000Z'),
events: [{ key: 'AVyM9oI1HjR_PLDzRciU', category: 'VERSION', name: '1.1-SNAPSHOT' }]
},
- { key: 'AVyM9n3cHjR_PLDzRciT', date: new Date('2017-06-09T11:12:27.000Z'), events: [] },
+ { key: 'AVyM9n3cHjR_PLDzRciT', date: dates.parseDate('2017-06-09T11:12:27.000Z'), events: [] },
{
key: 'AVyMjlK1HjR_PLDzRbB9',
- date: new Date('2017-06-09T11:12:27.000Z'),
+ date: dates.parseDate('2017-06-09T11:12:27.000Z'),
events: [{ key: 'AVyM9oI1HjR_PLDzRciU', category: 'VERSION', name: '1.1' }]
},
{
key: 'AVxZtCpH7841nF4RNEMI',
- date: new Date('2017-05-18T14:13:07.000Z'),
+ date: dates.parseDate('2017-05-18T14:13:07.000Z'),
events: [
{
key: 'AVxZtC-N7841nF4RNEMJ',
}
]
},
- { key: 'AVwaa1qkpbBde8B6UhYI', date: new Date('2017-05-18T07:17:32.000Z'), events: [] },
+ { key: 'AVwaa1qkpbBde8B6UhYI', date: dates.parseDate('2017-05-18T07:17:32.000Z'), events: [] },
{
key: 'AVwQF7kwl-nNFgFWOJ3V',
- date: new Date('2017-05-16T07:09:59.000Z'),
+ date: dates.parseDate('2017-05-16T07:09:59.000Z'),
events: [
{ key: 'AVyM9oI1HjR_PLDzRciU', category: 'VERSION', name: '1.0' },
{
}
]
},
- { key: 'AVvtGF3IY6vCuQNDdwxI', date: new Date('2017-05-09T12:03:59.000Z'), events: [] }
+ { key: 'AVvtGF3IY6vCuQNDdwxI', date: dates.parseDate('2017-05-09T12:03:59.000Z'), events: [] }
];
const HISTORY = [
{
metric: 'lines_to_cover',
history: [
- { date: new Date('2017-04-27T08:21:32.000Z'), value: '100' },
- { date: new Date('2017-04-30T23:06:24.000Z'), value: '100' }
+ { date: dates.parseDate('2017-04-27T08:21:32.000Z'), value: '100' },
+ { date: dates.parseDate('2017-04-30T23:06:24.000Z'), value: '100' }
]
},
{
metric: 'uncovered_lines',
history: [
- { date: new Date('2017-04-27T08:21:32.000Z'), value: '12' },
- { date: new Date('2017-04-30T23:06:24.000Z'), value: '50' }
+ { date: dates.parseDate('2017-04-27T08:21:32.000Z'), value: '12' },
+ { date: dates.parseDate('2017-04-30T23:06:24.000Z'), value: '50' }
]
}
];
const QUERY = {
category: '',
- from: new Date('2017-04-27T08:21:32.000Z'),
+ from: dates.parseDate('2017-04-27T08:21:32.000Z'),
graph: utils.DEFAULT_GRAPH,
project: 'foo',
to: undefined,
startDay.setUTCHours(0, 0, 0, 0);
return startDay;
});
-
it('should correctly map analysis by versions and by days', () => {
expect(
utils.getAnalysesByVersionByDay(ANALYSES, {
customMetrics: [],
graph: utils.DEFAULT_GRAPH,
project: 'foo',
- to: new Date('2017-06-09T11:12:27.000Z'),
- from: new Date('2017-05-18T14:13:07.000Z')
+ to: dates.parseDate('2017-06-09T11:12:27.000Z'),
+ from: dates.parseDate('2017-05-18T14:13:07.000Z')
})
).toMatchSnapshot();
});
expect(
utils.getAnalysesByVersionByDay(
[
- { key: 'AVyMjlK1HjR_PLDzRbB9', date: new Date('2017-06-09T13:06:10.000Z'), events: [] },
- { key: 'AVyM9n3cHjR_PLDzRciT', date: new Date('2017-06-09T11:12:27.000Z'), events: [] },
- { key: 'AVyMjlK1HjR_PLDzRbB9', date: new Date('2017-06-09T11:12:27.000Z'), events: [] },
- { key: 'AVxZtCpH7841nF4RNEMI', date: new Date('2017-05-18T14:13:07.000Z'), events: [] }
+ {
+ key: 'AVyMjlK1HjR_PLDzRbB9',
+ date: dates.parseDate('2017-06-09T13:06:10.000Z'),
+ events: []
+ },
+ {
+ key: 'AVyM9n3cHjR_PLDzRciT',
+ date: dates.parseDate('2017-06-09T11:12:27.000Z'),
+ events: []
+ },
+ {
+ key: 'AVyMjlK1HjR_PLDzRbB9',
+ date: dates.parseDate('2017-06-09T11:12:27.000Z'),
+ events: []
+ },
+ {
+ key: 'AVxZtCpH7841nF4RNEMI',
+ date: dates.parseDate('2017-05-18T14:13:07.000Z'),
+ events: []
+ }
],
{
category: '',
name: 'foo',
type: 'INT',
data: [
- { x: new Date('2017-04-27T08:21:32.000Z'), y: 2 },
- { x: new Date('2017-04-30T23:06:24.000Z'), y: 2 }
+ { x: dates.parseDate('2017-04-27T08:21:32.000Z'), y: 2 },
+ { x: dates.parseDate('2017-04-30T23:06:24.000Z'), y: 2 }
]
}
])
name: 'bar',
type: 'INT',
data: [
- { x: new Date('2017-04-27T08:21:32.000Z'), y: 2 },
- { x: new Date('2017-04-30T23:06:24.000Z'), y: 2 }
+ { x: dates.parseDate('2017-04-27T08:21:32.000Z'), y: 2 },
+ { x: dates.parseDate('2017-04-30T23:06:24.000Z'), y: 2 }
]
}
])
{
name: 'bar',
type: 'INT',
- data: [{ x: new Date('2017-04-27T08:21:32.000Z'), y: 2 }]
+ data: [{ x: dates.parseDate('2017-04-27T08:21:32.000Z'), y: 2 }]
}
])
).toBeFalsy();
import GraphHistory from './GraphHistory';
import { EVENT_TYPES, getSeriesMetricType, hasHistoryData, isCustomGraph } from '../utils';
import { translate } from '../../../helpers/l10n';
+import { parseDate } from '../../../helpers/dates';
/*:: import type { Analysis, MeasureHistory } from '../types'; */
/*:: import type { Serie } from '../../../components/charts/AdvancedTimeline'; */
return acc.concat({
className: event.category,
name: event.name,
- date: new Date(analysis.date)
+ date: parseDate(analysis.date)
});
}, []);
return sortBy(filteredEvents, 'date');
import ProjectActivityAnalysis from './ProjectActivityAnalysis';
import DateFormatter from '../../../components/intl/DateFormatter';
import { translate } from '../../../helpers/l10n';
+import { toShortNotSoISOString } from '../../../helpers/dates';
import {
activityQueryChanged,
getAnalysesByVersionByDay,
</div>}
<ul className="project-activity-days-list">
{days.map(day =>
- <li key={day} className="project-activity-day">
+ <li
+ key={day}
+ className="project-activity-day"
+ data-day={toShortNotSoISOString(Number(day))}>
<div className="project-activity-date">
<DateFormatter date={Number(day)} long={true} />
</div>
import ProjectActivityPageHeader from './ProjectActivityPageHeader';
import ProjectActivityAnalysesList from './ProjectActivityAnalysesList';
import ProjectActivityGraphs from './ProjectActivityGraphs';
+import { parseDate } from '../../../helpers/dates';
import { translate } from '../../../helpers/l10n';
import './projectActivity.css';
/*:: import type { Analysis, MeasureHistory, Metric, Query } from '../types'; */
<div className="project-activity-layout-page-main">
<ProjectActivityGraphs
analyses={analyses}
- leakPeriodDate={new Date(props.project.leakPeriodDate)}
+ leakPeriodDate={parseDate(props.project.leakPeriodDate)}
loading={props.graphLoading}
measuresHistory={measuresHistory}
metrics={props.metrics}
import { getMetrics } from '../../../api/metrics';
import * as api from '../../../api/projectActivity';
import * as actions from '../actions';
+import { parseDate } from '../../../helpers/dates';
import { getCustomGraph, getGraph } from '../../../helpers/storage';
import {
customMetricsChanged,
return api
.getProjectActivity({ ...parameters, ...additional })
.then(({ analyses, paging }) => ({
- analyses: analyses.map(analysis => ({ ...analysis, date: new Date(analysis.date) })),
+ analyses: analyses.map(analysis => ({ ...analysis, date: parseDate(analysis.date) })),
paging
}));
};
measures.map(measure => ({
metric: measure.metric,
history: measure.history.map(analysis => ({
- date: new Date(analysis.date),
+ date: parseDate(analysis.date),
value: analysis.value
}))
})),
*/
// @flow
import React from 'react';
-import { intlShape } from 'react-intl';
import DateInput from '../../../components/controls/DateInput';
-import { formatterOption } from '../../../components/intl/DateFormatter';
import { parseAsDate } from '../../../helpers/query';
import { translate } from '../../../helpers/l10n';
+import { toShortNotSoISOString } from '../../../helpers/dates';
/*:: import type { RawQuery } from '../../../helpers/query'; */
/*::
export default class ProjectActivityDateInput extends React.PureComponent {
/*:: props: Props; */
- static contextTypes = {
- intl: intlShape
- };
-
handleFromDateChange = (from /*: string */) => this.props.onChange({ from: parseAsDate(from) });
handleToDateChange = (to /*: string */) => this.props.onChange({ to: parseAsDate(to) });
handleResetClick = () => this.props.onChange({ from: null, to: null });
- formatDate = (date /*: ?Date */) =>
- date ? this.context.intl.formatDate(date, formatterOption) : undefined;
+ formatDate = (date /*: ?Date */) => (date ? toShortNotSoISOString(date) : undefined);
render() {
return (
import { shallow } from 'enzyme';
import GraphHistory from '../GraphHistory';
import { DEFAULT_GRAPH } from '../../utils';
+import { parseDate } from '../../../../helpers/dates';
const SERIES = [
{
name: 'bugs',
translatedName: 'metric.bugs.name',
data: [
- { x: new Date('2016-10-27T16:33:50+0200'), y: 5 },
- { x: new Date('2016-10-27T12:21:15+0200'), y: 16 },
- { x: new Date('2016-10-26T12:17:29+0200'), y: 12 }
+ { x: parseDate('2016-10-27T16:33:50+0200'), y: 5 },
+ { x: parseDate('2016-10-27T12:21:15+0200'), y: 16 },
+ { x: parseDate('2016-10-26T12:17:29+0200'), y: 12 }
]
}
];
import { shallow } from 'enzyme';
import GraphsHistory from '../GraphsHistory';
import { DEFAULT_GRAPH } from '../../utils';
+import { parseDate } from '../../../../helpers/dates';
const ANALYSES = [
{
key: 'A1',
- date: new Date('2016-10-27T16:33:50+0200'),
+ date: parseDate('2016-10-27T16:33:50+0200'),
events: [
{
key: 'E1',
},
{
key: 'A2',
- date: new Date('2016-10-27T12:21:15+0200'),
+ date: parseDate('2016-10-27T12:21:15+0200'),
events: []
},
{
key: 'A3',
- date: new Date('2016-10-26T12:17:29+0200'),
+ date: parseDate('2016-10-26T12:17:29+0200'),
events: [
{
key: 'E2',
name: 'bugs',
translatedName: 'metric.bugs.name',
data: [
- { x: new Date('2016-10-27T16:33:50+0200'), y: 5 },
- { x: new Date('2016-10-27T12:21:15+0200'), y: 16 },
- { x: new Date('2016-10-26T12:17:29+0200'), y: 12 }
+ { x: parseDate('2016-10-27T16:33:50+0200'), y: 5 },
+ { x: parseDate('2016-10-27T12:21:15+0200'), y: 16 },
+ { x: parseDate('2016-10-26T12:17:29+0200'), y: 12 }
]
}
];
{
name: 'bugs',
translatedName: 'metric.bugs.name',
- data: [{ x: new Date('2016-10-27T16:33:50+0200'), y: undefined }]
+ data: [{ x: parseDate('2016-10-27T16:33:50+0200'), y: undefined }]
}
]}
/>
import { shallow } from 'enzyme';
import GraphsTooltips from '../GraphsTooltips';
import { DEFAULT_GRAPH } from '../../utils';
+import { parseDate } from '../../../../helpers/dates';
const SERIES_ISSUES = [
{
graph: DEFAULT_GRAPH,
graphWidth: 500,
measuresHistory: [],
- selectedDate: new Date('2011-10-01T22:01:00.000Z'),
+ selectedDate: parseDate('2011-10-01T22:01:00.000Z'),
series: SERIES_ISSUES,
tooltipIdx: 0,
tooltipPos: 666
<GraphsTooltips
{...DEFAULT_PROPS}
graph="random"
- selectedDate={new Date('2011-10-25T10:27:41.000Z')}
+ selectedDate={parseDate('2011-10-25T10:27:41.000Z')}
tooltipIdx={1}
/>
)
import React from 'react';
import { shallow } from 'enzyme';
import ProjectActivityAnalysesList from '../ProjectActivityAnalysesList';
-import * as dates from '../../../../helpers/dates';
import { DEFAULT_GRAPH } from '../../utils';
+import * as dates from '../../../../helpers/dates';
const ANALYSES = [
{
key: 'A1',
- date: new Date('2016-10-27T16:33:50+0000'),
+ date: dates.parseDate('2016-10-27T16:33:50+0000'),
events: [
{
key: 'E1',
},
{
key: 'A2',
- date: new Date('2016-10-27T12:21:15+0000'),
+ date: dates.parseDate('2016-10-27T12:21:15+0000'),
events: []
},
{
key: 'A3',
- date: new Date('2016-10-26T12:17:29+0000'),
+ date: dates.parseDate('2016-10-26T12:17:29+0000'),
events: [
{
key: 'E2',
},
{
key: 'A4',
- date: new Date('2016-10-24T16:33:50+0000'),
+ date: dates.parseDate('2016-10-24T16:33:50+0000'),
events: [
{
key: 'E1',
return startDay;
});
+dates.toShortNotSoISOString = date => 'ISO.' + date;
+
it('should render correctly', () => {
expect(shallow(<ProjectActivityAnalysesList {...DEFAULT_PROPS} />)).toMatchSnapshot();
});
wrapper.setProps({
query: {
...DEFAULT_PROPS.query,
- from: new Date('2016-10-27T16:33:50+0000'),
- to: new Date('2016-10-27T16:33:50+0000')
+ from: dates.parseDate('2016-10-27T16:33:50+0000'),
+ to: dates.parseDate('2016-10-27T16:33:50+0000')
}
});
expect(wrapper).toMatchSnapshot();
import { shallow } from 'enzyme';
import ProjectActivityApp from '../ProjectActivityApp';
import { DEFAULT_GRAPH } from '../../utils';
+import { parseDate } from '../../../../helpers/dates';
const ANALYSES = [
{
key: 'A1',
- date: new Date('2016-10-27T16:33:50+0200'),
+ date: parseDate('2016-10-27T16:33:50+0200'),
events: [
{
key: 'E1',
},
{
key: 'A2',
- date: new Date('2016-10-27T12:21:15+0200'),
+ date: parseDate('2016-10-27T12:21:15+0200'),
events: []
},
{
key: 'A3',
- date: new Date('2016-10-26T12:17:29+0200'),
+ date: parseDate('2016-10-26T12:17:29+0200'),
events: [
{
key: 'E2',
{
metric: 'code_smells',
history: [
- { date: new Date('Fri Mar 04 2016 10:40:12 GMT+0100 (CET)'), value: '1749' },
- { date: new Date('Fri Mar 04 2016 18:40:16 GMT+0100 (CET)'), value: '2286' }
+ { date: parseDate('Fri Mar 04 2016 10:40:12 GMT+0100 (CET)'), value: '1749' },
+ { date: parseDate('Fri Mar 04 2016 18:40:16 GMT+0100 (CET)'), value: '2286' }
]
}
],
import React from 'react';
import { shallowWithIntl } from '../../../../helpers/testUtils';
import ProjectActivityDateInput from '../ProjectActivityDateInput';
+import { parseDate } from '../../../../helpers/dates';
it('should render correctly the date inputs', () => {
expect(
shallowWithIntl(
<ProjectActivityDateInput
- from={new Date('2016-10-27T12:21:15+0000')}
- to={new Date('2016-12-27T12:21:15+0000')}
+ from={parseDate('2016-10-27T12:21:15+0000')}
+ to={parseDate('2016-12-27T12:21:15+0000')}
onChange={() => {}}
/>
)
import { shallow } from 'enzyme';
import ProjectActivityGraphs from '../ProjectActivityGraphs';
import { DEFAULT_GRAPH } from '../../utils';
+import { parseDate } from '../../../../helpers/dates';
const ANALYSES = [
{
{
metric: 'code_smells',
history: [
- { date: new Date('2016-10-26T12:17:29+0200'), value: '2286' },
- { date: new Date('2016-10-27T12:21:15+0200'), value: '1749' },
- { date: new Date('2016-10-27T16:33:50+0200'), value: '500' }
+ { date: parseDate('2016-10-26T12:17:29+0200'), value: '2286' },
+ { date: parseDate('2016-10-27T12:21:15+0200'), value: '1749' },
+ { date: parseDate('2016-10-27T16:33:50+0200'), value: '500' }
]
}
],
import React from 'react';
import { shallow } from 'enzyme';
import ProjectActivityPageHeader from '../ProjectActivityPageHeader';
+import { parseDate } from '../../../../helpers/dates';
it('should render correctly the list of series', () => {
expect(
shallow(
<ProjectActivityPageHeader
category=""
- from={new Date('2016-10-27T12:21:15+0200')}
+ from={parseDate('2016-10-27T12:21:15+0200')}
project={{}}
updateQuery={() => {}}
/>
>
<li
className="project-activity-day"
+ data-day="ISO.1477267200000"
>
<div
className="project-activity-date"
>
<li
className="project-activity-day"
+ data-day="ISO.1477526400000"
>
<div
className="project-activity-date"
>
<li
className="project-activity-day"
+ data-day="ISO.1477526400000"
>
<div
className="project-activity-date"
>
<li
className="project-activity-day"
+ data-day="ISO.1477440000000"
>
<div
className="project-activity-date"
</li>
<li
className="project-activity-day"
+ data-day="ISO.1477267200000"
>
<div
className="project-activity-date"
name="from"
onChange={[Function]}
placeholder="from"
- value="10/27/2016"
+ value="2016-10-27"
/>
—
<DateInput
name="to"
onChange={[Function]}
placeholder="to"
- value="12/27/2016"
+ value="2016-12-27"
/>
<button
className="spacer-left"
serializeDate,
serializeString
} from '../../helpers/query';
-import { startOfDay } from '../../helpers/dates';
+import { parseDate, startOfDay } from '../../helpers/dates';
import { getLocalizedMetricName, translate } from '../../helpers/l10n';
/*:: import type { Analysis, MeasureHistory, Metric, Query } from './types'; */
/*:: import type { RawQuery } from '../../helpers/query'; */
acc.push(currentVersion);
}
- const day = startOfDay(new Date(analysis.date)).getTime().toString();
+ const day = startOfDay(parseDate(analysis.date)).getTime().toString();
let matchFilters = true;
if (query.category || query.from || query.to) {
import React from 'react';
import classNames from 'classnames';
import { Link } from 'react-router';
-import { FormattedRelative } from 'react-intl';
+import DateFromNow from '../../../components/intl/DateFromNow';
import DateTimeFormatter from '../../../components/intl/DateTimeFormatter.tsx';
import ProjectCardQualityGate from './ProjectCardQualityGate';
import ProjectCardLeakMeasures from './ProjectCardLeakMeasures';
hasLeakPeriodStart &&
<div className="project-card-dates note text-right pull-right">
{hasLeakPeriodStart &&
- <FormattedRelative value={project.leakPeriodDate}>
+ <DateFromNow date={project.leakPeriodDate}>
{fromNow =>
<span className="project-card-leak-date pull-right">
{translateWithParameters('projects.leak_period_x', fromNow)}
</span>}
- </FormattedRelative>}
+ </DateFromNow>}
{isProjectAnalyzed &&
<DateTimeFormatter date={project.analysisDate}>
{formattedDate =>
it('should display analysis date and leak start date', () => {
const card = shallow(<ProjectCardLeak type="leak" measures={MEASURES} project={PROJECT} />);
expect(card.find('.project-card-dates').exists()).toBeTruthy();
- expect(card.find('.project-card-dates').find('FormattedRelative').getNodes()).toHaveLength(1);
- expect(card.find('.project-card-dates').find('DateTimeFormatter').getNodes()).toHaveLength(1);
+ expect(card.find('.project-card-dates').find('DateFromNow')).toHaveLength(1);
+ expect(card.find('.project-card-dates').find('DateTimeFormatter')).toHaveLength(1);
});
it('should not display analysis date or leak start date', () => {
<div
className="project-card-dates note text-right pull-right"
>
- <FormattedRelative
- updateInterval={10000}
- value="2016-12-01"
+ <DateFromNow
+ date="2016-12-01"
/>
<DateTimeFormatter
date="2017-01-01"
import DateTimeFormatter from '../../../components/intl/DateTimeFormatter';
import { translate } from '../../../helpers/l10n';
import { getRulesUrl } from '../../../helpers/urls';
-import { differenceInSeconds } from '../../../helpers/dates';
+import { differenceInSeconds, parseDate } from '../../../helpers/dates';
import { ProfileChangelogEvent } from '../types';
interface Props {
const rows = props.events.map((event, index) => {
const prev = index > 0 ? props.events[index - 1] : null;
const isSameDate =
- prev != null && differenceInSeconds(new Date(prev.date), new Date(event.date)) < 10;
+ prev != null && differenceInSeconds(parseDate(prev.date), parseDate(event.date)) < 10;
const isBulkChange =
prev != null &&
isSameDate &&
*/
import * as React from 'react';
import DateInput from '../../../components/controls/DateInput';
+import { toShortNotSoISOString } from '../../../helpers/dates';
import { translate } from '../../../helpers/l10n';
interface Props {
this.props.onReset();
}
+ formatDate = (date?: string) => (date ? toShortNotSoISOString(date) : undefined);
+
render() {
return (
<div className="display-inline-block" id="quality-profile-changelog-form">
<DateInput
name="since"
- value={this.props.fromDate}
+ value={this.formatDate(this.props.fromDate)}
placeholder="From"
onChange={this.props.onFromDateChange}
/>
{' — '}
<DateInput
name="to"
- value={this.props.toDate}
+ value={this.formatDate(this.props.toDate)}
placeholder="To"
onChange={this.props.onToDateChange}
/>
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import { FormattedRelative } from 'react-intl';
+import DateFromNow from '../../../components/intl/DateFromNow';
import DateTimeFormatter from '../../../components/intl/DateTimeFormatter';
import Tooltip from '../../../components/controls/Tooltip';
import { translate } from '../../../helpers/l10n';
return date
? <Tooltip overlay={<DateTimeFormatter date={date} />}>
<span>
- <FormattedRelative value={date} />
+ <DateFromNow date={date} />
</span>
</Tooltip>
: <span>
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { sortBy } from 'lodash';
-import { differenceInYears, isValidDate } from '../../helpers/dates';
+import { differenceInYears, isValidDate, parseDate } from '../../helpers/dates';
import { Profile } from './types';
export function sortProfiles(profiles: Profile[]) {
export function isStagnant(profile: Profile): boolean {
if (profile.userUpdatedAt) {
- const updateDate = new Date(profile.userUpdatedAt);
+ const updateDate = parseDate(profile.userUpdatedAt);
if (isValidDate(updateDate)) {
return differenceInYears(new Date(), updateDate) >= 1;
}
*/
import * as React from 'react';
import { DateSource, FormattedDate } from 'react-intl';
+import { parseDate } from '../../helpers/dates';
interface Props {
children?: (formattedDate: string) => React.ReactNode;
return (
<FormattedDate
children={children}
- value={date}
+ value={parseDate(date)}
{...(long ? longFormatterOption : formatterOption)}
/>
);
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { DateSource, FormattedRelative } from 'react-intl';
+import { parseDate } from '../../helpers/dates';
+
+interface Props {
+ children?: (formattedDate: string) => React.ReactNode;
+ date: DateSource;
+}
+
+export default function DateFromNow({ children, date }: Props) {
+ return <FormattedRelative children={children} value={parseDate(date)} />;
+}
*/
import * as React from 'react';
import { DateSource, FormattedDate } from 'react-intl';
+import { parseDate } from '../../helpers/dates';
interface Props {
children?: (formattedDate: string) => React.ReactNode;
};
export default function DateTimeFormatter({ children, date }: Props) {
- return <FormattedDate children={children} value={date} {...formatterOption} />;
+ return <FormattedDate children={children} value={parseDate(date)} {...formatterOption} />;
}
import DateFormatter from './DateFormatter';
import DateTimeFormatter from './DateTimeFormatter';
import Tooltip from '../controls/Tooltip';
+import { parseDate } from '../../helpers/dates';
interface Props {
className?: string;
}
export default function DateTooltipFormatter({ className, date, placement }: Props) {
+ const parsedDate = parseDate(date);
return (
- <DateFormatter date={date} long={true}>
+ <DateFormatter date={parsedDate} long={true}>
{formattedDate =>
<Tooltip
- overlay={<DateTimeFormatter date={date} />}
+ overlay={<DateTimeFormatter date={parsedDate} />}
placement={placement}
mouseEnterDelay={0.5}>
- <time className={className} dateTime={new Date(date as Date).toISOString()}>
+ <time className={className} dateTime={parsedDate.toISOString()}>
{formattedDate}
</time>
</Tooltip>}
*/
import * as React from 'react';
import { DateSource, FormattedTime } from 'react-intl';
+import { parseDate } from '../../helpers/dates';
interface Props {
children?: (formattedDate: string) => React.ReactNode;
return (
<FormattedTime
children={children}
- value={date}
+ value={parseDate(date)}
{...(long ? longFormatterOption : formatterOption)}
/>
);
import * as React from 'react';
import TimeFormatter from './TimeFormatter';
import Tooltip from '../controls/Tooltip';
+import { parseDate } from '../../helpers/dates';
interface Props {
className?: string;
}
export default function TimeTooltipFormatter({ className, date, placement }: Props) {
+ const parsedDate = parseDate(date);
return (
- <TimeFormatter date={date} long={false}>
+ <TimeFormatter date={parsedDate} long={false}>
{formattedTime =>
<Tooltip
- overlay={<TimeFormatter date={date} long={true} />}
+ overlay={<TimeFormatter date={parsedDate} long={true} />}
placement={placement}
mouseEnterDelay={0.5}>
- <time className={className} dateTime={new Date(date as Date).toISOString()}>
+ <time className={className} dateTime={parsedDate.toISOString()}>
{formattedTime}
</time>
</Tooltip>}
*/
// @flow
import React from 'react';
-import { FormattedRelative } from 'react-intl';
import BubblePopupHelper from '../../../components/common/BubblePopupHelper';
import ChangelogPopup from '../popups/ChangelogPopup';
+import DateFromNow from '../../../components/intl/DateFromNow';
import DateTimeFormatter from '../../../components/intl/DateTimeFormatter';
import Tooltip from '../../../components/controls/Tooltip';
/*:: import type { Issue } from '../types'; */
className="button-link issue-action issue-action-with-options js-issue-show-changelog"
onClick={this.handleClick}>
<span className="issue-meta-label">
- <FormattedRelative value={this.props.creationDate} />
+ <DateFromNow date={this.props.creationDate} />
</span>
<i className="icon-dropdown little-spacer-left" />
</button>
*/
// @flow
import React from 'react';
-import { FormattedRelative } from 'react-intl';
import Avatar from '../../../components/ui/Avatar';
import BubblePopupHelper from '../../../components/common/BubblePopupHelper';
import CommentDeletePopup from '../popups/CommentDeletePopup';
import CommentPopup from '../popups/CommentPopup';
+import DateFromNow from '../../../components/intl/DateFromNow';
/*:: import type { IssueComment } from '../types'; */
/*::
tabIndex={0}
/>
<div className="issue-comment-age">
- <FormattedRelative value={comment.createdAt} />
+ <DateFromNow date={comment.createdAt} />
</div>
<div className="issue-comment-actions">
{comment.updatable &&
<span
className="issue-meta-label"
>
- <FormattedRelative
- updateInterval={10000}
- value="2017-03-01T09:36:01+0100"
+ <DateFromNow
+ date="2017-03-01T09:36:01+0100"
/>
</span>
<i
<span
className="issue-meta-label"
>
- <FormattedRelative
- updateInterval={10000}
- value="2017-03-01T09:36:01+0100"
+ <DateFromNow
+ date="2017-03-01T09:36:01+0100"
/>
</span>
<i
<div
className="issue-comment-age"
>
- <FormattedRelative
- updateInterval={10000}
- value="2017-03-01T09:36:01+0100"
+ <DateFromNow
+ date="2017-03-01T09:36:01+0100"
/>
</div>
<div
<div
className="issue-comment-age"
>
- <FormattedRelative
- updateInterval={10000}
- value="2017-03-01T09:36:01+0100"
+ <DateFromNow
+ date="2017-03-01T09:36:01+0100"
/>
</div>
<div
<div
className="issue-comment-age"
>
- <FormattedRelative
- updateInterval={10000}
- value="2017-03-01T09:36:01+0100"
+ <DateFromNow
+ date="2017-03-01T09:36:01+0100"
/>
</div>
<div
import { max } from 'd3-array';
import { select } from 'd3-selection';
import { scaleLinear, scaleBand } from 'd3-scale';
-import { isSameDay, toNotSoISOString } from '../../helpers/dates';
+import { isSameDay, parseDate, toNotSoISOString } from '../../helpers/dates';
function trans(left, top) {
return `translate(${left}, ${top})`;
const options = { ...defaults(), ...$(this).data() };
Object.assign(options, {
width: options.width || $(this).width(),
- endDate: options.endDate ? new Date(options.endDate) : null
+ endDate: options.endDate ? parseDate(options.endDate) : null
});
const container = select(this);
.attr('width', barWidth)
.attr('height', d => Math.floor(yScale(d.count)))
.style('cursor', 'pointer')
- .attr('data-period-start', d => toNotSoISOString(new Date(d.val)))
+ .attr('data-period-start', d => toNotSoISOString(d.val))
.attr('data-period-end', (d, i) => {
- const ending = i < data.length - 1 ? new Date(data[i + 1].val) : options.endDate;
+ const ending = i < data.length - 1 ? data[i + 1].val : options.endDate;
if (ending) {
return toNotSoISOString(ending);
} else {
}
})
.attr('title', (d, i) => {
- const beginning = new Date(d.val);
+ const beginning = parseDate(d.val);
let ending = options.endDate;
if (i < data.length - 1) {
- ending = new Date(data[i + 1].val);
+ ending = parseDate(data[i + 1].val);
ending.setDate(ending.getDate() - 1);
}
if (ending) {
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as dates from '../dates';
+import { parseDate } from '../../helpers/dates';
-const recentDate = new Date('2017-08-16T12:00:00.000Z');
-const recentDate2 = new Date('2016-12-16T12:00:00.000Z');
-const oldDate = new Date('2014-01-12T12:00:00.000Z');
+const recentDate = parseDate('2017-08-16T12:00:00.000Z');
+const recentDate2 = parseDate('2016-12-16T12:00:00.000Z');
+const oldDate = parseDate('2014-01-12T12:00:00.000Z');
it('toShortNotSoISOString', () => {
expect(dates.toShortNotSoISOString(recentDate)).toBe('2017-08-16');
it('isValidDate', () => {
expect(dates.isValidDate(recentDate)).toBeTruthy();
expect(dates.isValidDate(new Date())).toBeTruthy();
- expect(dates.isValidDate(new Date('foo'))).toBeFalsy();
+ expect(dates.isValidDate(parseDate('foo'))).toBeFalsy();
});
it('isSameDay', () => {
- expect(dates.isSameDay(recentDate, new Date(recentDate))).toBeTruthy();
+ expect(dates.isSameDay(recentDate, parseDate(recentDate))).toBeTruthy();
expect(dates.isSameDay(recentDate, recentDate2)).toBeFalsy();
expect(dates.isSameDay(recentDate, oldDate)).toBeFalsy();
- expect(dates.isSameDay(recentDate, new Date('2016-08-16T12:00:00.000Z'))).toBeFalsy();
+ expect(dates.isSameDay(recentDate, parseDate('2016-08-16T12:00:00.000Z'))).toBeFalsy();
});
it('differenceInYears', () => {
});
it('differenceInDays', () => {
- expect(dates.differenceInDays(recentDate, new Date('2017-08-01T12:00:00.000Z'))).toBe(15);
- expect(dates.differenceInDays(recentDate, new Date('2017-08-15T23:00:00.000Z'))).toBe(0);
+ expect(dates.differenceInDays(recentDate, parseDate('2017-08-01T12:00:00.000Z'))).toBe(15);
+ expect(dates.differenceInDays(recentDate, parseDate('2017-08-15T23:00:00.000Z'))).toBe(0);
expect(dates.differenceInDays(recentDate, recentDate2)).toBe(243);
expect(dates.differenceInDays(recentDate, oldDate)).toBe(1312);
});
it('differenceInSeconds', () => {
- expect(dates.differenceInSeconds(recentDate, new Date('2017-08-16T10:00:00.000Z'))).toBe(7200);
- expect(dates.differenceInSeconds(recentDate, new Date('2017-08-16T12:00:00.500Z'))).toBe(0);
+ expect(dates.differenceInSeconds(recentDate, parseDate('2017-08-16T10:00:00.000Z'))).toBe(7200);
+ expect(dates.differenceInSeconds(recentDate, parseDate('2017-08-16T12:00:00.500Z'))).toBe(0);
expect(dates.differenceInSeconds(recentDate, oldDate)).toBe(113356800);
});
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as query from '../query';
+import { parseDate } from '../dates';
describe('queriesEqual', () => {
it('should correctly test equality of two queries', () => {
});
describe('serializeDate', () => {
- const date = new Date('2016-06-20T13:09:48.256Z');
+ const date = parseDate('2016-06-20T13:09:48.256Z');
it('should serialize string correctly', () => {
expect(query.serializeDate(date)).toBe('2016-06-20T13:09:48+0000');
expect(query.serializeDate('')).toBeUndefined();
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-
-const MILLISECONDS_IN_MINUTE = 60 * 1000;
-const MILLISECONDS_IN_DAY = MILLISECONDS_IN_MINUTE * 60 * 24;
+import {
+ differenceInDays as _differenceInDays,
+ differenceInSeconds as _differenceInSeconds,
+ differenceInYears as _differenceInYears,
+ isSameDay as _isSameDay,
+ parse,
+ startOfDay as _startOfDay
+} from 'date-fns';
function pad(number: number) {
if (number < 10) {
return number;
}
-function compareDateAsc(dateLeft: Date, dateRight: Date): number {
- var timeLeft = dateLeft.getTime();
- var timeRight = dateRight.getTime();
+type ParsableDate = string | number | Date;
- if (timeLeft < timeRight) {
- return -1;
- } else if (timeLeft > timeRight) {
- return 1;
- } else {
- return 0;
- }
+export function parseDate(rawDate: ParsableDate): Date {
+ return parse(rawDate);
}
-export function toShortNotSoISOString(date: Date): string {
+export function toShortNotSoISOString(rawDate: ParsableDate): string {
+ const date = parseDate(rawDate);
return date.getFullYear() + '-' + pad(date.getMonth() + 1) + '-' + pad(date.getDate());
}
-export function toNotSoISOString(date: Date): string {
+export function toNotSoISOString(rawDate: ParsableDate): string {
+ const date = parseDate(rawDate);
return date.toISOString().replace(/\..+Z$/, '+0000');
}
export function startOfDay(date: Date): Date {
- const startDay = new Date(date);
- startDay.setHours(0, 0, 0, 0);
- return startDay;
+ return _startOfDay(date);
}
export function isValidDate(date: Date): boolean {
}
export function isSameDay(dateLeft: Date, dateRight: Date): boolean {
- const startDateLeft = startOfDay(dateLeft);
- const startDateRight = startOfDay(dateRight);
- return startDateLeft.getTime() === startDateRight.getTime();
+ return _isSameDay(dateLeft, dateRight);
}
export function differenceInYears(dateLeft: Date, dateRight: Date): number {
- const sign = compareDateAsc(dateLeft, dateRight);
- const diff = Math.abs(dateLeft.getFullYear() - dateRight.getFullYear());
- const tmpLeftDate = new Date(dateLeft);
- tmpLeftDate.setFullYear(dateLeft.getFullYear() - sign * diff);
- const isLastYearNotFull = compareDateAsc(tmpLeftDate, dateRight) === -sign;
- return sign * (diff - (isLastYearNotFull ? 1 : 0));
+ return _differenceInYears(dateLeft, dateRight);
}
export function differenceInDays(dateLeft: Date, dateRight: Date): number {
- const startDateLeft = startOfDay(dateLeft);
- const startDateRight = startOfDay(dateRight);
- const timestampLeft =
- startDateLeft.getTime() - startDateLeft.getTimezoneOffset() * MILLISECONDS_IN_MINUTE;
- const timestampRight =
- startDateRight.getTime() - startDateRight.getTimezoneOffset() * MILLISECONDS_IN_MINUTE;
- return Math.round((timestampLeft - timestampRight) / MILLISECONDS_IN_DAY);
+ return _differenceInDays(dateLeft, dateRight);
}
export function differenceInSeconds(dateLeft: Date, dateRight: Date): number {
- const diff = (dateLeft.getTime() - dateRight.getTime()) / 1000;
- return diff > 0 ? Math.floor(diff) : Math.ceil(diff);
+ return _differenceInSeconds(dateLeft, dateRight);
}
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+const { parseDate } = require('../../helpers/dates');
+const { DEFAULT_LANGUAGE } = require('../../helpers/l10n');
+
module.exports = function(date) {
- return new Intl.DateTimeFormat(localStorage.getItem('l10n.locale') || 'en', {
+ return new Intl.DateTimeFormat(localStorage.getItem('l10n.locale') || DEFAULT_LANGUAGE, {
year: 'numeric',
month: 'long',
day: 'numeric'
- }).format(new Date(date));
+ }).format(parseDate(date));
};
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+const { parseDate } = require('../../helpers/dates');
+const { DEFAULT_LANGUAGE } = require('../../helpers/l10n');
+
module.exports = function(date) {
- return new Intl.DateTimeFormat(localStorage.getItem('l10n.locale') || 'en', {
+ return new Intl.DateTimeFormat(localStorage.getItem('l10n.locale') || DEFAULT_LANGUAGE, {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: 'numeric',
minute: 'numeric'
- }).format(new Date(date));
+ }).format(parseDate(date));
};
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
const IntlRelativeFormat = require('intl-relativeformat');
+const { DEFAULT_LANGUAGE } = require('../../helpers/l10n');
module.exports = function(date) {
- return new IntlRelativeFormat(localStorage.getItem('l10n.locale') || 'en').format(date);
+ return new IntlRelativeFormat(localStorage.getItem('l10n.locale') || DEFAULT_LANGUAGE).format(
+ date
+ );
};
// do nothing
}
resetBundle(messages);
- return effectiveLocale || browserLocale || DEFAULT_LANGUAGE;
+ return effectiveLocale;
},
({ response }) => {
if (response && response.status === 304) {
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { translate, translateWithParameters } from './l10n';
+import { parseDate } from './dates';
export function getPeriod(periods, index) {
if (!Array.isArray(periods)) {
return null;
}
- return new Date(period.date);
+ return parseDate(period.date);
}
export function getLeakPeriodLabel(periods) {
*/
// @flow
import { isNil, omitBy } from 'lodash';
-import { isValidDate, toNotSoISOString } from './dates';
+import { isValidDate, parseDate, toNotSoISOString } from './dates';
/*::
export type RawQuery = { [string]: any };
export function parseAsDate(value /*: ?string */) /*: Date | void */ {
if (value) {
- const date = new Date(value);
+ const date = parseDate(value);
if (isValidDate(date)) {
return date;
}
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { shallow, ShallowWrapper } from 'enzyme';
+import { shallow, ShallowRendererProps, ShallowWrapper } from 'enzyme';
import { IntlProvider } from 'react-intl';
export const mockEvent = {
});
}
+// Create the IntlProvider to retrieve context for wrapping around.
const intlProvider = new IntlProvider({ locale: 'en' }, {});
const { intl } = intlProvider.getChildContext();
-export function shallowWithIntl(node, options = {}) {
+export function shallowWithIntl(node: React.ReactElement<any>, options: ShallowRendererProps = {}) {
return shallow(node, { ...options, context: { intl, ...options.context } });
}
version "2.2.0"
resolved "https://registry.yarnpkg.com/@types/classnames/-/classnames-2.2.0.tgz#f2312039e780bdf89d7d4102a26ec11de5ec58aa"
+"@types/date-fns@2.6.0":
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/@types/date-fns/-/date-fns-2.6.0.tgz#b062ca46562002909be0c63a6467ed173136acc1"
+ dependencies:
+ date-fns "*"
+
"@types/enzyme@2.8.6":
version "2.8.6"
resolved "https://registry.yarnpkg.com/@types/enzyme/-/enzyme-2.8.6.tgz#b508da0860b4fcda2ab851d600e5bfaf695775dd"
dependencies:
assert-plus "^1.0.0"
+date-fns@*, date-fns@1.28.5:
+ version "1.28.5"
+ resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.28.5.tgz#257cfc45d322df45ef5658665967ee841cd73faf"
+
date-now@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"