From: Grégoire Aubert Date: Tue, 22 Aug 2017 15:07:33 +0000 (+0200) Subject: Use date parsing function from date-fns instead of new Date() X-Git-Tag: 6.6-RC1~538 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=db6ad16520b210083bd9026a3648bb5211c10c28;p=sonarqube.git Use date parsing function from date-fns instead of new Date() --- diff --git a/server/sonar-web/package.json b/server/sonar-web/package.json index d95aba437bc..679b0c8538a 100644 --- a/server/sonar-web/package.json +++ b/server/sonar-web/package.json @@ -17,6 +17,7 @@ "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", @@ -44,6 +45,7 @@ }, "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", @@ -129,16 +131,8 @@ ], "jest": { "coverageDirectory": "/target/coverage", - "coveragePathIgnorePatterns": [ - "/node_modules", - "/tests" - ], - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "json" - ], + "coveragePathIgnorePatterns": ["/node_modules", "/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)$": "/config/jest/FileStub.js", "^.+\\.css$": "/config/jest/CSSStub.js" @@ -147,9 +141,7 @@ "/config/polyfills.js", "/config/jest/SetupTestEnvironment.js" ], - "snapshotSerializers": [ - "enzyme-to-json/serializer" - ], + "snapshotSerializers": ["enzyme-to-json/serializer"], "testPathIgnorePatterns": [ "/node_modules", "/src/main/webapp", diff --git a/server/sonar-web/src/main/js/app/components/LocalizationContainer.tsx b/server/sonar-web/src/main/js/app/components/LocalizationContainer.tsx index 89e68eee611..4391b8d8379 100644 --- a/server/sonar-web/src/main/js/app/components/LocalizationContainer.tsx +++ b/server/sonar-web/src/main/js/app/components/LocalizationContainer.tsx @@ -46,12 +46,14 @@ export default class LocalizationContainer extends React.PureComponent { - 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[]) => { diff --git a/server/sonar-web/src/main/js/apps/account/projects/ProjectCard.tsx b/server/sonar-web/src/main/js/apps/account/projects/ProjectCard.tsx index cd5f6d39fea..5ce7e174de7 100644 --- a/server/sonar-web/src/main/js/apps/account/projects/ProjectCard.tsx +++ b/server/sonar-web/src/main/js/apps/account/projects/ProjectCard.tsx @@ -19,9 +19,9 @@ */ 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'; @@ -43,12 +43,12 @@ export default function ProjectCard({ project }: Props) { overlay={} placement="right">
- - {(relativeDate: string) => + + {(fromNow: string) => - {translateWithParameters('my_account.projects.analyzed_x', relativeDate)} + {translateWithParameters('my_account.projects.analyzed_x', fromNow)} } - +
:
diff --git a/server/sonar-web/src/main/js/apps/account/projects/__tests__/ProjectCard-test.js b/server/sonar-web/src/main/js/apps/account/projects/__tests__/ProjectCard-test.js index aa597b1ce8c..d7a80d12599 100644 --- a/server/sonar-web/src/main/js/apps/account/projects/__tests__/ProjectCard-test.js +++ b/server/sonar-web/src/main/js/apps/account/projects/__tests__/ProjectCard-test.js @@ -49,7 +49,7 @@ it('should not render optional fields', () => { it('should render analysis date', () => { const project = { ...BASE, lastAnalysisDate: '2016-05-17' }; const output = shallow(); - expect(output.find('.account-project-analysis FormattedRelative')).toHaveLength(1); + expect(output.find('.account-project-analysis DateFromNow')).toHaveLength(1); }); it('should not render analysis date', () => { diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/DateFilter.js b/server/sonar-web/src/main/js/apps/background-tasks/components/DateFilter.js index 8fe7a69b028..de5c77abebd 100644 --- a/server/sonar-web/src/main/js/apps/background-tasks/components/DateFilter.js +++ b/server/sonar-web/src/main/js/apps/background-tasks/components/DateFilter.js @@ -19,7 +19,7 @@ */ 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() { @@ -45,8 +45,8 @@ export default class DateFilter extends Component { 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); diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/TaskDate.tsx b/server/sonar-web/src/main/js/apps/background-tasks/components/TaskDate.tsx index d03a3e62289..525d8bbc420 100644 --- a/server/sonar-web/src/main/js/apps/background-tasks/components/TaskDate.tsx +++ b/server/sonar-web/src/main/js/apps/background-tasks/components/TaskDate.tsx @@ -19,7 +19,7 @@ */ 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; @@ -27,8 +27,8 @@ interface Props { } 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) diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/TaskDay.tsx b/server/sonar-web/src/main/js/apps/background-tasks/components/TaskDay.tsx index ed6a79cef9c..c2d8911358b 100644 --- a/server/sonar-web/src/main/js/apps/background-tasks/components/TaskDay.tsx +++ b/server/sonar-web/src/main/js/apps/background-tasks/components/TaskDay.tsx @@ -19,7 +19,7 @@ */ 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 { @@ -29,7 +29,7 @@ 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 ( diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/LeakPeriodLegend.js b/server/sonar-web/src/main/js/apps/component-measures/components/LeakPeriodLegend.js index e8b41e80e36..8ca27ea3eb9 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/components/LeakPeriodLegend.js +++ b/server/sonar-web/src/main/js/apps/component-measures/components/LeakPeriodLegend.js @@ -20,7 +20,7 @@ // @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'; @@ -56,7 +56,7 @@ export default function LeakPeriodLegend({ className, component, period } /*: Pr const date = getPeriodDate(period); const tooltip = (
- + {', '}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureContent.js b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureContent.js index cf03a171d55..c5dedfe59b6 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureContent.js +++ b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureContent.js @@ -34,6 +34,7 @@ import { complementary } from '../config/complementary'; 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'; */ @@ -216,13 +217,13 @@ export default class MeasureContent extends React.PureComponent { 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; diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/LeakPeriodLegend-test.js.snap b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/LeakPeriodLegend-test.js.snap index b82411aaf92..6040a382d6c 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/LeakPeriodLegend-test.js.snap +++ b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/LeakPeriodLegend-test.js.snap @@ -4,9 +4,8 @@ exports[`should render correctly 1`] = ` - , { - 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); } @@ -186,7 +187,7 @@ export default class CreationDateFacet extends React.PureComponent {
- +
); @@ -194,20 +195,19 @@ export default class CreationDateFacet extends React.PureComponent { renderPeriodSelectors() { const { createdAfter, createdBefore } = this.props; - const { formatDate } = this.context.intl; return (
); diff --git a/server/sonar-web/src/main/js/apps/overview/components/LeakPeriodLegend.js b/server/sonar-web/src/main/js/apps/overview/components/LeakPeriodLegend.js index f932aeb8c8e..89181eecc93 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/LeakPeriodLegend.js +++ b/server/sonar-web/src/main/js/apps/overview/components/LeakPeriodLegend.js @@ -19,7 +19,7 @@ */ // @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'; @@ -101,7 +101,7 @@ export default function LeakPeriodLegend({ period } /*: { period: Period } */) {
{translateWithParameters('overview.leak_period_x', leakPeriodLabel)}
- + {fromNow => {translateWithParameters( @@ -109,7 +109,7 @@ export default function LeakPeriodLegend({ period } /*: { period: Period } */) { fromNow )} } - +
); diff --git a/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.js b/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.js index 800a62d4ccd..ac67fbae194 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.js +++ b/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.js @@ -30,6 +30,7 @@ import Meta from '../meta/Meta'; 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'; @@ -123,7 +124,7 @@ export default class OverviewApp extends React.PureComponent { 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; diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/LeakPeriodLegend-test.js b/server/sonar-web/src/main/js/apps/overview/components/__tests__/LeakPeriodLegend-test.js index b0179494ae0..39a24fcadb1 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/LeakPeriodLegend-test.js +++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/LeakPeriodLegend-test.js @@ -37,9 +37,7 @@ describe('check note', () => { mode: 'date', parameter: '2013-01-01' }; - expect( - shallow().find('FormattedRelative') - ).toMatchSnapshot(); + expect(shallow().find('DateFromNow')).toMatchSnapshot(); }); it('version', () => { @@ -48,9 +46,7 @@ describe('check note', () => { mode: 'version', parameter: '0.1' }; - expect( - shallow().find('FormattedRelative') - ).toMatchSnapshot(); + expect(shallow().find('DateFromNow')).toMatchSnapshot(); }); it('previous_version', () => { @@ -58,7 +54,7 @@ describe('check note', () => { date: '2013-09-22T00:00:00+0200', mode: 'previous_version' }; - expect(shallow().find('FormattedRelative')).toHaveLength(1); + expect(shallow().find('DateFromNow')).toHaveLength(1); }); it('previous_analysis', () => { @@ -66,6 +62,6 @@ describe('check note', () => { date: '2013-09-22T00:00:00+0200', mode: 'previous_analysis' }; - expect(shallow().find('FormattedRelative')).toHaveLength(1); + expect(shallow().find('DateFromNow')).toHaveLength(1); }); }); diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/Timeline-test.js b/server/sonar-web/src/main/js/apps/overview/components/__tests__/Timeline-test.js index 186f707fc34..c07d56a869e 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/Timeline-test.js +++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/Timeline-test.js @@ -20,13 +20,14 @@ 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', () => { @@ -38,7 +39,7 @@ it('should render correctly with a "before" 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(); expect(wrapper.find('LineChart').props().domain).toEqual([0, 360]); diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/LeakPeriodLegend-test.js.snap b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/LeakPeriodLegend-test.js.snap index 44caddb1324..b38a2d79967 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/LeakPeriodLegend-test.js.snap +++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/LeakPeriodLegend-test.js.snap @@ -9,15 +9,13 @@ exports[`check note 10 days 1`] = ` `; exports[`check note date 1`] = ` - `; exports[`check note version 1`] = ` - `; diff --git a/server/sonar-web/src/main/js/apps/overview/events/__tests__/PreviewGraphTooltips-test.js b/server/sonar-web/src/main/js/apps/overview/events/__tests__/PreviewGraphTooltips-test.js index 2953cb69037..1b8d08d2ef1 100644 --- a/server/sonar-web/src/main/js/apps/overview/events/__tests__/PreviewGraphTooltips-test.js +++ b/server/sonar-web/src/main/js/apps/overview/events/__tests__/PreviewGraphTooltips-test.js @@ -21,6 +21,7 @@ import React from 'react'; import { shallow } from 'enzyme'; import PreviewGraphTooltips from '../PreviewGraphTooltips'; import { DEFAULT_GRAPH } from '../../../projectActivity/utils'; +import { parseDate } from '../../../../helpers/dates'; const SERIES_ISSUES = [ { @@ -78,7 +79,7 @@ const DEFAULT_PROPS = { 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 @@ -90,7 +91,7 @@ it('should render correctly', () => { ) diff --git a/server/sonar-web/src/main/js/apps/overview/main/CodeSmells.js b/server/sonar-web/src/main/js/apps/overview/main/CodeSmells.js index 2eab616e195..26a751d6219 100644 --- a/server/sonar-web/src/main/js/apps/overview/main/CodeSmells.js +++ b/server/sonar-web/src/main/js/apps/overview/main/CodeSmells.js @@ -19,8 +19,8 @@ */ 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'; @@ -66,12 +66,12 @@ class CodeSmells extends React.PureComponent { return null; } return ( - + {fromNow => {translateWithParameters('overview.started_x', fromNow)} } - + ); } diff --git a/server/sonar-web/src/main/js/apps/projectActivity/__tests__/actions-test.js b/server/sonar-web/src/main/js/apps/projectActivity/__tests__/actions-test.js index 6914d110f1e..4e8432ce9d9 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/__tests__/actions-test.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/__tests__/actions-test.js @@ -19,11 +19,12 @@ */ // @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', @@ -34,12 +35,12 @@ const ANALYSES = [ }, { 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', diff --git a/server/sonar-web/src/main/js/apps/projectActivity/__tests__/utils-test.js b/server/sonar-web/src/main/js/apps/projectActivity/__tests__/utils-test.js index 455c679d2d7..d60213ed43e 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/__tests__/utils-test.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/__tests__/utils-test.js @@ -24,18 +24,18 @@ import * as dates from '../../../helpers/dates'; 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', @@ -44,10 +44,10 @@ const ANALYSES = [ } ] }, - { 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' }, { @@ -57,22 +57,22 @@ const ANALYSES = [ } ] }, - { 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' } ] } ]; @@ -84,7 +84,7 @@ const METRICS = [ 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, @@ -112,7 +112,6 @@ describe('getAnalysesByVersionByDay', () => { startDay.setUTCHours(0, 0, 0, 0); return startDay; }); - it('should correctly map analysis by versions and by days', () => { expect( utils.getAnalysesByVersionByDay(ANALYSES, { @@ -138,8 +137,8 @@ describe('getAnalysesByVersionByDay', () => { 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(); }); @@ -147,10 +146,26 @@ describe('getAnalysesByVersionByDay', () => { 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: '', @@ -253,8 +268,8 @@ describe('hasHistoryData', () => { 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 } ] } ]) @@ -270,8 +285,8 @@ describe('hasHistoryData', () => { 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 } ] } ]) @@ -281,7 +296,7 @@ describe('hasHistoryData', () => { { 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(); diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsHistory.js b/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsHistory.js index 044b1462323..de15fb7c664 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsHistory.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsHistory.js @@ -23,6 +23,7 @@ import DeferredSpinner from '../../../components/common/DeferredSpinner'; 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'; */ @@ -86,7 +87,7 @@ export default class GraphsHistory extends React.PureComponent { return acc.concat({ className: event.category, name: event.name, - date: new Date(analysis.date) + date: parseDate(analysis.date) }); }, []); return sortBy(filteredEvents, 'date'); diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAnalysesList.js b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAnalysesList.js index 7b94b01483c..9afecfd778f 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAnalysesList.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAnalysesList.js @@ -24,6 +24,7 @@ import { throttle } from 'lodash'; import ProjectActivityAnalysis from './ProjectActivityAnalysis'; import DateFormatter from '../../../components/intl/DateFormatter'; import { translate } from '../../../helpers/l10n'; +import { toShortNotSoISOString } from '../../../helpers/dates'; import { activityQueryChanged, getAnalysesByVersionByDay, @@ -190,7 +191,10 @@ export default class ProjectActivityAnalysesList extends React.PureComponent { }
    {days.map(day => -
  • +
  • diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityApp.js b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityApp.js index 2de698d4b52..e0b70d68e38 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityApp.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityApp.js @@ -23,6 +23,7 @@ import Helmet from 'react-helmet'; 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'; */ @@ -88,7 +89,7 @@ export default function ProjectActivityApp(props /*: Props */) {
    ({ - analyses: analyses.map(analysis => ({ ...analysis, date: new Date(analysis.date) })), + analyses: analyses.map(analysis => ({ ...analysis, date: parseDate(analysis.date) })), paging })); }; @@ -186,7 +187,7 @@ class ProjectActivityAppContainer extends React.PureComponent { measures.map(measure => ({ metric: measure.metric, history: measure.history.map(analysis => ({ - date: new Date(analysis.date), + date: parseDate(analysis.date), value: analysis.value })) })), diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityDateInput.js b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityDateInput.js index f6f85c29c9b..edd3ca20dc7 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityDateInput.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityDateInput.js @@ -19,11 +19,10 @@ */ // @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'; */ /*:: @@ -37,18 +36,13 @@ type Props = { 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 ( diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/GraphHistory-test.js b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/GraphHistory-test.js index 57cf8c7087e..466d141907d 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/GraphHistory-test.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/GraphHistory-test.js @@ -21,15 +21,16 @@ import React from 'react'; 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 } ] } ]; diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/GraphsHistory-test.js b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/GraphsHistory-test.js index 5a62d59c1fe..099d18fdfff 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/GraphsHistory-test.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/GraphsHistory-test.js @@ -21,11 +21,12 @@ import React from 'react'; 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', @@ -36,12 +37,12 @@ const ANALYSES = [ }, { 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', @@ -62,9 +63,9 @@ 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 } ] } ]; @@ -117,7 +118,7 @@ it('should show that there is no history data', () => { { 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 }] } ]} /> diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/GraphsTooltips-test.js b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/GraphsTooltips-test.js index 34f50c3911a..d67c36db1b1 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/GraphsTooltips-test.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/GraphsTooltips-test.js @@ -21,6 +21,7 @@ import React from 'react'; import { shallow } from 'enzyme'; import GraphsTooltips from '../GraphsTooltips'; import { DEFAULT_GRAPH } from '../../utils'; +import { parseDate } from '../../../../helpers/dates'; const SERIES_ISSUES = [ { @@ -72,7 +73,7 @@ const DEFAULT_PROPS = { 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 @@ -88,7 +89,7 @@ it('should render correctly for random graphs', () => { ) diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityAnalysesList-test.js b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityAnalysesList-test.js index 6a0c61741f2..216d9d7e727 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityAnalysesList-test.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityAnalysesList-test.js @@ -20,13 +20,13 @@ 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', @@ -37,12 +37,12 @@ const ANALYSES = [ }, { 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', @@ -58,7 +58,7 @@ const ANALYSES = [ }, { key: 'A4', - date: new Date('2016-10-24T16:33:50+0000'), + date: dates.parseDate('2016-10-24T16:33:50+0000'), events: [ { key: 'E1', @@ -92,6 +92,8 @@ dates.startOfDay = jest.fn(date => { return startDay; }); +dates.toShortNotSoISOString = date => 'ISO.' + date; + it('should render correctly', () => { expect(shallow()).toMatchSnapshot(); }); @@ -107,8 +109,8 @@ it('should correctly filter analyses by date range', () => { 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(); diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityApp-test.js b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityApp-test.js index 1d3d5cec290..2dcf1dd4d61 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityApp-test.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityApp-test.js @@ -21,11 +21,12 @@ import React from 'react'; 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', @@ -36,12 +37,12 @@ const ANALYSES = [ }, { 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', @@ -76,8 +77,8 @@ const DEFAULT_PROPS = { { 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' } ] } ], diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityDateInput-test.js b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityDateInput-test.js index 6b93eaae296..a0930873a30 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityDateInput-test.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityDateInput-test.js @@ -20,13 +20,14 @@ 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( {}} /> ) diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityGraphs-test.js b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityGraphs-test.js index 64c9f8b420b..ffc96031708 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityGraphs-test.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityGraphs-test.js @@ -21,6 +21,7 @@ import React from 'react'; import { shallow } from 'enzyme'; import ProjectActivityGraphs from '../ProjectActivityGraphs'; import { DEFAULT_GRAPH } from '../../utils'; +import { parseDate } from '../../../../helpers/dates'; const ANALYSES = [ { @@ -67,9 +68,9 @@ const DEFAULT_PROPS = { { 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' } ] } ], diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityPageHeader-test.js b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityPageHeader-test.js index f6faa2a1efa..4c02f5d15e6 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityPageHeader-test.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityPageHeader-test.js @@ -20,13 +20,14 @@ 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( {}} /> diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityAnalysesList-test.js.snap b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityAnalysesList-test.js.snap index 00938d611a8..904f0c3a49d 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityAnalysesList-test.js.snap +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityAnalysesList-test.js.snap @@ -25,6 +25,7 @@ exports[`should correctly filter analyses by category 1`] = ` >
  • — diff --git a/server/sonar-web/src/main/js/components/issue/components/IssueCommentLine.js b/server/sonar-web/src/main/js/components/issue/components/IssueCommentLine.js index 51865ad5850..aa6eeb9013f 100644 --- a/server/sonar-web/src/main/js/components/issue/components/IssueCommentLine.js +++ b/server/sonar-web/src/main/js/components/issue/components/IssueCommentLine.js @@ -19,11 +19,11 @@ */ // @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'; */ /*:: @@ -98,7 +98,7 @@ export default class IssueCommentLine extends React.PureComponent { tabIndex={0} />
    - +
    {comment.updatable && diff --git a/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueChangelog-test.js.snap b/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueChangelog-test.js.snap index 531d5bf7ab2..30f81a378f2 100644 --- a/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueChangelog-test.js.snap +++ b/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueChangelog-test.js.snap @@ -43,9 +43,8 @@ exports[`should open the popup when the button is clicked 2`] = ` - - -
    -
    -
    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 { @@ -101,10 +101,10 @@ $.fn.barchart = function(data) { } }) .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) { diff --git a/server/sonar-web/src/main/js/helpers/__tests__/dates-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/dates-test.ts index 455886d15a8..bbdb35139d0 100644 --- a/server/sonar-web/src/main/js/helpers/__tests__/dates-test.ts +++ b/server/sonar-web/src/main/js/helpers/__tests__/dates-test.ts @@ -18,10 +18,11 @@ * 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'); @@ -39,14 +40,14 @@ it('startOfDay', () => { 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', () => { @@ -56,14 +57,14 @@ 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); }); diff --git a/server/sonar-web/src/main/js/helpers/__tests__/query-test.js b/server/sonar-web/src/main/js/helpers/__tests__/query-test.js index 11d7b289cae..9c2c8c24b37 100644 --- a/server/sonar-web/src/main/js/helpers/__tests__/query-test.js +++ b/server/sonar-web/src/main/js/helpers/__tests__/query-test.js @@ -18,6 +18,7 @@ * 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', () => { @@ -78,7 +79,7 @@ describe('parseAsDate', () => { }); 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(); diff --git a/server/sonar-web/src/main/js/helpers/dates.ts b/server/sonar-web/src/main/js/helpers/dates.ts index 5bbb50b3bff..3bba40df67e 100644 --- a/server/sonar-web/src/main/js/helpers/dates.ts +++ b/server/sonar-web/src/main/js/helpers/dates.ts @@ -17,9 +17,14 @@ * 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) { @@ -28,31 +33,24 @@ function pad(number: number) { 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 { @@ -60,31 +58,17 @@ 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); } diff --git a/server/sonar-web/src/main/js/helpers/handlebars/d.js b/server/sonar-web/src/main/js/helpers/handlebars/d.js index ef43101b332..fc61cb21129 100644 --- a/server/sonar-web/src/main/js/helpers/handlebars/d.js +++ b/server/sonar-web/src/main/js/helpers/handlebars/d.js @@ -17,10 +17,13 @@ * 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)); }; diff --git a/server/sonar-web/src/main/js/helpers/handlebars/dt.js b/server/sonar-web/src/main/js/helpers/handlebars/dt.js index 3af77ae1d6c..2334f217f88 100644 --- a/server/sonar-web/src/main/js/helpers/handlebars/dt.js +++ b/server/sonar-web/src/main/js/helpers/handlebars/dt.js @@ -17,12 +17,15 @@ * 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)); }; diff --git a/server/sonar-web/src/main/js/helpers/handlebars/fromNow.js b/server/sonar-web/src/main/js/helpers/handlebars/fromNow.js index ea25726d79f..c17513de218 100644 --- a/server/sonar-web/src/main/js/helpers/handlebars/fromNow.js +++ b/server/sonar-web/src/main/js/helpers/handlebars/fromNow.js @@ -18,7 +18,10 @@ * 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 + ); }; diff --git a/server/sonar-web/src/main/js/helpers/l10n.ts b/server/sonar-web/src/main/js/helpers/l10n.ts index 57f51949074..5a1e4bcb190 100644 --- a/server/sonar-web/src/main/js/helpers/l10n.ts +++ b/server/sonar-web/src/main/js/helpers/l10n.ts @@ -113,7 +113,7 @@ export function requestMessages(): Promise { // do nothing } resetBundle(messages); - return effectiveLocale || browserLocale || DEFAULT_LANGUAGE; + return effectiveLocale; }, ({ response }) => { if (response && response.status === 304) { diff --git a/server/sonar-web/src/main/js/helpers/periods.js b/server/sonar-web/src/main/js/helpers/periods.js index 4c5ac1c876d..d458a1931eb 100644 --- a/server/sonar-web/src/main/js/helpers/periods.js +++ b/server/sonar-web/src/main/js/helpers/periods.js @@ -18,6 +18,7 @@ * 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)) { @@ -50,7 +51,7 @@ export function getPeriodDate(period) { return null; } - return new Date(period.date); + return parseDate(period.date); } export function getLeakPeriodLabel(periods) { diff --git a/server/sonar-web/src/main/js/helpers/query.js b/server/sonar-web/src/main/js/helpers/query.js index a87eefe5e3f..400390e65b8 100644 --- a/server/sonar-web/src/main/js/helpers/query.js +++ b/server/sonar-web/src/main/js/helpers/query.js @@ -19,7 +19,7 @@ */ // @flow import { isNil, omitBy } from 'lodash'; -import { isValidDate, toNotSoISOString } from './dates'; +import { isValidDate, parseDate, toNotSoISOString } from './dates'; /*:: export type RawQuery = { [string]: any }; @@ -66,7 +66,7 @@ export function parseAsBoolean( export function parseAsDate(value /*: ?string */) /*: Date | void */ { if (value) { - const date = new Date(value); + const date = parseDate(value); if (isValidDate(date)) { return date; } diff --git a/server/sonar-web/src/main/js/helpers/testUtils.ts b/server/sonar-web/src/main/js/helpers/testUtils.ts index a0931769355..02e2ce1c37c 100644 --- a/server/sonar-web/src/main/js/helpers/testUtils.ts +++ b/server/sonar-web/src/main/js/helpers/testUtils.ts @@ -17,7 +17,7 @@ * 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 = { @@ -71,8 +71,9 @@ export function doAsync(fn: Function): Promise { }); } +// 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, options: ShallowRendererProps = {}) { return shallow(node, { ...options, context: { intl, ...options.context } }); } diff --git a/server/sonar-web/yarn.lock b/server/sonar-web/yarn.lock index fc6cfa7afab..3ee0524870e 100644 --- a/server/sonar-web/yarn.lock +++ b/server/sonar-web/yarn.lock @@ -17,6 +17,12 @@ 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" @@ -1975,6 +1981,10 @@ dashdash@^1.12.0: 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"