aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src/main/js/apps
diff options
context:
space:
mode:
Diffstat (limited to 'server/sonar-web/src/main/js/apps')
-rw-r--r--server/sonar-web/src/main/js/apps/account/projects/ProjectCard.tsx28
-rw-r--r--server/sonar-web/src/main/js/apps/account/projects/__tests__/ProjectCard-test.js4
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/components/DateFilter.js18
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/components/Task.js6
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/components/TaskDate.tsx (renamed from server/sonar-web/src/main/js/apps/background-tasks/components/TaskDate.js)34
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/components/TaskDay.tsx (renamed from server/sonar-web/src/main/js/apps/background-tasks/components/TaskDay.js)24
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/types.ts (renamed from server/sonar-web/src/main/js/apps/background-tasks/types.js)12
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/components/LeakPeriodLegend.js12
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/components/MeasureContent.js7
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/components/__tests__/LeakPeriodLegend-test.js6
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/LeakPeriodLegend-test.js.snap14
-rw-r--r--server/sonar-web/src/main/js/apps/issues/sidebar/CreationDateFacet.js97
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/ApplicationLeakPeriodLegend.js4
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/LeakPeriodLegend.js37
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/OverviewApp.js3
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/__tests__/LeakPeriodLegend-test.js12
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/ApplicationLeakPeriodLegend-test.js.snap6
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/LeakPeriodLegend-test.js.snap34
-rw-r--r--server/sonar-web/src/main/js/apps/overview/events/Analysis.js4
-rw-r--r--server/sonar-web/src/main/js/apps/overview/events/Event.js20
-rw-r--r--server/sonar-web/src/main/js/apps/overview/events/PreviewGraphTooltips.js4
-rw-r--r--server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Analysis-test.js.snap4
-rw-r--r--server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Event-test.js.snap14
-rw-r--r--server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/PreviewGraphTooltips-test.js.snap4
-rw-r--r--server/sonar-web/src/main/js/apps/overview/main/CodeSmells.js28
-rw-r--r--server/sonar-web/src/main/js/apps/overview/main/enhance.js14
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/__tests__/__snapshots__/utils-test.js.snap78
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/__tests__/utils-test.js73
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/GraphsHistory.js3
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/GraphsTooltips.js4
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAnalysesList.js10
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAnalysis.js4
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityApp.js3
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAppContainer.js5
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityDateInput.js10
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityAnalysesList-test.js17
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityDateInput-test.js4
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/GraphsTooltips-test.js.snap9
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityAnalysesList-test.js.snap35
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityDateInput-test.js.snap4
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/utils.js4
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/ProjectCardLeak.js27
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/ProjectCardOverall.js14
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCardLeak-test.js8
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCardOverall-test.js5
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ProjectCardLeak-test.js.snap15
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ProjectCardOverall-test.js.snap8
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/changelog/Changelog.tsx8
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/Changelog-test.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileDate.tsx12
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionRules.tsx20
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionStagnant.tsx21
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/utils.ts12
-rw-r--r--server/sonar-web/src/main/js/apps/settings/licenses/LicenseRow.js4
-rw-r--r--server/sonar-web/src/main/js/apps/settings/licenses/__tests__/LicenseRow-test.js2
55 files changed, 444 insertions, 427 deletions
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 b81b2cf256f..cd5f6d39fea 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
@@ -18,35 +18,39 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import * as moment from 'moment';
import { sortBy } from 'lodash';
+import { FormattedRelative } from 'react-intl';
import { Link } from 'react-router';
import { Project } from './types';
+import DateTimeFormatter from '../../../components/intl/DateTimeFormatter';
import Level from '../../../components/ui/Level';
+import Tooltip from '../../../components/controls/Tooltip';
import { translateWithParameters, translate } from '../../../helpers/l10n';
interface Props {
project: Project;
}
-export default function ProjectCard(props: Props) {
- const { project } = props;
+export default function ProjectCard({ project }: Props) {
const isAnalyzed = project.lastAnalysisDate != null;
- const analysisMoment = isAnalyzed && moment(project.lastAnalysisDate);
const links = sortBy(project.links, 'type');
return (
<div className="account-project-card clearfix">
<aside className="account-project-side">
{isAnalyzed
- ? <div
- className="account-project-analysis"
- title={analysisMoment ? analysisMoment.format('LLL') : undefined}>
- {translateWithParameters(
- 'my_account.projects.analyzed_x',
- analysisMoment ? analysisMoment.fromNow() : undefined
- )}
- </div>
+ ? <Tooltip
+ overlay={<DateTimeFormatter date={project.lastAnalysisDate} />}
+ placement="right">
+ <div className="account-project-analysis">
+ <FormattedRelative value={project.lastAnalysisDate}>
+ {(relativeDate: string) =>
+ <span>
+ {translateWithParameters('my_account.projects.analyzed_x', relativeDate)}
+ </span>}
+ </FormattedRelative>
+ </div>
+ </Tooltip>
: <div className="account-project-analysis">
{translate('my_account.projects.never_analyzed')}
</div>}
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 f681f8af62f..aa597b1ce8c 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,9 +49,7 @@ it('should not render optional fields', () => {
it('should render analysis date', () => {
const project = { ...BASE, lastAnalysisDate: '2016-05-17' };
const output = shallow(<ProjectCard project={project} />);
- expect(output.find('.account-project-analysis').text()).toContain(
- 'my_account.projects.analyzed_x'
- );
+ expect(output.find('.account-project-analysis FormattedRelative')).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 98bd76ece05..8fe7a69b028 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
@@ -17,11 +17,9 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-// @flow
import $ from 'jquery';
-import moment from 'moment';
import React, { Component } from 'react';
-import { DATE_FORMAT } from '../constants';
+import { toShortNotSoISOString, isValidDate } from '../../../helpers/dates';
export default class DateFilter extends Component {
componentDidMount() {
@@ -47,17 +45,15 @@ export default class DateFilter extends Component {
handleChange() {
const date = {};
- const minDateRaw = this.refs.minDate.value;
- const maxDateRaw = this.refs.maxDate.value;
- const minDate = moment(minDateRaw, DATE_FORMAT, true);
- const maxDate = moment(maxDateRaw, DATE_FORMAT, true);
+ const minDate = new Date(this.refs.minDate.value);
+ const maxDate = new Date(this.refs.maxDate.value);
- if (minDate.isValid()) {
- date.minSubmittedAt = minDate.format(DATE_FORMAT);
+ if (isValidDate(minDate)) {
+ date.minSubmittedAt = toShortNotSoISOString(minDate);
}
- if (maxDate.isValid()) {
- date.maxExecutedAt = maxDate.format(DATE_FORMAT);
+ if (isValidDate(maxDate)) {
+ date.maxExecutedAt = toShortNotSoISOString(maxDate);
}
this.props.onChange(date);
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/Task.js b/server/sonar-web/src/main/js/apps/background-tasks/components/Task.js
index 7f49e254a41..3c93857dadb 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/components/Task.js
+++ b/server/sonar-web/src/main/js/apps/background-tasks/components/Task.js
@@ -48,9 +48,9 @@ export default class Task extends React.PureComponent {
<TaskComponent task={task} />
<TaskId task={task} />
<TaskDay task={task} prevTask={prevTask} />
- <TaskDate date={task.submittedAt} baseDate={task.submittedAt} format="LTS" />
- <TaskDate date={task.startedAt} baseDate={task.submittedAt} format="LTS" />
- <TaskDate date={task.executedAt} baseDate={task.submittedAt} format="LTS" />
+ <TaskDate date={task.submittedAt} baseDate={task.submittedAt} />
+ <TaskDate date={task.startedAt} baseDate={task.submittedAt} />
+ <TaskDate date={task.executedAt} baseDate={task.submittedAt} />
<TaskExecutionTime task={task} />
<TaskActions
component={component}
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/TaskDate.js b/server/sonar-web/src/main/js/apps/background-tasks/components/TaskDate.tsx
index 117702bafd9..d03a3e62289 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/components/TaskDate.js
+++ b/server/sonar-web/src/main/js/apps/background-tasks/components/TaskDate.tsx
@@ -17,28 +17,28 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-/* @flow */
-import moment from 'moment';
-import React from 'react';
+import * as React from 'react';
+import TimeFormatter from '../../../components/intl/TimeFormatter';
+import { differenceInDays, isValidDate } from '../../../helpers/dates';
-const TaskDate = (
- { date, baseDate, format } /*: {
- date: string,
- baseDate: string,
- format: string
-} */
-) => {
- const m = moment(date);
- const baseM = moment(baseDate);
- const diff = date && baseDate ? m.diff(baseM, 'days') : 0;
+interface Props {
+ date: string;
+ baseDate: string;
+}
+
+export default function TaskDate({ date, baseDate }: Props) {
+ const parsedDate = new Date(date);
+ const parsedBaseDate = new Date(baseDate);
+ const diff =
+ date && baseDate && isValidDate(parsedDate) && isValidDate(parsedBaseDate)
+ ? differenceInDays(parsedDate, parsedBaseDate)
+ : 0;
return (
<td className="thin nowrap text-right">
{diff > 0 && <span className="text-warning little-spacer-right">{`(+${diff}d)`}</span>}
- {date ? moment(date).format(format) : ''}
+ {date && isValidDate(parsedDate) ? <TimeFormatter date={parsedDate} long={true} /> : ''}
</td>
);
-};
-
-export default TaskDate;
+}
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/TaskDay.js b/server/sonar-web/src/main/js/apps/background-tasks/components/TaskDay.tsx
index 8307b341f36..ed6a79cef9c 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/components/TaskDay.js
+++ b/server/sonar-web/src/main/js/apps/background-tasks/components/TaskDay.tsx
@@ -17,23 +17,23 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-/* @flow */
-import moment from 'moment';
-import React from 'react';
-/*:: import type { Task } from '../types'; */
+import * as React from 'react';
+import DateFormatter from '../../../components/intl/DateFormatter';
+import { isSameDay } from '../../../helpers/dates';
+import { ITask } from '../types';
-function isAnotherDay(a, b) {
- return !moment(a).isSame(moment(b), 'day');
+interface Props {
+ task: ITask;
+ prevTask?: ITask;
}
-const TaskDay = ({ task, prevTask } /*: { task: Task, prevTask: ?Task } */) => {
- const shouldDisplay = !prevTask || isAnotherDay(task.submittedAt, prevTask.submittedAt);
+export default function TaskDay({ task, prevTask }: Props) {
+ const shouldDisplay =
+ !prevTask || !isSameDay(new Date(task.submittedAt), new Date(prevTask.submittedAt));
return (
<td className="thin nowrap text-right">
- {shouldDisplay ? moment(task.submittedAt).format('LL') : ''}
+ {shouldDisplay ? <DateFormatter date={task.submittedAt} long={true} /> : ''}
</td>
);
-};
-
-export default TaskDay;
+}
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/types.js b/server/sonar-web/src/main/js/apps/background-tasks/types.ts
index e272937867f..c517f201399 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/types.js
+++ b/server/sonar-web/src/main/js/apps/background-tasks/types.ts
@@ -17,9 +17,9 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-/*::
-export type Task = {
- incremental: boolean,
- id: string
-};
-*/
+
+export interface ITask {
+ incremental: boolean;
+ id: string;
+ submittedAt: string;
+}
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 ef72a1d213b..e8b41e80e36 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,8 @@
// @flow
import React from 'react';
import classNames from 'classnames';
-import moment from 'moment';
+import { FormattedRelative } from 'react-intl';
+import DateFormatter from '../../../components/intl/DateFormatter';
import Tooltip from '../../../components/controls/Tooltip';
import { getPeriodLabel, getPeriodDate } from '../../../helpers/periods';
import { translate, translateWithParameters } from '../../../helpers/l10n';
@@ -53,8 +54,13 @@ export default function LeakPeriodLegend({ className, component, period } /*: Pr
}
const date = getPeriodDate(period);
- const fromNow = moment(date).fromNow();
- const tooltip = fromNow + ', ' + moment(date).format('LL');
+ const tooltip = (
+ <div>
+ <FormattedRelative value={date} />
+ {', '}
+ <DateFormatter date={date} long={true} />
+ </div>
+ );
return (
<Tooltip placement="left" overlay={tooltip}>
{label}
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 b4c91f405cc..cf03a171d55 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
@@ -20,7 +20,6 @@
// @flow
import React from 'react';
import classNames from 'classnames';
-import moment from 'moment';
import Breadcrumbs from './Breadcrumbs';
import FilesView from '../drilldown/FilesView';
import MeasureFavoriteContainer from './MeasureFavoriteContainer';
@@ -217,15 +216,13 @@ export default class MeasureContent extends React.PureComponent {
renderCode() {
const { component, leakPeriod } = this.props;
const leakPeriodDate =
- isDiffMetric(this.props.metric.key) && leakPeriod != null
- ? moment(leakPeriod.date).toDate()
- : null;
+ isDiffMetric(this.props.metric.key) && leakPeriod != null ? new Date(leakPeriod.date) : null;
let filterLine;
if (leakPeriodDate != null) {
filterLine = line => {
if (line.scmDate) {
- const scmDate = moment(line.scmDate).toDate();
+ const scmDate = new Date(line.scmDate);
return scmDate >= leakPeriodDate;
} else {
return false;
diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/LeakPeriodLegend-test.js b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/LeakPeriodLegend-test.js
index 4f7fce011d7..9becda572f1 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/LeakPeriodLegend-test.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/LeakPeriodLegend-test.js
@@ -45,12 +45,6 @@ const PERIOD_DAYS = {
parameter: '18'
};
-jest.mock('moment', () => () => ({
- format: () => 'March 1, 2017 9:36 AM',
- fromNow: () => 'a month ago',
- toDate: () => 'date'
-}));
-
it('should render correctly', () => {
expect(shallow(<LeakPeriodLegend component={PROJECT} period={PERIOD} />)).toMatchSnapshot();
expect(shallow(<LeakPeriodLegend component={PROJECT} period={PERIOD_DAYS} />)).toMatchSnapshot();
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 0f0e328d85e..b82411aaf92 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
@@ -2,7 +2,19 @@
exports[`should render correctly 1`] = `
<Tooltip
- overlay="a month ago, March 1, 2017 9:36 AM"
+ overlay={
+ <div>
+ <FormattedRelative
+ updateInterval={10000}
+ value={2017-05-16T11:50:02.000Z}
+ />
+ ,
+ <DateFormatter
+ date={2017-05-16T11:50:02.000Z}
+ long={true}
+ />
+ </div>
+ }
placement="left"
>
<div
diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/CreationDateFacet.js b/server/sonar-web/src/main/js/apps/issues/sidebar/CreationDateFacet.js
index 3a30ccd1ec4..8a409a34ac8 100644
--- a/server/sonar-web/src/main/js/apps/issues/sidebar/CreationDateFacet.js
+++ b/server/sonar-web/src/main/js/apps/issues/sidebar/CreationDateFacet.js
@@ -19,13 +19,16 @@
*/
// @flow
import React from 'react';
-import moment from 'moment';
import { max } from 'lodash';
+import { FormattedRelative, intlShape } from 'react-intl';
+import { formatterOption, 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 { translate } from '../../../helpers/l10n';
import { formatMeasure } from '../../../helpers/measures';
/*:: import type { Component } from '../utils'; */
@@ -46,8 +49,6 @@ type Props = {|
|};
*/
-const DATE_FORMAT = 'YYYY-MM-DDTHH:mm:ssZZ';
-
export default class CreationDateFacet extends React.PureComponent {
/*:: props: Props; */
@@ -55,6 +56,10 @@ export default class CreationDateFacet extends React.PureComponent {
open: true
};
+ static contextTypes = {
+ intl: intlShape
+ };
+
property = 'createdAt';
hasValue = () =>
@@ -84,36 +89,34 @@ export default class CreationDateFacet extends React.PureComponent {
};
handleBarClick = (
- {
- createdAfter,
- createdBefore
- } /*: {
- createdAfter: Object,
- createdBefore?: Object
+ { createdAfter, createdBefore } /*: {
+ createdAfter: Date,
+ createdBefore?: Date
} */
) => {
this.resetTo({
- createdAfter: createdAfter.format(DATE_FORMAT),
- createdBefore: createdBefore && createdBefore.format(DATE_FORMAT)
+ createdAfter: toShortNotSoISOString(createdAfter),
+ createdBefore: createdBefore && toShortNotSoISOString(createdBefore)
});
};
- handlePeriodChange = (property /*: string */) => (value /*: string */) => {
+ handlePeriodChange = (property /*: string */, value /*: string */) => {
this.props.onChange({
createdAt: undefined,
createdInLast: undefined,
sinceLeakPeriod: undefined,
- [property]: value
+ [property]: toShortNotSoISOString(new Date(value))
});
};
- handlePeriodClick = (period /*: string */) => {
- this.resetTo({ createdInLast: period });
- };
+ handlePeriodChangeBefore = (value /*: string */) =>
+ this.handlePeriodChange('createdBefore', value);
- handleLeakPeriodClick = () => {
- this.resetTo({ sinceLeakPeriod: true });
- };
+ handlePeriodChangeAfter = (value /*: string */) => this.handlePeriodChange('createdAfter', value);
+
+ handlePeriodClick = (period /*: string */) => this.resetTo({ createdInLast: period });
+
+ handleLeakPeriodClick = () => this.resetTo({ sinceLeakPeriod: true });
renderBarChart() {
const { createdBefore, stats } = this.props;
@@ -128,31 +131,32 @@ export default class CreationDateFacet extends React.PureComponent {
return null;
}
- const data = periods.map((startDate, index) => {
- const startMoment = moment(startDate);
- const nextStartMoment =
- index < periods.length - 1
- ? moment(periods[index + 1])
- : createdBefore ? moment(createdBefore) : undefined;
- const endMoment = nextStartMoment && nextStartMoment.clone().subtract(1, 'days');
+ const { formatDate } = this.context.intl;
+ const beforeDate = createdBefore ? createdBefore : undefined;
+ const data = periods.map((start, index) => {
+ const startDate = new Date(start);
+ let nextStartDate = index < periods.length - 1 ? periods[index + 1] : beforeDate;
+ let endDate;
+ if (nextStartDate) {
+ nextStartDate = new Date(nextStartDate);
+ endDate = new Date(nextStartDate);
+ endDate.setDate(endDate.getDate() - 1);
+ }
let tooltip =
- formatMeasure(stats[startDate], 'SHORT_INT') + '<br>' + startMoment.format('LL');
-
- if (endMoment) {
- const isSameDay = endMoment.diff(startMoment, 'days') <= 1;
- if (!isSameDay) {
- tooltip += ' – ' + endMoment.format('LL');
- }
+ formatMeasure(stats[start], 'SHORT_INT') +
+ '<br/>' +
+ formatDate(startDate, longFormatterOption);
+ if (endDate && !isSameDay(endDate, startDate)) {
+ tooltip += ' – ' + formatDate(endDate, longFormatterOption);
}
return {
- createdAfter: startMoment,
- createdBefore: nextStartMoment,
- startMoment,
+ createdAfter: startDate,
+ createdBefore: nextStartDate,
tooltip,
x: index,
- y: stats[startDate]
+ y: stats[start]
};
});
@@ -177,13 +181,12 @@ export default class CreationDateFacet extends React.PureComponent {
}
renderExactDate() {
- const m = moment(this.props.createdAt);
return (
<div className="search-navigator-facet-container">
- {m.format('LLL')}
+ <DateTimeFormatter date={this.props.createdAt} />
<br />
<span className="note">
- ({m.fromNow()})
+ <FormattedRelative value={this.props.createdAt} />
</span>
</div>
);
@@ -191,26 +194,26 @@ export default class CreationDateFacet extends React.PureComponent {
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.handlePeriodChange('createdAfter')}
+ onChange={this.handlePeriodChangeAfter}
placeholder={translate('from')}
- value={createdAfter ? moment(createdAfter).format('YYYY-MM-DD') : undefined}
+ value={createdAfter ? formatDate(createdAfter, formatterOption) : undefined}
/>
<DateInput
className="search-navigator-date-facet-selection-dropdown-right"
- onChange={this.handlePeriodChange('createdBefore')}
+ onChange={this.handlePeriodChangeBefore}
placeholder={translate('to')}
- value={createdBefore ? moment(createdBefore).format('YYYY-MM-DD') : undefined}
+ value={createdBefore ? formatDate(createdBefore, formatterOption) : undefined}
/>
</div>
);
}
- renderPrefefinedPeriods() {
+ renderPredefinedPeriods() {
const { component, createdInLast, sinceLeakPeriod } = this.props;
return (
<div className="spacer-top issues-predefined-periods">
@@ -259,7 +262,7 @@ export default class CreationDateFacet extends React.PureComponent {
: <div>
{this.renderBarChart()}
{this.renderPeriodSelectors()}
- {this.renderPrefefinedPeriods()}
+ {this.renderPredefinedPeriods()}
</div>;
}
diff --git a/server/sonar-web/src/main/js/apps/overview/components/ApplicationLeakPeriodLegend.js b/server/sonar-web/src/main/js/apps/overview/components/ApplicationLeakPeriodLegend.js
index 3c9785aa8be..aaca5381cb4 100644
--- a/server/sonar-web/src/main/js/apps/overview/components/ApplicationLeakPeriodLegend.js
+++ b/server/sonar-web/src/main/js/apps/overview/components/ApplicationLeakPeriodLegend.js
@@ -20,7 +20,7 @@
// @flow
import React from 'react';
import Tooltip from '../../../components/controls/Tooltip';
-import FormattedDate from '../../../components/ui/FormattedDate';
+import DateTooltipFormatter from '../../../components/intl/DateTooltipFormatter';
import { getApplicationLeak } from '../../../api/application';
import { translate } from '../../../helpers/l10n';
@@ -79,7 +79,7 @@ export default class ApplicationLeakPeriodLegend extends React.Component {
? <ul className="text-left">
{this.state.leaks.map(leak =>
<li key={leak.project}>
- {leak.projectName}: <FormattedDate date={leak.date} format="LL" />
+ {leak.projectName}: <DateTooltipFormatter date={leak.date} />
</li>
)}
</ul>
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 88d26edef84..f932aeb8c8e 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,8 @@
*/
// @flow
import React from 'react';
-import moment from 'moment';
+import { FormattedRelative } from 'react-intl';
+import DateFormatter from '../../../components/intl/DateFormatter';
import Tooltip from '../../../components/controls/Tooltip';
import { getPeriodDate, getPeriodLabel } from '../../../helpers/periods';
import { translateWithParameters } from '../../../helpers/l10n';
@@ -82,23 +83,33 @@ export default function LeakPeriodLegend({ period } /*: { period: Period } */) {
}
const leakPeriodDate = getPeriodDate(period);
- const momentDate = moment(leakPeriodDate);
- const fromNow = momentDate.fromNow();
- const note = ['date'].includes(period.mode)
- ? translateWithParameters('overview.last_analysis_x', fromNow)
- : translateWithParameters('overview.started_x', fromNow);
- const tooltip = ['date'].includes(period.mode)
- ? translateWithParameters('overview.last_analysis_on_x', momentDate.format('LL'))
- : translateWithParameters('overview.started_on_x', momentDate.format('LL'));
-
+ const tooltip = (
+ <DateFormatter date={leakPeriodDate} long={true}>
+ {formattedLeakPeriodDate =>
+ <span>
+ {translateWithParameters(
+ ['date'].includes(period.mode)
+ ? 'overview.last_analysis_on_x'
+ : 'overview.started_on_x',
+ formattedLeakPeriodDate
+ )}
+ </span>}
+ </DateFormatter>
+ );
return (
<Tooltip overlay={tooltip} placement="top">
<div className="overview-legend">
{translateWithParameters('overview.leak_period_x', leakPeriodLabel)}
<br />
- <span className="note">
- {note}
- </span>
+ <FormattedRelative value={leakPeriodDate}>
+ {fromNow =>
+ <span className="note">
+ {translateWithParameters(
+ ['date'].includes(period.mode) ? 'overview.last_analysis_x' : 'overview.started_x',
+ fromNow
+ )}
+ </span>}
+ </FormattedRelative>
</div>
</Tooltip>
);
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 11d09882375..800a62d4ccd 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
@@ -20,7 +20,6 @@
// @flow
import React from 'react';
import { uniq } from 'lodash';
-import moment from 'moment';
import QualityGate from '../qualityGate/QualityGate';
import ApplicationQualityGate from '../qualityGate/ApplicationQualityGate';
import BugsAndVulnerabilities from '../main/BugsAndVulnerabilities';
@@ -124,7 +123,7 @@ export default class OverviewApp extends React.PureComponent {
const history /*: History */ = {};
r.measures.forEach(measure => {
const measureHistory = measure.history.map(analysis => ({
- date: moment(analysis.date).toDate(),
+ date: new Date(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 251e20594bc..b0179494ae0 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,7 +37,9 @@ describe('check note', () => {
mode: 'date',
parameter: '2013-01-01'
};
- expect(shallow(<LeakPeriodLegend period={period} />).find('.note')).toMatchSnapshot();
+ expect(
+ shallow(<LeakPeriodLegend period={period} />).find('FormattedRelative')
+ ).toMatchSnapshot();
});
it('version', () => {
@@ -46,7 +48,9 @@ describe('check note', () => {
mode: 'version',
parameter: '0.1'
};
- expect(shallow(<LeakPeriodLegend period={period} />).find('.note')).toMatchSnapshot();
+ expect(
+ shallow(<LeakPeriodLegend period={period} />).find('FormattedRelative')
+ ).toMatchSnapshot();
});
it('previous_version', () => {
@@ -54,7 +58,7 @@ describe('check note', () => {
date: '2013-09-22T00:00:00+0200',
mode: 'previous_version'
};
- expect(shallow(<LeakPeriodLegend period={period} />).find('.note')).toMatchSnapshot();
+ expect(shallow(<LeakPeriodLegend period={period} />).find('FormattedRelative')).toHaveLength(1);
});
it('previous_analysis', () => {
@@ -62,6 +66,6 @@ describe('check note', () => {
date: '2013-09-22T00:00:00+0200',
mode: 'previous_analysis'
};
- expect(shallow(<LeakPeriodLegend period={period} />).find('.note')).toMatchSnapshot();
+ expect(shallow(<LeakPeriodLegend period={period} />).find('FormattedRelative')).toHaveLength(1);
});
});
diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/ApplicationLeakPeriodLegend-test.js.snap b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/ApplicationLeakPeriodLegend-test.js.snap
index 217405a6565..cb842597822 100644
--- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/ApplicationLeakPeriodLegend-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/ApplicationLeakPeriodLegend-test.js.snap
@@ -28,17 +28,15 @@ exports[`renders 2`] = `
<li>
Foo
:
- <FormattedDate
+ <DateTooltipFormatter
date="2017-01-01T11:39:03+0100"
- format="LL"
/>
</li>
<li>
Bar
:
- <FormattedDate
+ <DateTooltipFormatter
date="2017-02-01T11:39:03+0100"
- format="LL"
/>
</li>
</ul>
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 397016097b3..44caddb1324 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,33 +9,15 @@ exports[`check note 10 days 1`] = `
`;
exports[`check note date 1`] = `
-<span
- className="note"
->
- overview.last_analysis_x.4 years ago
-</span>
-`;
-
-exports[`check note previous_analysis 1`] = `
-<span
- className="note"
->
- overview.started_x.4 years ago
-</span>
-`;
-
-exports[`check note previous_version 1`] = `
-<span
- className="note"
->
- overview.started_x.4 years ago
-</span>
+<FormattedRelative
+ updateInterval={10000}
+ value={2013-09-21T22:00:00.000Z}
+/>
`;
exports[`check note version 1`] = `
-<span
- className="note"
->
- overview.started_x.4 years ago
-</span>
+<FormattedRelative
+ updateInterval={10000}
+ value={2013-09-21T22:00:00.000Z}
+/>
`;
diff --git a/server/sonar-web/src/main/js/apps/overview/events/Analysis.js b/server/sonar-web/src/main/js/apps/overview/events/Analysis.js
index ef1b6d37e8d..5a9f7cc7807 100644
--- a/server/sonar-web/src/main/js/apps/overview/events/Analysis.js
+++ b/server/sonar-web/src/main/js/apps/overview/events/Analysis.js
@@ -21,7 +21,7 @@
import React from 'react';
import { sortBy } from 'lodash';
import Event from './Event';
-import FormattedDate from '../../../components/ui/FormattedDate';
+import DateTooltipFormatter from '../../../components/intl/DateTooltipFormatter';
import { translate } from '../../../helpers/l10n';
/*:: import type { Analysis as AnalysisType, Event as EventType } from '../../projectActivity/types'; */
@@ -46,7 +46,7 @@ export default function Analysis(props /*: Props */) {
<li className="overview-analysis">
<div className="small little-spacer-bottom">
<strong>
- <FormattedDate date={analysis.date} format="LL" />
+ <DateTooltipFormatter date={analysis.date} placement="right" />
</strong>
</div>
diff --git a/server/sonar-web/src/main/js/apps/overview/events/Event.js b/server/sonar-web/src/main/js/apps/overview/events/Event.js
index be23bc7bc07..bf62a5bd1cc 100644
--- a/server/sonar-web/src/main/js/apps/overview/events/Event.js
+++ b/server/sonar-web/src/main/js/apps/overview/events/Event.js
@@ -20,8 +20,8 @@
// @flow
import React from 'react';
import Tooltip from '../../../components/controls/Tooltip';
-/*:: import type { Event as EventType } from '../../projectActivity/types'; */
import { translate } from '../../../helpers/l10n';
+/*:: import type { Event as EventType } from '../../projectActivity/types'; */
export default function Event(props /*: { event: EventType } */) {
const { event } = props;
@@ -35,13 +35,17 @@ export default function Event(props /*: { event: EventType } */) {
}
return (
- <div className="overview-analysis-event">
+ <span className="overview-analysis-event">
<span className="note">{translate('event.category', event.category)}:</span>{' '}
- <Tooltip overlay={event.description} placement="left">
- <strong>
- {event.name}
- </strong>
- </Tooltip>
- </div>
+ {event.description
+ ? <Tooltip overlay={event.description} placement="left" mouseEnterDelay={0.5}>
+ <strong>
+ {event.name}
+ </strong>
+ </Tooltip>
+ : <strong>
+ {event.name}
+ </strong>}
+ </span>
);
}
diff --git a/server/sonar-web/src/main/js/apps/overview/events/PreviewGraphTooltips.js b/server/sonar-web/src/main/js/apps/overview/events/PreviewGraphTooltips.js
index d4bc3609a6d..c1a898a3bf1 100644
--- a/server/sonar-web/src/main/js/apps/overview/events/PreviewGraphTooltips.js
+++ b/server/sonar-web/src/main/js/apps/overview/events/PreviewGraphTooltips.js
@@ -19,7 +19,7 @@
*/
import React from 'react';
import BubblePopup from '../../../components/common/BubblePopup';
-import FormattedDate from '../../../components/ui/FormattedDate';
+import DateFormatter from '../../../components/intl/DateFormatter';
import PreviewGraphTooltipsContent from './PreviewGraphTooltipsContent';
/*:: import type { Metric } from '../types'; */
/*:: import type { Serie } from '../../../components/charts/AdvancedTimeline'; */
@@ -56,7 +56,7 @@ export default class PreviewGraphTooltips extends React.PureComponent {
<BubblePopup customClass={customClass} position={{ top, left, width: TOOLTIP_WIDTH }}>
<div className="overview-analysis-graph-tooltip">
<div className="overview-analysis-graph-tooltip-title">
- <FormattedDate date={this.props.selectedDate} format="LL" />
+ <DateFormatter date={this.props.selectedDate} long={true} />
</div>
<table className="width-100">
<tbody>
diff --git a/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Analysis-test.js.snap b/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Analysis-test.js.snap
index e37d21f47d9..33bc4e28c18 100644
--- a/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Analysis-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Analysis-test.js.snap
@@ -8,9 +8,9 @@ exports[`should sort the events with version first 1`] = `
className="small little-spacer-bottom"
>
<strong>
- <FormattedDate
+ <DateTooltipFormatter
date="2017-06-10T16:10:59+0200"
- format="LL"
+ placement="right"
/>
</strong>
</div>
diff --git a/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Event-test.js.snap b/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Event-test.js.snap
index 18c6f76ec73..802c927a96c 100644
--- a/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Event-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Event-test.js.snap
@@ -9,7 +9,7 @@ exports[`should render a version correctly 1`] = `
`;
exports[`should render an event correctly 1`] = `
-<div
+<span
className="overview-analysis-event"
>
<span
@@ -19,12 +19,8 @@ exports[`should render an event correctly 1`] = `
:
</span>
- <Tooltip
- placement="left"
- >
- <strong>
- test
- </strong>
- </Tooltip>
-</div>
+ <strong>
+ test
+ </strong>
+</span>
`;
diff --git a/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/PreviewGraphTooltips-test.js.snap b/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/PreviewGraphTooltips-test.js.snap
index 0d0aec9012c..64d9d39a3e4 100644
--- a/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/PreviewGraphTooltips-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/PreviewGraphTooltips-test.js.snap
@@ -17,9 +17,9 @@ exports[`should render correctly 1`] = `
<div
className="overview-analysis-graph-tooltip-title"
>
- <FormattedDate
+ <DateFormatter
date={2011-10-25T10:27:41.000Z}
- format="LL"
+ long={true}
/>
</div>
<table
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 00e81e9d47a..2eab616e195 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
@@ -17,10 +17,11 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import moment from 'moment';
import React from 'react';
import { Link } from 'react-router';
+import { FormattedRelative } from 'react-intl';
import Tooltip from '../../../components/controls/Tooltip';
+import DateTimeFormatter from '../../../components/intl/DateTimeFormatter';
import enhance from './enhance';
import { getMetricName } from '../helpers/metrics';
import { translate, translateWithParameters } from '../../../helpers/l10n';
@@ -43,9 +44,14 @@ class CodeSmells extends React.PureComponent {
Object.assign(params, { sinceLeakPeriod: 'true' });
}
- const formattedAnalysisDate = moment(component.analysisDate).format('LLL');
- const tooltip = translateWithParameters('widget.as_calculated_on_x', formattedAnalysisDate);
-
+ const tooltip = (
+ <DateTimeFormatter date={component.analysisDate}>
+ {formattedAnalysisDate =>
+ <span>
+ {translateWithParameters('widget.as_calculated_on_x', formattedAnalysisDate)}
+ </span>}
+ </DateTimeFormatter>
+ );
return (
<Tooltip overlay={tooltip} placement="top">
<Link to={getComponentIssuesUrl(component.key, params)}>
@@ -56,12 +62,16 @@ class CodeSmells extends React.PureComponent {
}
renderTimelineStartDate() {
- const momentDate = moment(this.props.historyStartDate);
- const fromNow = momentDate.fromNow();
+ if (!this.props.historyStartDate) {
+ return null;
+ }
return (
- <span className="overview-domain-timeline-date">
- {translateWithParameters('overview.started_x', fromNow)}
- </span>
+ <FormattedRelative value={this.props.historyStartDate}>
+ {fromNow =>
+ <span className="overview-domain-timeline-date">
+ {translateWithParameters('overview.started_x', fromNow)}
+ </span>}
+ </FormattedRelative>
);
}
diff --git a/server/sonar-web/src/main/js/apps/overview/main/enhance.js b/server/sonar-web/src/main/js/apps/overview/main/enhance.js
index b4be68adcb1..fb008cabb12 100644
--- a/server/sonar-web/src/main/js/apps/overview/main/enhance.js
+++ b/server/sonar-web/src/main/js/apps/overview/main/enhance.js
@@ -19,9 +19,9 @@
*/
import React from 'react';
import { Link } from 'react-router';
-import moment from 'moment';
import { DrilldownLink } from '../../../components/shared/drilldown-link';
import BubblesIcon from '../../../components/icons-components/BubblesIcon';
+import DateTimeFormatter from '../../../components/intl/DateTimeFormatter';
import HistoryIcon from '../../../components/icons-components/HistoryIcon';
import Rating from './../../../components/ui/Rating';
import Timeline from '../components/Timeline';
@@ -157,8 +157,16 @@ export default function enhance(ComposedComponent) {
if (isDiffMetric(metric)) {
Object.assign(params, { sinceLeakPeriod: 'true' });
}
- const formattedAnalysisDate = moment(component.analysisDate).format('LLL');
- const tooltip = translateWithParameters('widget.as_calculated_on_x', formattedAnalysisDate);
+
+ const tooltip = (
+ <DateTimeFormatter date={component.analysisDate}>
+ {formattedAnalysisDate =>
+ <span>
+ {translateWithParameters('widget.as_calculated_on_x', formattedAnalysisDate)}
+ </span>}
+ </DateTimeFormatter>
+ );
+
return (
<Tooltip overlay={tooltip} placement="top">
<Link to={getComponentIssuesUrl(component.key, params)}>
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/__tests__/__snapshots__/utils-test.js.snap b/server/sonar-web/src/main/js/apps/projectActivity/__tests__/__snapshots__/utils-test.js.snap
index 06b8994c23d..1bc54255ce1 100644
--- a/server/sonar-web/src/main/js/apps/projectActivity/__tests__/__snapshots__/utils-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/projectActivity/__tests__/__snapshots__/utils-test.js.snap
@@ -4,11 +4,11 @@ exports[`generateCoveredLinesMetric should correctly generate covered lines metr
Object {
"data": Array [
Object {
- "x": 2017-04-27T06:21:32.000Z,
+ "x": 2017-04-27T08:21:32.000Z,
"y": 88,
},
Object {
- "x": 2017-04-30T21:06:24.000Z,
+ "x": 2017-04-30T23:06:24.000Z,
"y": 50,
},
],
@@ -23,11 +23,11 @@ Array [
Object {
"data": Array [
Object {
- "x": 2017-04-27T06:21:32.000Z,
+ "x": 2017-04-27T08:21:32.000Z,
"y": 88,
},
Object {
- "x": 2017-04-30T21:06:24.000Z,
+ "x": 2017-04-30T23:06:24.000Z,
"y": 50,
},
],
@@ -38,11 +38,11 @@ Array [
Object {
"data": Array [
Object {
- "x": 2017-04-27T06:21:32.000Z,
+ "x": 2017-04-27T08:21:32.000Z,
"y": 100,
},
Object {
- "x": 2017-04-30T21:06:24.000Z,
+ "x": 2017-04-30T23:06:24.000Z,
"y": 100,
},
],
@@ -57,9 +57,9 @@ exports[`getAnalysesByVersionByDay should also filter analysis based on the quer
Array [
Object {
"byDay": Object {
- "2017-4-18": Array [
+ "1495065600000": Array [
Object {
- "date": 2017-05-18T12:13:07.000Z,
+ "date": 2017-05-18T14:13:07.000Z,
"events": Array [
Object {
"category": "QUALITY_PROFILE",
@@ -76,9 +76,9 @@ Array [
},
Object {
"byDay": Object {
- "2017-4-16": Array [
+ "1494892800000": Array [
Object {
- "date": 2017-05-16T05:09:59.000Z,
+ "date": 2017-05-16T07:09:59.000Z,
"events": Array [
Object {
"category": "VERSION",
@@ -105,9 +105,9 @@ exports[`getAnalysesByVersionByDay should also filter analysis based on the quer
Array [
Object {
"byDay": Object {
- "2017-5-9": Array [
+ "1496966400000": Array [
Object {
- "date": 2017-06-09T09:12:27.000Z,
+ "date": 2017-06-09T11:12:27.000Z,
"events": Array [],
"key": "AVyM9n3cHjR_PLDzRciT",
},
@@ -118,9 +118,9 @@ Array [
},
Object {
"byDay": Object {
- "2017-4-18": Array [
+ "1495065600000": Array [
Object {
- "date": 2017-05-18T12:13:07.000Z,
+ "date": 2017-05-18T14:13:07.000Z,
"events": Array [
Object {
"category": "QUALITY_PROFILE",
@@ -131,9 +131,9 @@ Array [
"key": "AVxZtCpH7841nF4RNEMI",
},
],
- "2017-5-9": Array [
+ "1496966400000": Array [
Object {
- "date": 2017-06-09T09:12:27.000Z,
+ "date": 2017-06-09T11:12:27.000Z,
"events": Array [
Object {
"category": "VERSION",
@@ -160,9 +160,9 @@ exports[`getAnalysesByVersionByDay should correctly map analysis by versions and
Array [
Object {
"byDay": Object {
- "2017-5-9": Array [
+ "1496966400000": Array [
Object {
- "date": 2017-06-09T11:06:10.000Z,
+ "date": 2017-06-09T13:06:10.000Z,
"events": Array [
Object {
"category": "VERSION",
@@ -173,7 +173,7 @@ Array [
"key": "AVyMjlK1HjR_PLDzRbB9",
},
Object {
- "date": 2017-06-09T09:12:27.000Z,
+ "date": 2017-06-09T11:12:27.000Z,
"events": Array [],
"key": "AVyM9n3cHjR_PLDzRciT",
},
@@ -184,9 +184,9 @@ Array [
},
Object {
"byDay": Object {
- "2017-4-18": Array [
+ "1495065600000": Array [
Object {
- "date": 2017-05-18T12:13:07.000Z,
+ "date": 2017-05-18T14:13:07.000Z,
"events": Array [
Object {
"category": "QUALITY_PROFILE",
@@ -197,14 +197,14 @@ Array [
"key": "AVxZtCpH7841nF4RNEMI",
},
Object {
- "date": 2017-05-18T05:17:32.000Z,
+ "date": 2017-05-18T07:17:32.000Z,
"events": Array [],
"key": "AVwaa1qkpbBde8B6UhYI",
},
],
- "2017-5-9": Array [
+ "1496966400000": Array [
Object {
- "date": 2017-06-09T09:12:27.000Z,
+ "date": 2017-06-09T11:12:27.000Z,
"events": Array [
Object {
"category": "VERSION",
@@ -221,9 +221,16 @@ Array [
},
Object {
"byDay": Object {
- "2017-4-16": Array [
+ "1494288000000": Array [
Object {
- "date": 2017-05-16T05:09:59.000Z,
+ "date": 2017-05-09T12:03:59.000Z,
+ "events": Array [],
+ "key": "AVvtGF3IY6vCuQNDdwxI",
+ },
+ ],
+ "1494892800000": Array [
+ Object {
+ "date": 2017-05-16T07:09:59.000Z,
"events": Array [
Object {
"category": "VERSION",
@@ -239,13 +246,6 @@ Array [
"key": "AVwQF7kwl-nNFgFWOJ3V",
},
],
- "2017-4-9": Array [
- Object {
- "date": 2017-05-09T10:03:59.000Z,
- "events": Array [],
- "key": "AVvtGF3IY6vCuQNDdwxI",
- },
- ],
},
"key": "AVyM9oI1HjR_PLDzRciU",
"version": "1.0",
@@ -257,26 +257,26 @@ exports[`getAnalysesByVersionByDay should create fake version 1`] = `
Array [
Object {
"byDay": Object {
- "2017-4-18": Array [
+ "1495065600000": Array [
Object {
- "date": 2017-05-18T12:13:07.000Z,
+ "date": 2017-05-18T14:13:07.000Z,
"events": Array [],
"key": "AVxZtCpH7841nF4RNEMI",
},
],
- "2017-5-9": Array [
+ "1496966400000": Array [
Object {
- "date": 2017-06-09T11:06:10.000Z,
+ "date": 2017-06-09T13:06:10.000Z,
"events": Array [],
"key": "AVyMjlK1HjR_PLDzRbB9",
},
Object {
- "date": 2017-06-09T09:12:27.000Z,
+ "date": 2017-06-09T11:12:27.000Z,
"events": Array [],
"key": "AVyM9n3cHjR_PLDzRciT",
},
Object {
- "date": 2017-06-09T09:12:27.000Z,
+ "date": 2017-06-09T11:12:27.000Z,
"events": Array [],
"key": "AVyMjlK1HjR_PLDzRbB9",
},
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 2ee3b2cfe3d..455c679d2d7 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
@@ -19,22 +19,23 @@
*/
// @flow
import * as utils from '../utils';
+import * as dates from '../../../helpers/dates';
const ANALYSES = [
{
key: 'AVyMjlK1HjR_PLDzRbB9',
- date: new Date('2017-06-09T13:06:10+0200'),
+ date: new Date('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+0200'), 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+0200'),
+ date: new Date('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+0200'),
+ date: new Date('2017-05-18T14:13:07.000Z'),
events: [
{
key: 'AVxZtC-N7841nF4RNEMJ',
@@ -43,10 +44,10 @@ const ANALYSES = [
}
]
},
- { key: 'AVwaa1qkpbBde8B6UhYI', date: new Date('2017-05-18T07:17:32+0200'), events: [] },
+ { key: 'AVwaa1qkpbBde8B6UhYI', date: new Date('2017-05-18T07:17:32.000Z'), events: [] },
{
key: 'AVwQF7kwl-nNFgFWOJ3V',
- date: new Date('2017-05-16T07:09:59+0200'),
+ date: new Date('2017-05-16T07:09:59.000Z'),
events: [
{ key: 'AVyM9oI1HjR_PLDzRciU', category: 'VERSION', name: '1.0' },
{
@@ -56,22 +57,22 @@ const ANALYSES = [
}
]
},
- { key: 'AVvtGF3IY6vCuQNDdwxI', date: new Date('2017-05-09T12:03:59+0200'), events: [] }
+ { key: 'AVvtGF3IY6vCuQNDdwxI', date: new Date('2017-05-09T12:03:59.000Z'), events: [] }
];
const HISTORY = [
{
metric: 'lines_to_cover',
history: [
- { date: new Date('2017-04-27T08:21:32+0200'), value: '100' },
- { date: new Date('2017-04-30T23:06:24+0200'), value: '100' }
+ { date: new Date('2017-04-27T08:21:32.000Z'), value: '100' },
+ { date: new Date('2017-04-30T23:06:24.000Z'), value: '100' }
]
},
{
metric: 'uncovered_lines',
history: [
- { date: new Date('2017-04-27T08:21:32+0200'), value: '12' },
- { date: new Date('2017-04-30T23:06:24+0200'), value: '50' }
+ { date: new Date('2017-04-27T08:21:32.000Z'), value: '12' },
+ { date: new Date('2017-04-30T23:06:24.000Z'), value: '50' }
]
}
];
@@ -83,7 +84,7 @@ const METRICS = [
const QUERY = {
category: '',
- from: new Date('2017-04-27T08:21:32+0200'),
+ from: new Date('2017-04-27T08:21:32.000Z'),
graph: utils.DEFAULT_GRAPH,
project: 'foo',
to: undefined,
@@ -91,16 +92,6 @@ const QUERY = {
customMetrics: ['foo', 'bar', 'baz']
};
-jest.mock('moment', () => date => ({
- startOf: () => {
- return {
- valueOf: () => `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`
- };
- },
- toDate: () => new Date(date),
- format: format => `Formated.${format}:${date.valueOf()}`
-}));
-
describe('generateCoveredLinesMetric', () => {
it('should correctly generate covered lines metric', () => {
expect(utils.generateCoveredLinesMetric(HISTORY[1], HISTORY)).toMatchSnapshot();
@@ -116,6 +107,12 @@ describe('generateSeries', () => {
});
describe('getAnalysesByVersionByDay', () => {
+ dates.startOfDay = jest.fn(date => {
+ const startDay = new Date(date);
+ startDay.setUTCHours(0, 0, 0, 0);
+ return startDay;
+ });
+
it('should correctly map analysis by versions and by days', () => {
expect(
utils.getAnalysesByVersionByDay(ANALYSES, {
@@ -141,8 +138,8 @@ describe('getAnalysesByVersionByDay', () => {
customMetrics: [],
graph: utils.DEFAULT_GRAPH,
project: 'foo',
- to: new Date('2017-06-09T11:12:27+0200'),
- from: new Date('2017-05-18T14:13:07+0200')
+ to: new Date('2017-06-09T11:12:27.000Z'),
+ from: new Date('2017-05-18T14:13:07.000Z')
})
).toMatchSnapshot();
});
@@ -150,10 +147,10 @@ describe('getAnalysesByVersionByDay', () => {
expect(
utils.getAnalysesByVersionByDay(
[
- { key: 'AVyMjlK1HjR_PLDzRbB9', date: new Date('2017-06-09T13:06:10+0200'), events: [] },
- { key: 'AVyM9n3cHjR_PLDzRciT', date: new Date('2017-06-09T11:12:27+0200'), events: [] },
- { key: 'AVyMjlK1HjR_PLDzRbB9', date: new Date('2017-06-09T11:12:27+0200'), events: [] },
- { key: 'AVxZtCpH7841nF4RNEMI', date: new Date('2017-05-18T14:13:07+0200'), events: [] }
+ { 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: [] }
],
{
category: '',
@@ -208,7 +205,7 @@ describe('parseQuery', () => {
it('should parse query with default values', () => {
expect(
utils.parseQuery({
- from: '2017-04-27T08:21:32+0200',
+ from: '2017-04-27T08:21:32.000Z',
id: 'foo',
custom_metrics: 'foo,bar,baz'
})
@@ -219,11 +216,11 @@ describe('parseQuery', () => {
describe('serializeQuery', () => {
it('should serialize query for api request', () => {
expect(utils.serializeQuery(QUERY)).toEqual({
- from: 'Formated.YYYY-MM-DDTHH:mm:ssZZ:1493274092000',
+ from: '2017-04-27T08:21:32+0000',
project: 'foo'
});
expect(utils.serializeQuery({ ...QUERY, graph: 'coverage', category: 'test' })).toEqual({
- from: 'Formated.YYYY-MM-DDTHH:mm:ssZZ:1493274092000',
+ from: '2017-04-27T08:21:32+0000',
project: 'foo',
category: 'test'
});
@@ -233,14 +230,14 @@ describe('serializeQuery', () => {
describe('serializeUrlQuery', () => {
it('should serialize query for url', () => {
expect(utils.serializeUrlQuery(QUERY)).toEqual({
- from: 'Formated.YYYY-MM-DDTHH:mm:ssZZ:1493274092000',
+ from: '2017-04-27T08:21:32+0000',
id: 'foo',
custom_metrics: 'foo,bar,baz'
});
expect(
utils.serializeUrlQuery({ ...QUERY, graph: 'coverage', category: 'test', customMetrics: [] })
).toEqual({
- from: 'Formated.YYYY-MM-DDTHH:mm:ssZZ:1493274092000',
+ from: '2017-04-27T08:21:32+0000',
id: 'foo',
graph: 'coverage',
category: 'test'
@@ -256,8 +253,8 @@ describe('hasHistoryData', () => {
name: 'foo',
type: 'INT',
data: [
- { x: new Date('2017-04-27T08:21:32+0200'), y: 2 },
- { x: new Date('2017-04-30T23:06:24+0200'), y: 2 }
+ { x: new Date('2017-04-27T08:21:32.000Z'), y: 2 },
+ { x: new Date('2017-04-30T23:06:24.000Z'), y: 2 }
]
}
])
@@ -273,8 +270,8 @@ describe('hasHistoryData', () => {
name: 'bar',
type: 'INT',
data: [
- { x: new Date('2017-04-27T08:21:32+0200'), y: 2 },
- { x: new Date('2017-04-30T23:06:24+0200'), y: 2 }
+ { x: new Date('2017-04-27T08:21:32.000Z'), y: 2 },
+ { x: new Date('2017-04-30T23:06:24.000Z'), y: 2 }
]
}
])
@@ -284,7 +281,7 @@ describe('hasHistoryData', () => {
{
name: 'bar',
type: 'INT',
- data: [{ x: new Date('2017-04-27T08:21:32+0200'), y: 2 }]
+ data: [{ x: new Date('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 4e5be7ea5db..044b1462323 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
@@ -18,7 +18,6 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import React from 'react';
-import moment from 'moment';
import { isEqual, sortBy } from 'lodash';
import DeferredSpinner from '../../../components/common/DeferredSpinner';
import GraphHistory from './GraphHistory';
@@ -87,7 +86,7 @@ export default class GraphsHistory extends React.PureComponent {
return acc.concat({
className: event.category,
name: event.name,
- date: moment(analysis.date).toDate()
+ date: new Date(analysis.date)
});
}, []);
return sortBy(filteredEvents, 'date');
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsTooltips.js b/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsTooltips.js
index 4eb0e719a28..320f934e028 100644
--- a/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsTooltips.js
+++ b/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsTooltips.js
@@ -20,7 +20,7 @@
// @flow
import React from 'react';
import BubblePopup from '../../../components/common/BubblePopup';
-import FormattedDate from '../../../components/ui/FormattedDate';
+import DateTimeFormatter from '../../../components/intl/DateTimeFormatter';
import GraphsTooltipsContent from './GraphsTooltipsContent';
import GraphsTooltipsContentEvents from './GraphsTooltipsContentEvents';
import GraphsTooltipsContentCoverage from './GraphsTooltipsContentCoverage';
@@ -98,7 +98,7 @@ export default class GraphsTooltips extends React.PureComponent {
<BubblePopup customClass={customClass} position={{ top, left, width: TOOLTIP_WIDTH }}>
<div className="project-activity-graph-tooltip">
<div className="project-activity-graph-tooltip-title spacer-bottom">
- <FormattedDate date={this.props.selectedDate} format="LL" />
+ <DateTimeFormatter date={this.props.selectedDate} />
</div>
<table className="width-100">
<tbody>
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 7f69288c33d..7b94b01483c 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
@@ -20,10 +20,9 @@
// @flow
import React from 'react';
import classNames from 'classnames';
-import moment from 'moment';
import { throttle } from 'lodash';
import ProjectActivityAnalysis from './ProjectActivityAnalysis';
-import FormattedDate from '../../../components/ui/FormattedDate';
+import DateFormatter from '../../../components/intl/DateFormatter';
import { translate } from '../../../helpers/l10n';
import {
activityQueryChanged,
@@ -191,12 +190,9 @@ export default class ProjectActivityAnalysesList extends React.PureComponent {
</div>}
<ul className="project-activity-days-list">
{days.map(day =>
- <li
- key={day}
- className="project-activity-day"
- data-day={moment(Number(day)).format('YYYY-MM-DD')}>
+ <li key={day} className="project-activity-day">
<div className="project-activity-date">
- <FormattedDate date={Number(day)} format="LL" />
+ <DateFormatter date={Number(day)} long={true} />
</div>
<ul className="project-activity-analyses-list">
{version.byDay[day] != null &&
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAnalysis.js b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAnalysis.js
index f52a59b5943..bc17b6a46b6 100644
--- a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAnalysis.js
+++ b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAnalysis.js
@@ -23,7 +23,7 @@ import classNames from 'classnames';
import Events from './Events';
import AddEventForm from './forms/AddEventForm';
import RemoveAnalysisForm from './forms/RemoveAnalysisForm';
-import FormattedDate from '../../../components/ui/FormattedDate';
+import TimeTooltipFormatter from '../../../components/intl/TimeTooltipFormatter';
import { translate } from '../../../helpers/l10n';
/*:: import type { Analysis } from '../types'; */
@@ -65,7 +65,7 @@ export default class ProjectActivityAnalysis extends React.PureComponent {
role="listitem"
tabIndex="0">
<div className="project-activity-time spacer-right">
- <FormattedDate className="text-middle" date={date} format="LT" tooltipFormat="LTS" />
+ <TimeTooltipFormatter className="text-middle" date={date} placement="right" />
</div>
<div className="project-activity-analysis-icon big-spacer-right" title={analysisTitle} />
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 cdc41b48e99..2de698d4b52 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
@@ -20,7 +20,6 @@
// @flow
import React from 'react';
import Helmet from 'react-helmet';
-import moment from 'moment';
import ProjectActivityPageHeader from './ProjectActivityPageHeader';
import ProjectActivityAnalysesList from './ProjectActivityAnalysesList';
import ProjectActivityGraphs from './ProjectActivityGraphs';
@@ -89,7 +88,7 @@ export default function ProjectActivityApp(props /*: Props */) {
<div className="project-activity-layout-page-main">
<ProjectActivityGraphs
analyses={analyses}
- leakPeriodDate={moment(props.project.leakPeriodDate).toDate()}
+ leakPeriodDate={new Date(props.project.leakPeriodDate)}
loading={props.graphLoading}
measuresHistory={measuresHistory}
metrics={props.metrics}
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAppContainer.js b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAppContainer.js
index 61e9bd077c2..172e0d35bcf 100644
--- a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAppContainer.js
+++ b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAppContainer.js
@@ -19,7 +19,6 @@
*/
// @flow
import React from 'react';
-import moment from 'moment';
import { connect } from 'react-redux';
import { withRouter } from 'react-router';
import ProjectActivityApp from './ProjectActivityApp';
@@ -173,7 +172,7 @@ class ProjectActivityAppContainer extends React.PureComponent {
return api
.getProjectActivity({ ...parameters, ...additional })
.then(({ analyses, paging }) => ({
- analyses: analyses.map(analysis => ({ ...analysis, date: moment(analysis.date).toDate() })),
+ analyses: analyses.map(analysis => ({ ...analysis, date: new Date(analysis.date) })),
paging
}));
};
@@ -187,7 +186,7 @@ class ProjectActivityAppContainer extends React.PureComponent {
measures.map(measure => ({
metric: measure.metric,
history: measure.history.map(analysis => ({
- date: moment(analysis.date).toDate(),
+ date: new Date(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 1ece1355970..f6f85c29c9b 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,8 +19,9 @@
*/
// @flow
import React from 'react';
-import moment from 'moment';
+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 type { RawQuery } from '../../../helpers/query'; */
@@ -36,13 +37,18 @@ 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 ? moment(date).format('YYYY-MM-DD') : null);
+ formatDate = (date /*: ?Date */) =>
+ date ? this.context.intl.formatDate(date, formatterOption) : undefined;
render() {
return (
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 30864a995f9..6a0c61741f2 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,6 +20,7 @@
import React from 'react';
import { shallow } from 'enzyme';
import ProjectActivityAnalysesList from '../ProjectActivityAnalysesList';
+import * as dates from '../../../../helpers/dates';
import { DEFAULT_GRAPH } from '../../utils';
const ANALYSES = [
@@ -83,18 +84,14 @@ const DEFAULT_PROPS = {
updateQuery: () => {}
};
-jest.mock('moment', () => date => ({
- startOf: () => {
- return {
- valueOf: () => `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`
- };
- },
- toDate: () => new Date(date),
- format: format => `Formated.${format}:${date}`
-}));
-
window.Number = val => val;
+dates.startOfDay = jest.fn(date => {
+ const startDay = new Date(date);
+ startDay.setUTCHours(0, 0, 0, 0);
+ return startDay;
+});
+
it('should render correctly', () => {
expect(shallow(<ProjectActivityAnalysesList {...DEFAULT_PROPS} />)).toMatchSnapshot();
});
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 fa199664561..6b93eaae296 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
@@ -18,12 +18,12 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import React from 'react';
-import { shallow } from 'enzyme';
+import { shallowWithIntl } from '../../../../helpers/testUtils';
import ProjectActivityDateInput from '../ProjectActivityDateInput';
it('should render correctly the date inputs', () => {
expect(
- shallow(
+ shallowWithIntl(
<ProjectActivityDateInput
from={new Date('2016-10-27T12:21:15+0000')}
to={new Date('2016-12-27T12:21:15+0000')}
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/GraphsTooltips-test.js.snap b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/GraphsTooltips-test.js.snap
index aea593d413e..e2ab4b039a8 100644
--- a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/GraphsTooltips-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/GraphsTooltips-test.js.snap
@@ -17,9 +17,8 @@ exports[`should not add separators if not needed 1`] = `
<div
className="project-activity-graph-tooltip-title spacer-bottom"
>
- <FormattedDate
+ <DateTimeFormatter
date={2011-10-01T22:01:00.000Z}
- format="LL"
/>
</div>
<table
@@ -53,9 +52,8 @@ exports[`should render correctly for issues graphs 1`] = `
<div
className="project-activity-graph-tooltip-title spacer-bottom"
>
- <FormattedDate
+ <DateTimeFormatter
date={2011-10-01T22:01:00.000Z}
- format="LL"
/>
</div>
<table
@@ -109,9 +107,8 @@ exports[`should render correctly for random graphs 1`] = `
<div
className="project-activity-graph-tooltip-title spacer-bottom"
>
- <FormattedDate
+ <DateTimeFormatter
date={2011-10-25T10:27:41.000Z}
- format="LL"
/>
</div>
<table
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 32622085444..00938d611a8 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,14 +25,13 @@ exports[`should correctly filter analyses by category 1`] = `
>
<li
className="project-activity-day"
- data-day="Formated.YYYY-MM-DD:2016-9-24"
>
<div
className="project-activity-date"
>
- <FormattedDate
- date="2016-9-24"
- format="LL"
+ <DateFormatter
+ date="1477267200000"
+ long={true}
/>
</div>
<ul
@@ -95,14 +94,13 @@ exports[`should correctly filter analyses by date range 1`] = `
>
<li
className="project-activity-day"
- data-day="Formated.YYYY-MM-DD:2016-9-27"
>
<div
className="project-activity-date"
>
- <FormattedDate
- date="2016-9-27"
- format="LL"
+ <DateFormatter
+ date="1477526400000"
+ long={true}
/>
</div>
<ul
@@ -165,14 +163,13 @@ exports[`should render correctly 1`] = `
>
<li
className="project-activity-day"
- data-day="Formated.YYYY-MM-DD:2016-9-27"
>
<div
className="project-activity-date"
>
- <FormattedDate
- date="2016-9-27"
- format="LL"
+ <DateFormatter
+ date="1477526400000"
+ long={true}
/>
</div>
<ul
@@ -241,14 +238,13 @@ exports[`should render correctly 1`] = `
>
<li
className="project-activity-day"
- data-day="Formated.YYYY-MM-DD:2016-9-26"
>
<div
className="project-activity-date"
>
- <FormattedDate
- date="2016-9-26"
- format="LL"
+ <DateFormatter
+ date="1477440000000"
+ long={true}
/>
</div>
<ul
@@ -288,14 +284,13 @@ exports[`should render correctly 1`] = `
</li>
<li
className="project-activity-day"
- data-day="Formated.YYYY-MM-DD:2016-9-24"
>
<div
className="project-activity-date"
>
- <FormattedDate
- date="2016-9-24"
- format="LL"
+ <DateFormatter
+ date="1477267200000"
+ long={true}
/>
</div>
<ul
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityDateInput-test.js.snap b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityDateInput-test.js.snap
index bc15b05c60e..95d05668fef 100644
--- a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityDateInput-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityDateInput-test.js.snap
@@ -8,7 +8,7 @@ exports[`should render correctly the date inputs 1`] = `
name="from"
onChange={[Function]}
placeholder="from"
- value="2016-10-27"
+ value="10/27/2016"
/>
<DateInput
@@ -17,7 +17,7 @@ exports[`should render correctly the date inputs 1`] = `
name="to"
onChange={[Function]}
placeholder="to"
- value="2016-12-27"
+ value="12/27/2016"
/>
<button
className="spacer-left"
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/utils.js b/server/sonar-web/src/main/js/apps/projectActivity/utils.js
index 12694dba2bf..03eb0510b61 100644
--- a/server/sonar-web/src/main/js/apps/projectActivity/utils.js
+++ b/server/sonar-web/src/main/js/apps/projectActivity/utils.js
@@ -18,7 +18,6 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
// @flow
-import moment from 'moment';
import { chunk, flatMap, groupBy, isEqual, sortBy } from 'lodash';
import {
cleanQuery,
@@ -29,6 +28,7 @@ import {
serializeDate,
serializeString
} from '../../helpers/query';
+import { startOfDay } from '../../helpers/dates';
import { getLocalizedMetricName, translate } from '../../helpers/l10n';
/*:: import type { Analysis, MeasureHistory, Metric, Query } from './types'; */
/*:: import type { RawQuery } from '../../helpers/query'; */
@@ -157,7 +157,7 @@ export function getAnalysesByVersionByDay(analyses /*: Array<Analysis> */, query
acc.push(currentVersion);
}
- const day = moment(analysis.date).startOf('day').valueOf().toString();
+ const day = startOfDay(new Date(analysis.date)).getTime().toString();
let matchFilters = true;
if (query.category || query.from || query.to) {
diff --git a/server/sonar-web/src/main/js/apps/projects/components/ProjectCardLeak.js b/server/sonar-web/src/main/js/apps/projects/components/ProjectCardLeak.js
index b6af4d5cd10..695136bb6c6 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/ProjectCardLeak.js
+++ b/server/sonar-web/src/main/js/apps/projects/components/ProjectCardLeak.js
@@ -20,8 +20,9 @@
// @flow
import React from 'react';
import classNames from 'classnames';
-import moment from 'moment';
import { Link } from 'react-router';
+import { FormattedRelative } from 'react-intl';
+import DateTimeFormatter from '../../../components/intl/DateTimeFormatter.tsx';
import ProjectCardQualityGate from './ProjectCardQualityGate';
import ProjectCardLeakMeasures from './ProjectCardLeakMeasures';
import FavoriteContainer from '../../../components/controls/FavoriteContainer';
@@ -90,19 +91,19 @@ export default function ProjectCardLeak({ measures, organization, project } /*:
hasLeakPeriodStart &&
<div className="project-card-dates note text-right pull-right">
{hasLeakPeriodStart &&
- <span className="project-card-leak-date pull-right">
- {translateWithParameters(
- 'projects.leak_period_x',
- moment(project.leakPeriodDate).fromNow()
- )}
- </span>}
+ <FormattedRelative value={project.leakPeriodDate}>
+ {fromNow =>
+ <span className="project-card-leak-date pull-right">
+ {translateWithParameters('projects.leak_period_x', fromNow)}
+ </span>}
+ </FormattedRelative>}
{isProjectAnalyzed &&
- <span>
- {translateWithParameters(
- 'projects.last_analysis_on_x',
- moment(project.analysisDate).format('LLL')
- )}
- </span>}
+ <DateTimeFormatter date={project.analysisDate}>
+ {formattedDate =>
+ <span>
+ {translateWithParameters('projects.last_analysis_on_x', formattedDate)}
+ </span>}
+ </DateTimeFormatter>}
</div>}
</div>
diff --git a/server/sonar-web/src/main/js/apps/projects/components/ProjectCardOverall.js b/server/sonar-web/src/main/js/apps/projects/components/ProjectCardOverall.js
index 5d8cddae025..baea9ad442e 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/ProjectCardOverall.js
+++ b/server/sonar-web/src/main/js/apps/projects/components/ProjectCardOverall.js
@@ -20,8 +20,8 @@
// @flow
import React from 'react';
import classNames from 'classnames';
-import moment from 'moment';
import { Link } from 'react-router';
+import DateTimeFormatter from '../../../components/intl/DateTimeFormatter';
import ProjectCardQualityGate from './ProjectCardQualityGate';
import ProjectCardOverallMeasures from './ProjectCardOverallMeasures';
import FavoriteContainer from '../../../components/controls/FavoriteContainer';
@@ -87,12 +87,12 @@ export default function ProjectCardOverall({ measures, organization, project } /
</div>
{isProjectAnalyzed &&
<div className="project-card-dates note text-right">
- <span className="big-spacer-left">
- {translateWithParameters(
- 'projects.last_analysis_on_x',
- moment(project.analysisDate).format('LLL')
- )}
- </span>
+ <DateTimeFormatter date={project.analysisDate}>
+ {formattedDate =>
+ <span className="big-spacer-left">
+ {translateWithParameters('projects.last_analysis_on_x', formattedDate)}
+ </span>}
+ </DateTimeFormatter>
</div>}
</div>
diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCardLeak-test.js b/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCardLeak-test.js
index 46819f2bd13..2ac25e044ab 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCardLeak-test.js
+++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCardLeak-test.js
@@ -35,15 +35,11 @@ const MEASURES = {
new_bugs: 12
};
-jest.mock('moment', () => () => ({
- format: () => 'March 1, 2017 9:36 AM',
- fromNow: () => 'a month ago'
-}));
-
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('span').getNodes()).toHaveLength(2);
+ expect(card.find('.project-card-dates').find('FormattedRelative').getNodes()).toHaveLength(1);
+ expect(card.find('.project-card-dates').find('DateTimeFormatter').getNodes()).toHaveLength(1);
});
it('should not display analysis date or leak start date', () => {
diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCardOverall-test.js b/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCardOverall-test.js
index b6f5698f231..91144662ec5 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCardOverall-test.js
+++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCardOverall-test.js
@@ -35,11 +35,6 @@ const MEASURES = {
new_bugs: 12
};
-jest.mock('moment', () => () => ({
- format: () => 'March 1, 2017 9:36 AM',
- fromNow: () => 'a month ago'
-}));
-
it('should display analysis date (and not leak period) when defined', () => {
expect(
shallow(<ProjectCardOverall measures={{}} project={PROJECT} />)
diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ProjectCardLeak-test.js.snap b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ProjectCardLeak-test.js.snap
index cb539fbafe6..591ed49e1c8 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ProjectCardLeak-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ProjectCardLeak-test.js.snap
@@ -35,14 +35,13 @@ exports[`should display the leak measures and quality gate 1`] = `
<div
className="project-card-dates note text-right pull-right"
>
- <span
- className="project-card-leak-date pull-right"
- >
- projects.leak_period_x.a month ago
- </span>
- <span>
- projects.last_analysis_on_x.March 1, 2017 9:36 AM
- </span>
+ <FormattedRelative
+ updateInterval={10000}
+ value="2016-12-01"
+ />
+ <DateTimeFormatter
+ date="2017-01-01"
+ />
</div>
</div>
<div
diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ProjectCardOverall-test.js.snap b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ProjectCardOverall-test.js.snap
index b93bf252c31..720f0f20129 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ProjectCardOverall-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ProjectCardOverall-test.js.snap
@@ -35,11 +35,9 @@ exports[`should display the overall measures and quality gate 1`] = `
<div
className="project-card-dates note text-right"
>
- <span
- className="big-spacer-left"
- >
- projects.last_analysis_on_x.March 1, 2017 9:36 AM
- </span>
+ <DateTimeFormatter
+ date="2017-01-01"
+ />
</div>
</div>
<div
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/Changelog.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/Changelog.tsx
index 1dbfdda95fd..1e94f724259 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/Changelog.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/Changelog.tsx
@@ -19,10 +19,11 @@
*/
import * as React from 'react';
import { Link } from 'react-router';
-import * as moment from 'moment';
import ChangesList from './ChangesList';
+import DateTimeFormatter from '../../../components/intl/DateTimeFormatter';
import { translate } from '../../../helpers/l10n';
import { getRulesUrl } from '../../../helpers/urls';
+import { differenceInSeconds } from '../../../helpers/dates';
import { ProfileChangelogEvent } from '../types';
interface Props {
@@ -35,7 +36,8 @@ export default function Changelog(props: Props) {
const rows = props.events.map((event, index) => {
const prev = index > 0 ? props.events[index - 1] : null;
- const isSameDate = prev != null && moment(prev.date).diff(event.date, 'seconds') < 10;
+ const isSameDate =
+ prev != null && differenceInSeconds(new Date(prev.date), new Date(event.date)) < 10;
const isBulkChange =
prev != null &&
isSameDate &&
@@ -51,7 +53,7 @@ export default function Changelog(props: Props) {
return (
<tr key={index} className={className}>
<td className="thin nowrap">
- {!isBulkChange && moment(event.date).format('LLL')}
+ {!isBulkChange && <DateTimeFormatter date={event.date} />}
</td>
<td className="thin nowrap">
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/Changelog-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/Changelog-test.tsx
index b28f8e236e0..6272bcc2f12 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/Changelog-test.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/Changelog-test.tsx
@@ -45,7 +45,7 @@ it('should render events', () => {
it('should render event date', () => {
const events = [createEvent()];
const changelog = shallow(<Changelog events={events} organization={null} />);
- expect(changelog.text()).toContain('2016');
+ expect(changelog.find('DateTimeFormatter')).toHaveLength(1);
});
it('should render author', () => {
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileDate.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileDate.tsx
index 947b15e419c..3841c70ee0f 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileDate.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileDate.tsx
@@ -18,7 +18,9 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import * as moment from 'moment';
+import { FormattedRelative } from 'react-intl';
+import DateTimeFormatter from '../../../components/intl/DateTimeFormatter';
+import Tooltip from '../../../components/controls/Tooltip';
import { translate } from '../../../helpers/l10n';
interface Props {
@@ -27,9 +29,11 @@ interface Props {
export default function ProfileDate({ date }: Props) {
return date
- ? <span title={moment(date).format('LLL')} data-toggle="tooltip">
- {moment(date).fromNow()}
- </span>
+ ? <Tooltip overlay={<DateTimeFormatter date={date} />}>
+ <span>
+ <FormattedRelative value={date} />
+ </span>
+ </Tooltip>
: <span>
{translate('never')}
</span>;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionRules.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionRules.tsx
index 84df54ceb49..2119c23ae3e 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionRules.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionRules.tsx
@@ -19,17 +19,15 @@
*/
import * as React from 'react';
import { Link } from 'react-router';
-import * as moment from 'moment';
import { sortBy } from 'lodash';
import { searchRules } from '../../../api/rules';
import { translateWithParameters, translate } from '../../../helpers/l10n';
import { getRulesUrl } from '../../../helpers/urls';
+import { toShortNotSoISOString } from '../../../helpers/dates';
import { formatMeasure } from '../../../helpers/measures';
const RULES_LIMIT = 10;
-const PERIOD_START_MOMENT = moment().subtract(1, 'year');
-
function parseRules(r: any) {
const { rules, actives } = r;
return rules.map((rule: any) => {
@@ -55,8 +53,16 @@ interface State {
}
export default class EvolutionRules extends React.PureComponent<Props, State> {
+ periodStartDate: string;
mounted: boolean;
- state: State = {};
+
+ constructor(props: Props) {
+ super(props);
+ this.state = {};
+ const startDate = new Date();
+ startDate.setFullYear(startDate.getFullYear() - 1);
+ this.periodStartDate = toShortNotSoISOString(startDate);
+ }
componentDidMount() {
this.mounted = true;
@@ -69,7 +75,7 @@ export default class EvolutionRules extends React.PureComponent<Props, State> {
loadLatestRules() {
const data = {
- available_since: PERIOD_START_MOMENT.format('YYYY-MM-DD'),
+ available_since: this.periodStartDate,
s: 'createdAt',
asc: false,
ps: RULES_LIMIT,
@@ -92,9 +98,7 @@ export default class EvolutionRules extends React.PureComponent<Props, State> {
}
const newRulesUrl = getRulesUrl(
- {
- available_since: PERIOD_START_MOMENT.format('YYYY-MM-DD')
- },
+ { available_since: this.periodStartDate },
this.props.organization
);
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionStagnant.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionStagnant.tsx
index 578020e7129..5252d1c1840 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionStagnant.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionStagnant.tsx
@@ -18,9 +18,9 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import * as moment from 'moment';
+import DateFormatter from '../../../components/intl/DateFormatter';
import ProfileLink from '../components/ProfileLink';
-import { translate } from '../../../helpers/l10n';
+import { translate, translateWithParameters } from '../../../helpers/l10n';
import { isStagnant } from '../utils';
import { Profile } from '../types';
@@ -29,7 +29,7 @@ interface Props {
profiles: Profile[];
}
-export default function EvolutionStagnan(props: Props) {
+export default function EvolutionStagnant(props: Props) {
// TODO filter built-in out
const outdated = props.profiles.filter(isStagnant);
@@ -60,11 +60,16 @@ export default function EvolutionStagnan(props: Props) {
{profile.name}
</ProfileLink>
</div>
- <div className="note">
- {profile.languageName}
- {', '}
- updated on {moment(profile.rulesUpdatedAt).format('LL')}
- </div>
+ <DateFormatter date={profile.rulesUpdatedAt} long={true}>
+ {formattedDate =>
+ <div className="note">
+ {translateWithParameters(
+ 'quality_profiles.x_updated_on_y',
+ profile.languageName,
+ formattedDate
+ )}
+ </div>}
+ </DateFormatter>
</li>
)}
</ul>
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/utils.ts b/server/sonar-web/src/main/js/apps/quality-profiles/utils.ts
index cc7140c0fd4..d058aa01acd 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/utils.ts
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/utils.ts
@@ -18,7 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { sortBy } from 'lodash';
-import * as moment from 'moment';
+import { differenceInYears, isValidDate } from '../../helpers/dates';
import { Profile } from './types';
export function sortProfiles(profiles: Profile[]) {
@@ -65,8 +65,14 @@ export function createFakeProfile(overrides?: any) {
};
}
-export function isStagnant(profile: Profile) {
- return moment().diff(moment(profile.userUpdatedAt), 'years') >= 1;
+export function isStagnant(profile: Profile): boolean {
+ if (profile.userUpdatedAt) {
+ const updateDate = new Date(profile.userUpdatedAt);
+ if (isValidDate(updateDate)) {
+ return differenceInYears(new Date(), updateDate) >= 1;
+ }
+ }
+ return false;
}
export const getProfilesPath = (organization: string | null | undefined) =>
diff --git a/server/sonar-web/src/main/js/apps/settings/licenses/LicenseRow.js b/server/sonar-web/src/main/js/apps/settings/licenses/LicenseRow.js
index f8ef6d4c7f0..d6b26fd3a75 100644
--- a/server/sonar-web/src/main/js/apps/settings/licenses/LicenseRow.js
+++ b/server/sonar-web/src/main/js/apps/settings/licenses/LicenseRow.js
@@ -19,7 +19,7 @@
*/
import React from 'react';
import PropTypes from 'prop-types';
-import moment from 'moment';
+import DateFormatter from '../../../components/intl/DateFormatter';
import LicenseStatus from './LicenseStatus';
import LicenseChangeForm from './LicenseChangeForm';
@@ -50,7 +50,7 @@ export default class LicenseRow extends React.PureComponent {
<td className="js-expiration text-middle">
{license.expiration != null &&
<div className={license.invalidExpiration ? 'text-danger' : null}>
- {moment(license.expiration).format('LL')}
+ <DateFormatter date={license.expiration} long={true} />
</div>}
</td>
<td className="js-type text-middle">
diff --git a/server/sonar-web/src/main/js/apps/settings/licenses/__tests__/LicenseRow-test.js b/server/sonar-web/src/main/js/apps/settings/licenses/__tests__/LicenseRow-test.js
index 4d7c758d416..94e3d55b633 100644
--- a/server/sonar-web/src/main/js/apps/settings/licenses/__tests__/LicenseRow-test.js
+++ b/server/sonar-web/src/main/js/apps/settings/licenses/__tests__/LicenseRow-test.js
@@ -73,7 +73,7 @@ it('should render expiration', () => {
'.js-expiration'
);
expect(licenseExpiration.length).toBe(1);
- expect(licenseExpiration.text()).toContain('2015');
+ expect(licenseExpiration.find('DateFormatter')).toHaveLength(1);
});
it('should render invalid expiration', () => {