]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-15779 Update react-intl 9.2.2.50622
authorJeremy Davis <jeremy.davis@sonarsource.com>
Fri, 3 Dec 2021 17:13:46 +0000 (18:13 +0100)
committerPhilippe Perrin <philippe.perrin@sonarsource.com>
Wed, 15 Dec 2021 13:25:28 +0000 (14:25 +0100)
35 files changed:
server/sonar-web/package.json
server/sonar-web/src/main/js/app/components/extensions/Extension.tsx
server/sonar-web/src/main/js/app/components/extensions/__tests__/__snapshots__/ProjectAdminPageExtension-test.tsx.snap
server/sonar-web/src/main/js/app/components/extensions/__tests__/__snapshots__/ProjectPageExtension-test.tsx.snap
server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBgTaskNotif-test.tsx
server/sonar-web/src/main/js/apps/coding-rules/components/AvailableSinceFacet.tsx
server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/FacetsList-test.tsx.snap
server/sonar-web/src/main/js/apps/component-measures/components/LeakPeriodLegend.tsx
server/sonar-web/src/main/js/apps/component-measures/components/__tests__/LeakPeriodLegend-test.tsx
server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/MeasureHeader-test.tsx.snap
server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/MeasureOverview-test.tsx.snap
server/sonar-web/src/main/js/apps/issues/sidebar/CreationDateFacet.tsx
server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/CreationDateFacet-test.tsx
server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/__snapshots__/Sidebar-test.tsx.snap
server/sonar-web/src/main/js/apps/overview/branches/ProjectLeakPeriodInfo.tsx
server/sonar-web/src/main/js/apps/overview/branches/__tests__/ProjectLeakPeriodInfo-test.tsx
server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/LeakPeriodInfo-test.tsx.snap
server/sonar-web/src/main/js/apps/overview/components/LeakPeriodLegend.tsx
server/sonar-web/src/main/js/apps/overview/components/__tests__/LeakPeriodLegend-test.tsx
server/sonar-web/src/main/js/components/controls/DateInput.tsx
server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/DateInput-test.tsx.snap
server/sonar-web/src/main/js/components/intl/DateFormatter.tsx
server/sonar-web/src/main/js/components/intl/DateFromNow.tsx
server/sonar-web/src/main/js/components/intl/DateTimeFormatter.tsx
server/sonar-web/src/main/js/components/intl/TimeFormatter.tsx
server/sonar-web/src/main/js/components/intl/__mocks__/DateFromNow.tsx
server/sonar-web/src/main/js/components/intl/__tests__/DateFromNow-test.tsx
server/sonar-web/src/main/js/components/intl/__tests__/__snapshots__/DateFromNow-test.tsx.snap
server/sonar-web/src/main/js/components/intl/__tests__/__snapshots__/dateUtils-test.ts [new file with mode: 0644]
server/sonar-web/src/main/js/components/intl/dateUtils.ts [new file with mode: 0644]
server/sonar-web/src/main/js/helpers/dates.ts
server/sonar-web/src/main/js/helpers/l10n.ts
server/sonar-web/src/main/js/types/dates.ts [new file with mode: 0644]
server/sonar-web/src/main/js/types/extension.ts
server/sonar-web/yarn.lock

index 6b5f81b68b16537d2e79f23eee4415e64a161d9a..6720f9eb2e300f2f2dad93e974c3a295388e2b49 100644 (file)
@@ -33,7 +33,7 @@
     "react-dom": "16.13.0",
     "react-draggable": "4.2.0",
     "react-helmet-async": "1.0.4",
-    "react-intl": "2.8.0",
+    "react-intl": "3.12.1",
     "react-modal": "3.14.3",
     "react-redux": "5.1.1",
     "react-router": "3.2.6",
@@ -76,7 +76,6 @@
     "@types/react": "16.8.23",
     "@types/react-dom": "16.8.4",
     "@types/react-helmet": "5.0.15",
-    "@types/react-intl": "2.3.17",
     "@types/react-modal": "3.12.1",
     "@types/react-redux": "6.0.6",
     "@types/react-router": "3.0.20",
index bf72c7e3e499b94a337acce24b3f7ced1db96498..8d4e5dea4eabcdc910301221b08d9cf766bc8efe 100644 (file)
@@ -19,7 +19,7 @@
  */
 import * as React from 'react';
 import { Helmet } from 'react-helmet-async';
-import { InjectedIntlProps, injectIntl } from 'react-intl';
+import { injectIntl, WrappedComponentProps } from 'react-intl';
 import { connect } from 'react-redux';
 import { Location, Router, withRouter } from '../../../components/hoc/withRouter';
 import { getExtensionStart } from '../../../helpers/extensions';
@@ -31,7 +31,7 @@ import { ExtensionStartMethod } from '../../../types/extension';
 import * as theme from '../../theme';
 import getStore from '../../utils/getStore';
 
-interface Props extends InjectedIntlProps {
+interface Props extends WrappedComponentProps {
   currentUser: T.CurrentUser;
   extension: T.Extension;
   location: Location;
index 8b70ec45509ee171ca71928938ca8c200b0b731a..883107cc708377fa1c68c0ee87f8f8e9837766cd 100644 (file)
@@ -1,7 +1,7 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`should render correctly: extension exists 1`] = `
-<InjectIntl(withRouter(Connect(Extension)))
+<injectIntl(withRouter(Connect(Extension)))
   extension={
     Object {
       "key": "foo/bar",
index 60dcb72eb90040c9472df69a1f57e6f0f945e203..fdc4f9e95f39644b654460b6d128df9cab62cd5d 100644 (file)
@@ -1,7 +1,7 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`should render correctly 1`] = `
-<InjectIntl(withRouter(Connect(Extension)))
+<injectIntl(withRouter(Connect(Extension)))
   extension={
     Object {
       "key": "plugin-key/extension-key",
index 1cafb3663d7f3e47ec731c8cf4b44b5eda414a52..ba065029391163447ce18eb53dba576685aaa1a4 100644 (file)
@@ -279,7 +279,7 @@ it.each([
         pathname: onBackgroudTaskPage ? '/project/background_tasks' : '/foo/bar'
       })
     });
-    const messageProps = wrapper.find(FormattedMessage).props();
+    const messageProps = wrapper.find<FormattedMessage>(FormattedMessage).props();
 
     // Translation key.
     expect(messageProps.defaultMessage).toBe(expectedMessage);
index e52c20e49ff4b1ea790cb221662a9c2bf888e91b..bdf0c0507e2db908a472f323879f8b772e4eee23 100644 (file)
@@ -18,7 +18,7 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
-import { InjectedIntlProps, injectIntl } from 'react-intl';
+import { injectIntl, WrappedComponentProps } from 'react-intl';
 import DateInput from '../../../components/controls/DateInput';
 import FacetBox from '../../../components/facet/FacetBox';
 import FacetHeader from '../../../components/facet/FacetHeader';
@@ -33,7 +33,7 @@ interface Props {
   value?: Date;
 }
 
-class AvailableSinceFacet extends React.PureComponent<Props & InjectedIntlProps> {
+class AvailableSinceFacet extends React.PureComponent<Props & WrappedComponentProps> {
   handleHeaderClick = () => {
     this.props.onToggle('availableSince');
   };
index 85aaa9b4e934ba379dfb2529a3f0b0386feecfef..7b252f0158747162b8956d007bc6f0337570c08d 100644 (file)
@@ -48,7 +48,7 @@ exports[`should render correctly 1`] = `
     sansTop25Open={false}
     sonarsourceSecurityOpen={false}
   />
-  <InjectIntl(AvailableSinceFacet)
+  <injectIntl(AvailableSinceFacet)
     onChange={[MockFunction]}
     onToggle={[MockFunction]}
     open={false}
index 6cadbcfe0ca09dfc6fb474afb4967f9e87917607..419886e780dc9ef2765ac78f881631783ba03bf2 100644 (file)
@@ -20,7 +20,7 @@
 import classNames from 'classnames';
 import { differenceInDays } from 'date-fns';
 import * as React from 'react';
-import { InjectedIntlProps, injectIntl } from 'react-intl';
+import { injectIntl, WrappedComponentProps } from 'react-intl';
 import Tooltip from '../../../components/controls/Tooltip';
 import DateFormatter, { longFormatterOption } from '../../../components/intl/DateFormatter';
 import DateFromNow from '../../../components/intl/DateFromNow';
@@ -34,7 +34,7 @@ interface Props {
   period: T.Period;
 }
 
-export class LeakPeriodLegend extends React.PureComponent<Props & InjectedIntlProps> {
+export class LeakPeriodLegend extends React.PureComponent<Props & WrappedComponentProps> {
   formatDate = (date: string) => {
     return this.props.intl.formatDate(date, longFormatterOption);
   };
index e2adbbcc61d0a697971917fbf58cbc4d48818fa2..2ba3b0220a40ca935d46761af688f9b29665f1f2 100644 (file)
@@ -20,7 +20,7 @@
 import { differenceInDays } from 'date-fns';
 import { shallow } from 'enzyme';
 import * as React from 'react';
-import { InjectedIntlProps } from 'react-intl';
+import { IntlShape } from 'react-intl';
 import { LeakPeriodLegend } from '../LeakPeriodLegend';
 
 jest.mock('date-fns', () => {
@@ -72,7 +72,7 @@ function getWrapper(component: T.ComponentMeasure, period: T.Period) {
   return shallow(
     <LeakPeriodLegend
       component={component}
-      intl={{ formatDate: (x: any) => x } as InjectedIntlProps['intl']}
+      intl={{ formatDate: (x: any) => x } as IntlShape}
       period={period}
     />
   );
index 2e025bedaf58d427187357c5493020805ba5292c..643a2bb9dd83fd66b39ccb7f4bd16312a64889a7 100644 (file)
@@ -51,7 +51,7 @@ exports[`should render correctly 1`] = `
     <div
       className="measure-details-primary-actions"
     >
-      <InjectIntl(LeakPeriodLegend)
+      <injectIntl(LeakPeriodLegend)
         className="spacer-left"
         component={
           Object {
@@ -105,7 +105,7 @@ exports[`should render correctly for leak 1`] = `
     <div
       className="measure-details-primary-actions"
     >
-      <InjectIntl(LeakPeriodLegend)
+      <injectIntl(LeakPeriodLegend)
         className="spacer-left"
         component={
           Object {
@@ -159,7 +159,7 @@ exports[`should render with a branch 1`] = `
     <div
       className="measure-details-primary-actions"
     >
-      <InjectIntl(LeakPeriodLegend)
+      <injectIntl(LeakPeriodLegend)
         className="spacer-left"
         component={
           Object {
@@ -232,7 +232,7 @@ exports[`should work with measure without value 1`] = `
     <div
       className="measure-details-primary-actions"
     >
-      <InjectIntl(LeakPeriodLegend)
+      <injectIntl(LeakPeriodLegend)
         className="spacer-left"
         component={
           Object {
index 170556dc4d097351daaca9904817f2bf0eba80ef..13bfbaa05b30681c2433a170c7087c170f19579b 100644 (file)
@@ -194,7 +194,7 @@ exports[`should render correctly: has leak period 1`] = `
     <div
       className="clearfix big-spacer-bottom"
     >
-      <InjectIntl(LeakPeriodLegend)
+      <injectIntl(LeakPeriodLegend)
         className="pull-right"
         component={
           Object {
index 609f48f5e5176c6d9b9db7b5fea487e0b3b415e3..a69c5b1c7f17ab530a7281d85fa25f283ccc87ca 100644 (file)
@@ -20,7 +20,7 @@
 import { isSameDay } from 'date-fns';
 import { max } from 'lodash';
 import * as React from 'react';
-import { InjectedIntlProps, injectIntl } from 'react-intl';
+import { injectIntl, WrappedComponentProps } from 'react-intl';
 import BarChart from '../../../components/charts/BarChart';
 import DateRangeInput from '../../../components/controls/DateRangeInput';
 import FacetBox from '../../../components/facet/FacetBox';
@@ -52,7 +52,7 @@ interface Props {
   stats: T.Dict<number> | undefined;
 }
 
-export class CreationDateFacet extends React.PureComponent<Props & InjectedIntlProps> {
+export class CreationDateFacet extends React.PureComponent<Props & WrappedComponentProps> {
   property = 'createdAt';
 
   static defaultProps = {
index 2dfa5ea4b7df89ef3d48ea31b7c1a822318d64b9..c1bf31a3299a7c4ad70ebfa0b0d4e86fe704b208 100644 (file)
@@ -19,7 +19,7 @@
  */
 import { shallow } from 'enzyme';
 import * as React from 'react';
-import { InjectedIntlProps } from 'react-intl';
+import { IntlShape } from 'react-intl';
 import { mockComponent } from '../../../../helpers/mocks/component';
 import { ComponentQualifier } from '../../../../types/component';
 import { CreationDateFacet } from '../CreationDateFacet';
@@ -68,7 +68,7 @@ function shallowRender(props?: Partial<CreationDateFacet['props']>) {
       intl={
         {
           formatDate: (date: string) => 'formatted.' + date
-        } as InjectedIntlProps['intl']
+        } as IntlShape
       }
       onChange={jest.fn()}
       onToggle={jest.fn()}
index df5f5febae0689161e01d675db9a2877f619bb16..435a8ee0bcd7ebaab02265921936c9290d708014 100644 (file)
@@ -8,7 +8,7 @@ Array [
   "ResolutionFacet",
   "StatusFacet",
   "StandardFacet",
-  "InjectIntl(CreationDateFacet)",
+  "injectIntl(CreationDateFacet)",
   "Connect(LanguageFacet)",
   "RuleFacet",
   "TagFacet",
@@ -24,7 +24,7 @@ Array [
   "ResolutionFacet",
   "StatusFacet",
   "StandardFacet",
-  "InjectIntl(CreationDateFacet)",
+  "injectIntl(CreationDateFacet)",
   "Connect(LanguageFacet)",
   "RuleFacet",
   "TagFacet",
@@ -42,7 +42,7 @@ Array [
   "ResolutionFacet",
   "StatusFacet",
   "StandardFacet",
-  "InjectIntl(CreationDateFacet)",
+  "injectIntl(CreationDateFacet)",
   "Connect(LanguageFacet)",
   "RuleFacet",
   "TagFacet",
@@ -61,7 +61,7 @@ Array [
   "ResolutionFacet",
   "StatusFacet",
   "StandardFacet",
-  "InjectIntl(CreationDateFacet)",
+  "injectIntl(CreationDateFacet)",
   "Connect(LanguageFacet)",
   "RuleFacet",
   "TagFacet",
@@ -80,7 +80,7 @@ Array [
   "ResolutionFacet",
   "StatusFacet",
   "StandardFacet",
-  "InjectIntl(CreationDateFacet)",
+  "injectIntl(CreationDateFacet)",
   "Connect(LanguageFacet)",
   "RuleFacet",
   "TagFacet",
@@ -98,7 +98,7 @@ Array [
   "ResolutionFacet",
   "StatusFacet",
   "StandardFacet",
-  "InjectIntl(CreationDateFacet)",
+  "injectIntl(CreationDateFacet)",
   "Connect(LanguageFacet)",
   "RuleFacet",
   "TagFacet",
@@ -116,7 +116,7 @@ Array [
   "ResolutionFacet",
   "StatusFacet",
   "StandardFacet",
-  "InjectIntl(CreationDateFacet)",
+  "injectIntl(CreationDateFacet)",
   "Connect(LanguageFacet)",
   "RuleFacet",
   "TagFacet",
@@ -134,7 +134,7 @@ Array [
   "ResolutionFacet",
   "StatusFacet",
   "StandardFacet",
-  "InjectIntl(CreationDateFacet)",
+  "injectIntl(CreationDateFacet)",
   "Connect(LanguageFacet)",
   "RuleFacet",
   "TagFacet",
@@ -152,7 +152,7 @@ Array [
   "ResolutionFacet",
   "StatusFacet",
   "StandardFacet",
-  "InjectIntl(CreationDateFacet)",
+  "injectIntl(CreationDateFacet)",
   "Connect(LanguageFacet)",
   "RuleFacet",
   "TagFacet",
@@ -171,7 +171,7 @@ Array [
   "ResolutionFacet",
   "StatusFacet",
   "StandardFacet",
-  "InjectIntl(CreationDateFacet)",
+  "injectIntl(CreationDateFacet)",
   "Connect(LanguageFacet)",
   "RuleFacet",
   "TagFacet",
index 8c47ec3485dcfc92a19252d506eb682605e692da..1996f07ae95c0781d3c9b5919a7a34675fa96ffb 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
-import { InjectedIntl, injectIntl } from 'react-intl';
+import { injectIntl, WrappedComponentProps } from 'react-intl';
 import { longFormatterOption } from '../../../components/intl/DateFormatter';
 import DateFromNow from '../../../components/intl/DateFromNow';
 import { formatterOption } from '../../../components/intl/DateTimeFormatter';
 import { translateWithParameters } from '../../../helpers/l10n';
 import { getPeriodDate, getPeriodLabel } from '../../../helpers/periods';
 
-export interface ProjectLeakPeriodInfoProps {
-  intl: Pick<InjectedIntl, 'formatDate' | 'formatTime'>;
+export interface ProjectLeakPeriodInfoProps extends WrappedComponentProps {
   leakPeriod: T.Period;
 }
 
index eb3a9d35711299665b43b7e08dfdf437b4f84261..efe108afacdb234ba5314440988a4596ff1fc1fd 100644 (file)
@@ -20,6 +20,7 @@
 import { differenceInDays } from 'date-fns';
 import { shallow } from 'enzyme';
 import * as React from 'react';
+import { IntlShape } from 'react-intl';
 import { mockPeriod } from '../../../../helpers/testMocks';
 import { ProjectLeakPeriodInfo } from '../ProjectLeakPeriodInfo';
 
@@ -63,10 +64,12 @@ it('should render a more precise date', () => {
 function shallowRender(period: Partial<T.Period> = {}) {
   return shallow(
     <ProjectLeakPeriodInfo
-      intl={{
-        formatDate: (date: string) => 'formatted.' + date,
-        formatTime: (date: string) => 'formattedTime.' + date
-      }}
+      intl={
+        {
+          formatDate: (date: string) => 'formatted.' + date,
+          formatTime: (date: string) => 'formattedTime.' + date
+        } as IntlShape
+      }
       leakPeriod={mockPeriod({ ...period })}
     />
   );
index a6a8d910dfa866f1244264fdd539aeba517a8026..1feb0477f158a586b7fe0dbe3bbdf7079f63caf5 100644 (file)
@@ -13,7 +13,7 @@ exports[`renders correctly for applications 1`] = `
 `;
 
 exports[`renders correctly for projects 1`] = `
-<Memo(InjectIntl(ProjectLeakPeriodInfo))
+<Memo(injectIntl(ProjectLeakPeriodInfo))
   leakPeriod={
     Object {
       "date": "2019-04-23T02:12:32+0100",
index 62b725b5086bf43a2944bb241bbfb054f4bfb4f3..c07984784aa3b29f27f1b405efbe0850b3901466 100644 (file)
@@ -19,7 +19,7 @@
  */
 import { differenceInDays } from 'date-fns';
 import * as React from 'react';
-import { InjectedIntlProps, injectIntl } from 'react-intl';
+import { injectIntl, WrappedComponentProps } from 'react-intl';
 import Tooltip from '../../../components/controls/Tooltip';
 import DateFormatter, { longFormatterOption } from '../../../components/intl/DateFormatter';
 import DateFromNow from '../../../components/intl/DateFromNow';
@@ -36,7 +36,7 @@ const MODE_INCLUDES_TIME: T.Dict<boolean> = {
   SPECIFIC_ANALYSIS: true
 };
 
-export class LeakPeriodLegend extends React.PureComponent<Props & InjectedIntlProps> {
+export class LeakPeriodLegend extends React.PureComponent<Props & WrappedComponentProps> {
   formatDate = (date: string) => {
     return this.props.intl.formatDate(date, longFormatterOption);
   };
index b1ee6be8e1e6381cf9d0957e29e167c7ae8be1c5..76929c951e99ac1de1a0d72d089705816b1a8e0f 100644 (file)
@@ -20,7 +20,7 @@
 import { differenceInDays } from 'date-fns';
 import { shallow } from 'enzyme';
 import * as React from 'react';
-import { InjectedIntlProps } from 'react-intl';
+import { IntlShape } from 'react-intl';
 import { LeakPeriodLegend } from '../LeakPeriodLegend';
 
 jest.mock('date-fns', () => {
@@ -67,7 +67,7 @@ function getWrapper(period: Partial<T.Period> = {}) {
         {
           formatDate: (date: string) => 'formatted.' + date,
           formatTime: (date: string) => 'formattedTime.' + date
-        } as InjectedIntlProps['intl']
+        } as IntlShape
       }
       period={{
         date: '2013-09-22T00:00:00+0200',
index b484e952e471239c4683239b15e71c684ef50489..df8906c3038ae74d8242164e6032a1e506224674 100644 (file)
@@ -22,7 +22,7 @@ import { addMonths, setMonth, setYear, subMonths } from 'date-fns';
 import { range } from 'lodash';
 import * as React from 'react';
 import { DayModifiers, Modifier, Modifiers } from 'react-day-picker';
-import { InjectedIntlProps, injectIntl } from 'react-intl';
+import { injectIntl, WrappedComponentProps } from 'react-intl';
 import { ButtonIcon, ClearButton } from '../../components/controls/buttons';
 import OutsideClickHandler from '../../components/controls/OutsideClickHandler';
 import Select from '../../components/controls/Select';
@@ -149,7 +149,7 @@ export default class DateInput extends React.PureComponent<Props, State> {
             className={classNames('date-input-control-input', this.props.inputClassName, {
               'is-filled': this.props.value !== undefined
             })}
-            innerRef={node => (this.input = node)}
+            innerRef={(node: HTMLInputElement | null) => (this.input = node)}
             name={this.props.name}
             onFocus={this.openCalendar}
             placeholder={this.props.placeholder}
@@ -218,7 +218,7 @@ function NullComponent() {
 }
 
 type InputWrapperProps = T.Omit<React.InputHTMLAttributes<HTMLInputElement>, 'value'> &
-  InjectedIntlProps & {
+  WrappedComponentProps & {
     innerRef: React.Ref<HTMLInputElement>;
     value: Date | undefined;
   };
index 5b49a50d0f5730054590dcad089bec00487d6340..9ed742f24de5ed8843011b30330fe12622dd2424 100644 (file)
@@ -7,7 +7,7 @@ exports[`should render 1`] = `
   <span
     className="date-input-control"
   >
-    <InjectIntl(Component)
+    <injectIntl(Component)
       className="date-input-control-input"
       innerRef={[Function]}
       onFocus={[Function]}
@@ -30,7 +30,7 @@ exports[`should render 2`] = `
   <span
     className="date-input-control"
   >
-    <InjectIntl(Component)
+    <injectIntl(Component)
       className="date-input-control-input is-filled"
       innerRef={[Function]}
       onFocus={[Function]}
@@ -63,7 +63,7 @@ exports[`should render 3`] = `
   <span
     className="date-input-control"
   >
-    <InjectIntl(Component)
+    <injectIntl(Component)
       className="date-input-control-input is-filled"
       innerRef={[Function]}
       onFocus={[Function]}
@@ -271,7 +271,7 @@ exports[`should select a day 1`] = `
   <span
     className="date-input-control"
   >
-    <InjectIntl(Component)
+    <injectIntl(Component)
       className="date-input-control-input"
       innerRef={[Function]}
       onFocus={[Function]}
index c33b8a78ff57ba9ec4877d2c52598352754b3387..ff5ed29959461c81080727cd90f1458e55343045 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
-import { DateSource, FormattedDate } from 'react-intl';
+import { FormatDateOptions, FormattedDate } from 'react-intl';
 import { parseDate } from '../../helpers/dates';
+import { ParsableDate } from '../../types/dates';
 
 export interface DateFormatterProps {
   children?: (formattedDate: string) => React.ReactNode;
-  date: DateSource;
+  date: ParsableDate;
   long?: boolean;
 }
 
-export const formatterOption = { year: 'numeric', month: 'short', day: '2-digit' };
+export const formatterOption: FormatDateOptions = {
+  year: 'numeric',
+  month: 'short',
+  day: '2-digit'
+};
 
-export const longFormatterOption = { year: 'numeric', month: 'long', day: 'numeric' };
+export const longFormatterOption: FormatDateOptions = {
+  year: 'numeric',
+  month: 'long',
+  day: 'numeric'
+};
 
 export default function DateFormatter({ children, date, long }: DateFormatterProps) {
   return (
index 713b31fdf8d9ebaa75832d4a46339721be8aa975..13fc3d407a66e8359ff0f1f1cc74f7205273ef39 100644 (file)
  */
 import { differenceInHours } from 'date-fns';
 import * as React from 'react';
-import { DateSource, FormattedRelative } from 'react-intl';
+import { FormattedRelativeTime } from 'react-intl';
 import { parseDate } from '../../helpers/dates';
 import { translate } from '../../helpers/l10n';
+import { ParsableDate } from '../../types/dates';
 import DateTimeFormatter from './DateTimeFormatter';
+import { getRelativeTimeProps } from './dateUtils';
 
 export interface DateFromNowProps {
   children?: (formattedDate: string) => React.ReactNode;
-  date?: DateSource;
+  date?: ParsableDate;
   hourPrecision?: boolean;
 }
 
@@ -43,17 +45,21 @@ export default function DateFromNow(props: DateFromNowProps) {
     return <>{originalChildren(translate('never'))}</>;
   }
 
-  if (date && hourPrecision && differenceInHours(Date.now(), date) < 1) {
+  if (hourPrecision && differenceInHours(Date.now(), date) < 1) {
     children = () => originalChildren(translate('less_than_1_hour_ago'));
   }
 
   const parsedDate = parseDate(date);
 
+  const relativeTimeProps = getRelativeTimeProps(date);
+
   return (
     <DateTimeFormatter date={parsedDate}>
       {formattedDate => (
         <span title={formattedDate}>
-          <FormattedRelative value={parsedDate}>{children}</FormattedRelative>
+          <FormattedRelativeTime {...relativeTimeProps}>
+            {children as FormattedRelativeTime['props']['children']}
+          </FormattedRelativeTime>
         </span>
       )}
     </DateTimeFormatter>
index 64394b80c5821fd1fc4d4d0f2a33add3ed1e8ba7..8390bfbfca15b0cb9bad69a250f2bdcfc966e7aa 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
-import { DateSource, FormattedDate } from 'react-intl';
+import { FormatDateOptions, FormattedDate } from 'react-intl';
 import { parseDate } from '../../helpers/dates';
+import { ParsableDate } from '../../types/dates';
 
 interface Props {
   children?: (formattedDate: string) => React.ReactNode;
-  date: DateSource;
+  date: ParsableDate;
 }
 
-export const formatterOption = {
+export const formatterOption: FormatDateOptions = {
   year: 'numeric',
   month: 'long',
   day: 'numeric',
index 8fb5af054400a99cb7d5818d57b649e7aad07940..d35bcd966e6240272f82553ebcdad28c4ff913f4 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
-import { DateSource, FormattedTime } from 'react-intl';
+import { FormatDateOptions, FormattedTime } from 'react-intl';
 import { parseDate } from '../../helpers/dates';
+import { ParsableDate } from '../../types/dates';
 
 export interface TimeFormatterProps {
   children?: (formattedDate: string) => React.ReactNode;
-  date: DateSource;
+  date: ParsableDate;
   long?: boolean;
 }
 
-export const formatterOption = { hour: 'numeric', minute: 'numeric' };
+export const formatterOption: FormatDateOptions = { hour: 'numeric', minute: 'numeric' };
 
-export const longFormatterOption = { hour: 'numeric', minute: 'numeric', second: 'numeric' };
+export const longFormatterOption: FormatDateOptions = {
+  hour: 'numeric',
+  minute: 'numeric',
+  second: 'numeric'
+};
 
 export default function TimeFormatter({ children, date, long }: TimeFormatterProps) {
   return (
index 76a585b404501c684dabcc9ecc017327fbb54854..b06a43ee32944b1b69e4ec98e439c6f5865df7f5 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
-import { DateSource } from 'react-intl';
+import { ParsableDate } from '../../../types/dates';
 
 interface Props {
   children?: (formattedDate: string) => React.ReactNode;
-  date: DateSource;
+  date: ParsableDate;
 }
 
 export default function DateFromNow({ children, date }: Props) {
index 901b5cbba0c2cc9133f777d4b5ddf0bc521c5520..216daccdeb04c1f2ba3d969ebe8f5aa9ef6d0638 100644 (file)
  */
 import { shallow } from 'enzyme';
 import * as React from 'react';
-import { FormattedRelative, IntlProvider } from 'react-intl';
+import { FormattedRelativeTime, IntlProvider } from 'react-intl';
 import DateFromNow, { DateFromNowProps } from '../DateFromNow';
 import DateTimeFormatter from '../DateTimeFormatter';
 
 const date = '2020-02-20T20:20:20Z';
 
+jest.mock('../dateUtils', () => ({
+  getRelativeTimeProps: jest.fn().mockReturnValue({ value: -1, unit: 'year' })
+}));
+
 it('should render correctly', () => {
   const wrapper = shallowRender();
 
@@ -43,24 +47,30 @@ it('should render correctly when there is no date', () => {
 it('should render correctly when the date is less than one hour in the past', () => {
   const veryCloseDate = new Date(date);
   veryCloseDate.setMinutes(veryCloseDate.getMinutes() - 10);
-  jest.spyOn(Date, 'now').mockImplementation(() => (new Date(date) as unknown) as number);
+  const mockDateNow = jest
+    .spyOn(Date, 'now')
+    .mockImplementation(() => (new Date(date) as unknown) as number);
   const children = jest.fn();
 
   shallowRender({ date: veryCloseDate, hourPrecision: true }, children)
-    .dive()
-    .dive()
-    .find(FormattedRelative)
+    .dive() // into DateTimeFormatter
+    .dive() // into DateFormatter
+    .dive() // into rendering function
+    .find(FormattedRelativeTime)
     .props().children!(date);
 
   expect(children).toHaveBeenCalledWith('less_than_1_hour_ago');
+  mockDateNow.mockRestore();
 });
 
 function shallowRender(overrides: Partial<DateFromNowProps> = {}, children: jest.Mock = jest.fn()) {
-  return shallow<DateFromNowProps>(
+  return shallow(
     <IntlProvider defaultLocale="en-US" locale="en">
       <DateFromNow date={date} {...overrides}>
         {formattedDate => children(formattedDate)}
       </DateFromNow>
     </IntlProvider>
-  ).dive();
+  )
+    .dive() // into the ContextProvider generated by IntlProvider
+    .dive(); // into the DateFromNow we actually want to render
 }
index 19ee5460047a7f5497d09a4d594b747bb1683f7a..f893ec98cf7631dc9bb30382d04010d4c110b631 100644 (file)
@@ -12,11 +12,11 @@ exports[`should render correctly: children 1`] = `
 <span
   title="2020-02-20T20:20:20Z"
 >
-  <FormattedRelative
-    updateInterval={10000}
-    value={2020-02-20T20:20:20.000Z}
+  <FormattedRelativeTime
+    unit="year"
+    value={-1}
   >
     [Function]
-  </FormattedRelative>
+  </FormattedRelativeTime>
 </span>
 `;
diff --git a/server/sonar-web/src/main/js/components/intl/__tests__/__snapshots__/dateUtils-test.ts b/server/sonar-web/src/main/js/components/intl/__tests__/__snapshots__/dateUtils-test.ts
new file mode 100644 (file)
index 0000000..b5187f3
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+import { getRelativeTimeProps } from '../../dateUtils';
+
+const mockDateNow = jest.spyOn(Date, 'now');
+
+describe('getRelativeTimeProps', () => {
+  mockDateNow.mockImplementation(() => new Date('2021-02-20T20:20:20Z').getTime());
+
+  it.each([
+    ['year', '2020-02-19T20:20:20Z', -1],
+    ['month', '2020-11-18T20:20:20Z', -3],
+    ['day', '2021-02-18T18:20:20Z', -2]
+  ])('should return the correct props for dates older than a %s', (unit, date, value) => {
+    expect(getRelativeTimeProps(date)).toEqual({ value, unit });
+  });
+
+  it('should return the correct props for dates from less than a day ago', () => {
+    expect(getRelativeTimeProps('2021-02-20T20:19:45Z')).toEqual({
+      value: -35,
+      unit: 'second',
+      updateIntervalInSeconds: 10
+    });
+  });
+});
diff --git a/server/sonar-web/src/main/js/components/intl/dateUtils.ts b/server/sonar-web/src/main/js/components/intl/dateUtils.ts
new file mode 100644 (file)
index 0000000..390d9d7
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+import {
+  differenceInDays,
+  differenceInMonths,
+  differenceInSeconds,
+  differenceInYears
+} from 'date-fns';
+import { FormattedRelativeTime } from 'react-intl';
+import { ParsableDate } from '../../types/dates';
+
+const UPDATE_INTERVAL_IN_SECONDS = 10;
+
+export function getRelativeTimeProps(
+  date: ParsableDate
+): Pick<FormattedRelativeTime['props'], 'unit' | 'value' | 'updateIntervalInSeconds'> {
+  const y = differenceInYears(date, Date.now());
+
+  if (Math.abs(y) > 0) {
+    return { value: y, unit: 'year' };
+  }
+
+  const m = differenceInMonths(date, Date.now());
+  if (Math.abs(m) > 0) {
+    return { value: m, unit: 'month' };
+  }
+
+  const d = differenceInDays(date, Date.now());
+  if (Math.abs(d) > 0) {
+    return { value: d, unit: 'day' };
+  }
+
+  return {
+    value: differenceInSeconds(date, Date.now()),
+    unit: 'second',
+    updateIntervalInSeconds: UPDATE_INTERVAL_IN_SECONDS
+  };
+}
index f7944f3955ab3f4c35c771b1383edc48d505ba7b..1e1b23d5d78a7e38ed9fbb989832f5bd67890769 100644 (file)
@@ -18,6 +18,7 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import { parse } from 'date-fns';
+import { ParsableDate } from '../types/dates';
 
 function pad(number: number) {
   if (number < 10) {
@@ -26,8 +27,6 @@ function pad(number: number) {
   return number;
 }
 
-type ParsableDate = string | number | Date;
-
 export function parseDate(rawDate: ParsableDate): Date {
   return parse(rawDate);
 }
index a96f34682c26dd99f717ef470d5ebdfc78972148..a57732333ca7257a32976b3bf013e96738da482a 100644 (file)
@@ -147,16 +147,6 @@ export async function loadL10nBundle() {
   resetCurrentLocale(bundle.locale);
   resetMessages(bundle.messages);
 
-  // No need to load english (default) bundle, it's coming with react-intl
-  if (bundle.locale !== DEFAULT_LOCALE) {
-    const [intlBundle, intl] = await Promise.all([
-      import(`react-intl/locale-data/${bundle.locale}`),
-      import('react-intl')
-    ]);
-
-    intl.addLocaleData(intlBundle.default);
-  }
-
   return bundle;
 }
 
diff --git a/server/sonar-web/src/main/js/types/dates.ts b/server/sonar-web/src/main/js/types/dates.ts
new file mode 100644 (file)
index 0000000..8b22146
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+export type ParsableDate = string | number | Date;
index 624da3e779308297be93669fe634cc6fa1fa7638..38d0432c26710eea822e20dd4f4ba1551a73a8fd 100644 (file)
@@ -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 { InjectedIntl } from 'react-intl';
+import { IntlShape } from 'react-intl';
 import { Store as ReduxStore } from 'redux';
 import { Location, Router } from '../components/hoc/withRouter';
 import { Store } from '../store/rootReducer';
@@ -35,7 +35,7 @@ export interface ExtensionStartMethodParameter {
   store: ReduxStore<Store, any>;
   el: HTMLElement | undefined | null;
   currentUser: T.CurrentUser;
-  intl: InjectedIntl;
+  intl: IntlShape;
   location: Location;
   router: Router;
   theme: {
index df07f16390b1704b6caa53484d9336a091403ba7..d0e643a4ec08e272a13788509285fd48c587c3a1 100644 (file)
@@ -1891,6 +1891,49 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@formatjs/intl-displaynames@npm:^1.2.0":
+  version: 1.2.10
+  resolution: "@formatjs/intl-displaynames@npm:1.2.10"
+  dependencies:
+    "@formatjs/intl-utils": ^2.3.0
+  checksum: 25320e00c383260c1c3c44bd8be017b8ebd1b1b7de4188d05934aa40b65adda02b102eba46bf4e01e06f9db79d2d8663a720afe7f2ee69495a3022055bea4810
+  languageName: node
+  linkType: hard
+
+"@formatjs/intl-listformat@npm:^1.4.1":
+  version: 1.4.8
+  resolution: "@formatjs/intl-listformat@npm:1.4.8"
+  dependencies:
+    "@formatjs/intl-utils": ^2.3.0
+  checksum: 1e5b2ef45b7e0143fb4c809178aed00ad1d1dfbcba25c339bf54bdd5e35acee6c72a25bd30189812a3211103a58a7e0800e49bc3e973f89bc5e80c41da38f6e1
+  languageName: node
+  linkType: hard
+
+"@formatjs/intl-relativetimeformat@npm:^4.5.9":
+  version: 4.5.16
+  resolution: "@formatjs/intl-relativetimeformat@npm:4.5.16"
+  dependencies:
+    "@formatjs/intl-utils": ^2.3.0
+  checksum: 466268cb4f3c326b222cc0f79b176949d4cc79e29d11fe6e8d003b89b3495018728d55ba25189f3856b88c0f5657a57365f039504c32ea78a8fb555ff80e9580
+  languageName: node
+  linkType: hard
+
+"@formatjs/intl-unified-numberformat@npm:^3.2.0":
+  version: 3.3.7
+  resolution: "@formatjs/intl-unified-numberformat@npm:3.3.7"
+  dependencies:
+    "@formatjs/intl-utils": ^2.3.0
+  checksum: dae9c855d8b36b833ee9a71e63b13240dabc9b84ed13192411f06ac903a5c2fb002fd4736d7b71df73c4c776792255c7b2deedb94c5cddc12967fcb7c14f6133
+  languageName: node
+  linkType: hard
+
+"@formatjs/intl-utils@npm:^2.2.0, @formatjs/intl-utils@npm:^2.3.0":
+  version: 2.3.0
+  resolution: "@formatjs/intl-utils@npm:2.3.0"
+  checksum: a7a6339dac796bccd738b3f0425863c79951156c5b61ed804869bd2ba064544badf3ec0bad576eb56fdbaf11585d99b8a089522a9b5829ba0f99a85d33222cfb
+  languageName: node
+  linkType: hard
+
 "@gar/promisify@npm:^1.0.1":
   version: 1.1.2
   resolution: "@gar/promisify@npm:1.1.2"
@@ -2465,6 +2508,16 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@types/hoist-non-react-statics@npm:^3.3.1":
+  version: 3.3.1
+  resolution: "@types/hoist-non-react-statics@npm:3.3.1"
+  dependencies:
+    "@types/react": "*"
+    hoist-non-react-statics: ^3.3.0
+  checksum: 2c0778570d9a01d05afabc781b32163f28409bb98f7245c38d5eaf082416fdb73034003f5825eb5e21313044e8d2d9e1f3fe2831e345d3d1b1d20bcd12270719
+  languageName: node
+  linkType: hard
+
 "@types/htmlparser2@npm:*":
   version: 3.10.0
   resolution: "@types/htmlparser2@npm:3.10.0"
@@ -2476,6 +2529,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@types/invariant@npm:^2.2.31":
+  version: 2.2.35
+  resolution: "@types/invariant@npm:2.2.35"
+  checksum: af1b624057c89789ed0917838fea3d42bb0c101cc22b829a24d8777c678be3bc79d6ae05992a13bdf607b94731262467a2e62a809602ea1f7eea5e8c2242660d
+  languageName: node
+  linkType: hard
+
 "@types/istanbul-lib-coverage@npm:*, @types/istanbul-lib-coverage@npm:^2.0.0, @types/istanbul-lib-coverage@npm:^2.0.1":
   version: 2.0.1
   resolution: "@types/istanbul-lib-coverage@npm:2.0.1"
@@ -2623,13 +2683,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@types/react-intl@npm:2.3.17":
-  version: 2.3.17
-  resolution: "@types/react-intl@npm:2.3.17"
-  checksum: 6d6169a7d41d87552074bfdf0f42ee229b7f48eb9bc1d99205c39693bdc006cbb2a5790954c2087cbe4ca20cf027e992bfe60de8ae9e15d71700e8742541b470
-  languageName: node
-  linkType: hard
-
 "@types/react-modal@npm:3.12.1":
   version: 3.12.1
   resolution: "@types/react-modal@npm:3.12.1"
@@ -2872,7 +2925,6 @@ __metadata:
     "@types/react": 16.8.23
     "@types/react-dom": 16.8.4
     "@types/react-helmet": 5.0.15
-    "@types/react-intl": 2.3.17
     "@types/react-modal": 3.12.1
     "@types/react-redux": 6.0.6
     "@types/react-router": 3.0.20
@@ -2942,7 +2994,7 @@ __metadata:
     react-dom: 16.13.0
     react-draggable: 4.2.0
     react-helmet-async: 1.0.4
-    react-intl: 2.8.0
+    react-intl: 3.12.1
     react-modal: 3.14.3
     react-redux: 5.1.1
     react-router: 3.2.6
@@ -7192,7 +7244,7 @@ fsevents@~2.3.2:
   languageName: node
   linkType: hard
 
-"hoist-non-react-statics@npm:^3.3.2":
+"hoist-non-react-statics@npm:^3.3.0, hoist-non-react-statics@npm:^3.3.2":
   version: 3.3.2
   resolution: "hoist-non-react-statics@npm:3.3.2"
   dependencies:
@@ -7526,39 +7578,33 @@ fsevents@~2.3.2:
   languageName: node
   linkType: hard
 
-"intl-format-cache@npm:^2.0.5":
-  version: 2.2.9
-  resolution: "intl-format-cache@npm:2.2.9"
-  checksum: 70ebb4fe2e3005d718562eff56a9f19d29ace8f51d6e549abe57ac9bd8a6791ace905f7d0d2a870236552746eff24793e782d64a3d29b93d3ff2e9bca0e3d6d8
-  languageName: node
-  linkType: hard
-
-"intl-messageformat-parser@npm:1.4.0":
-  version: 1.4.0
-  resolution: "intl-messageformat-parser@npm:1.4.0"
-  checksum: 0606b78523a9730b47292dbf1f1835e189120cd91aa742d1c0925ce0925fb067233fc74ec259a20d7810f5a1a0bd801f5884fe04493082596cf578bfeafa34c6
+"intl-format-cache@npm:^4.2.21":
+  version: 4.3.1
+  resolution: "intl-format-cache@npm:4.3.1"
+  checksum: d55581edaba0d083a3ff26a46e2ed953c434420918e61991db78140e3e0a7db14f924f195fcd0c01cf3de65cb18dda0c549d35f683e01dd8f062d27fe0524fae
   languageName: node
   linkType: hard
 
-"intl-messageformat@npm:^2.0.0, intl-messageformat@npm:^2.1.0":
-  version: 2.2.0
-  resolution: "intl-messageformat@npm:2.2.0"
+"intl-messageformat-parser@npm:^3.6.4":
+  version: 3.6.4
+  resolution: "intl-messageformat-parser@npm:3.6.4"
   dependencies:
-    intl-messageformat-parser: 1.4.0
-  checksum: 5562de75dddae69546180403fec196ed6564d41cb82964de8e319bd9fa9edfe5aaa581bc40775815b65fbdab3db96b62bb0757c2a936ac025e705333e4bd82cd
+    "@formatjs/intl-unified-numberformat": ^3.2.0
+  checksum: 69e781b6fec47f1fe5b2dc9abba79ac74b8cb4e9b40da4acc3ef2e9c6140d3d90070fd2c055d16e48c3a8bce626bb1f547ad1e29df772aff468a377658e70e6e
   languageName: node
   linkType: hard
 
-"intl-relativeformat@npm:^2.1.0":
-  version: 2.2.0
-  resolution: "intl-relativeformat@npm:2.2.0"
+"intl-messageformat@npm:^7.8.4":
+  version: 7.8.4
+  resolution: "intl-messageformat@npm:7.8.4"
   dependencies:
-    intl-messageformat: ^2.0.0
-  checksum: 887862279d7ad415f9fefa59b5abb48878f08214b7d4592e4834c956e5317b258d1103ba1c353284c213dcc574a98b5f65075323f50c94632ec79f7c5cb5c2cd
+    intl-format-cache: ^4.2.21
+    intl-messageformat-parser: ^3.6.4
+  checksum: a24fd5763c3aae450d97c4a67d95618d791f7a564996cbf6f1c4c5433c3c6fe0c141d967f94775bf9c0e70ce7791c66854987fa03a99a57f10c96186ddd90658
   languageName: node
   linkType: hard
 
-"invariant@npm:^2.1.1, invariant@npm:^2.2.1, invariant@npm:^2.2.2, invariant@npm:^2.2.4":
+"invariant@npm:^2.2.1, invariant@npm:^2.2.2, invariant@npm:^2.2.4":
   version: 2.2.4
   resolution: "invariant@npm:2.2.4"
   dependencies:
@@ -11513,19 +11559,25 @@ fsevents@~2.3.2:
   languageName: node
   linkType: hard
 
-"react-intl@npm:2.8.0":
-  version: 2.8.0
-  resolution: "react-intl@npm:2.8.0"
-  dependencies:
-    hoist-non-react-statics: ^2.5.5
-    intl-format-cache: ^2.0.5
-    intl-messageformat: ^2.1.0
-    intl-relativeformat: ^2.1.0
-    invariant: ^2.1.1
+"react-intl@npm:3.12.1":
+  version: 3.12.1
+  resolution: "react-intl@npm:3.12.1"
+  dependencies:
+    "@formatjs/intl-displaynames": ^1.2.0
+    "@formatjs/intl-listformat": ^1.4.1
+    "@formatjs/intl-relativetimeformat": ^4.5.9
+    "@formatjs/intl-unified-numberformat": ^3.2.0
+    "@formatjs/intl-utils": ^2.2.0
+    "@types/hoist-non-react-statics": ^3.3.1
+    "@types/invariant": ^2.2.31
+    hoist-non-react-statics: ^3.3.2
+    intl-format-cache: ^4.2.21
+    intl-messageformat: ^7.8.4
+    intl-messageformat-parser: ^3.6.4
+    shallow-equal: ^1.2.1
   peerDependencies:
-    prop-types: ^15.5.4
-    react: ^0.14.9 || ^15.0.0 || ^16.0.0
-  checksum: c23ff0b895af8c563435ccace81d8eb32c27e078fad9cf10a44f4409b53c9e4eab08ec7ebc25a17a0ff60d8542b745aff8ee3c323aeaf6ed2dae1b27d7d47840
+    react: ^16.3.0
+  checksum: 4a9e9101d8d5bd60c73713b99bdad2deb2b6b21fd953f16165b5c4be64aafd503418e009736ba986ca75756c08ad41b80991090e222d80b2bebfefb027bf11eb
   languageName: node
   linkType: hard
 
@@ -12567,6 +12619,13 @@ resolve@^1.2.0:
   languageName: node
   linkType: hard
 
+"shallow-equal@npm:^1.2.1":
+  version: 1.2.1
+  resolution: "shallow-equal@npm:1.2.1"
+  checksum: 4f1645cc516e7754c4438db687e1da439a5f29a7dba2ba90c5f88e5708aeb17bc4355ba45cad805b0e95dc898e37d8bf6d77d854919c7512f89939986cff8cd1
+  languageName: node
+  linkType: hard
+
 "shallowequal@npm:^1.1.0":
   version: 1.1.0
   resolution: "shallowequal@npm:1.1.0"