diff options
author | Jeremy Davis <jeremy.davis@sonarsource.com> | 2021-12-03 18:13:46 +0100 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2021-12-07 20:03:18 +0000 |
commit | 601e7fbb0ca7cd323b69742e15cd016dac46cf62 (patch) | |
tree | 5c131ac68baabe8a14f7239028e59908785071cd /server/sonar-web/src/main/js | |
parent | 05f25e35b7b489874e8c0cf24ea70196dee90ddb (diff) | |
download | sonarqube-601e7fbb0ca7cd323b69742e15cd016dac46cf62.tar.gz sonarqube-601e7fbb0ca7cd323b69742e15cd016dac46cf62.zip |
SONAR-15779 Update react-intl
Diffstat (limited to 'server/sonar-web/src/main/js')
33 files changed, 234 insertions, 92 deletions
diff --git a/server/sonar-web/src/main/js/app/components/extensions/Extension.tsx b/server/sonar-web/src/main/js/app/components/extensions/Extension.tsx index bf72c7e3e49..8d4e5dea4ea 100644 --- a/server/sonar-web/src/main/js/app/components/extensions/Extension.tsx +++ b/server/sonar-web/src/main/js/app/components/extensions/Extension.tsx @@ -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; diff --git a/server/sonar-web/src/main/js/app/components/extensions/__tests__/__snapshots__/ProjectAdminPageExtension-test.tsx.snap b/server/sonar-web/src/main/js/app/components/extensions/__tests__/__snapshots__/ProjectAdminPageExtension-test.tsx.snap index 8b70ec45509..883107cc708 100644 --- a/server/sonar-web/src/main/js/app/components/extensions/__tests__/__snapshots__/ProjectAdminPageExtension-test.tsx.snap +++ b/server/sonar-web/src/main/js/app/components/extensions/__tests__/__snapshots__/ProjectAdminPageExtension-test.tsx.snap @@ -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", diff --git a/server/sonar-web/src/main/js/app/components/extensions/__tests__/__snapshots__/ProjectPageExtension-test.tsx.snap b/server/sonar-web/src/main/js/app/components/extensions/__tests__/__snapshots__/ProjectPageExtension-test.tsx.snap index 60dcb72eb90..fdc4f9e95f3 100644 --- a/server/sonar-web/src/main/js/app/components/extensions/__tests__/__snapshots__/ProjectPageExtension-test.tsx.snap +++ b/server/sonar-web/src/main/js/app/components/extensions/__tests__/__snapshots__/ProjectPageExtension-test.tsx.snap @@ -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", diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBgTaskNotif-test.tsx b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBgTaskNotif-test.tsx index 1cafb3663d7..ba065029391 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBgTaskNotif-test.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBgTaskNotif-test.tsx @@ -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); diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/AvailableSinceFacet.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/AvailableSinceFacet.tsx index e52c20e49ff..bdf0c0507e2 100644 --- a/server/sonar-web/src/main/js/apps/coding-rules/components/AvailableSinceFacet.tsx +++ b/server/sonar-web/src/main/js/apps/coding-rules/components/AvailableSinceFacet.tsx @@ -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'); }; diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/FacetsList-test.tsx.snap b/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/FacetsList-test.tsx.snap index 85aaa9b4e93..7b252f01587 100644 --- a/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/FacetsList-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/FacetsList-test.tsx.snap @@ -48,7 +48,7 @@ exports[`should render correctly 1`] = ` sansTop25Open={false} sonarsourceSecurityOpen={false} /> - <InjectIntl(AvailableSinceFacet) + <injectIntl(AvailableSinceFacet) onChange={[MockFunction]} onToggle={[MockFunction]} open={false} diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/LeakPeriodLegend.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/LeakPeriodLegend.tsx index 6cadbcfe0ca..419886e780d 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/components/LeakPeriodLegend.tsx +++ b/server/sonar-web/src/main/js/apps/component-measures/components/LeakPeriodLegend.tsx @@ -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); }; diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/LeakPeriodLegend-test.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/LeakPeriodLegend-test.tsx index e2adbbcc61d..2ba3b0220a4 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/LeakPeriodLegend-test.tsx +++ b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/LeakPeriodLegend-test.tsx @@ -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} /> ); diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/MeasureHeader-test.tsx.snap b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/MeasureHeader-test.tsx.snap index 2e025bedaf5..643a2bb9dd8 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/MeasureHeader-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/MeasureHeader-test.tsx.snap @@ -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 { diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/MeasureOverview-test.tsx.snap b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/MeasureOverview-test.tsx.snap index 170556dc4d0..13bfbaa05b3 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/MeasureOverview-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/MeasureOverview-test.tsx.snap @@ -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 { diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/CreationDateFacet.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/CreationDateFacet.tsx index 609f48f5e51..a69c5b1c7f1 100644 --- a/server/sonar-web/src/main/js/apps/issues/sidebar/CreationDateFacet.tsx +++ b/server/sonar-web/src/main/js/apps/issues/sidebar/CreationDateFacet.tsx @@ -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 = { diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/CreationDateFacet-test.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/CreationDateFacet-test.tsx index 2dfa5ea4b7d..c1bf31a3299 100644 --- a/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/CreationDateFacet-test.tsx +++ b/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/CreationDateFacet-test.tsx @@ -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()} diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/__snapshots__/Sidebar-test.tsx.snap b/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/__snapshots__/Sidebar-test.tsx.snap index df5f5febae0..435a8ee0bcd 100644 --- a/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/__snapshots__/Sidebar-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/__snapshots__/Sidebar-test.tsx.snap @@ -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", diff --git a/server/sonar-web/src/main/js/apps/overview/branches/ProjectLeakPeriodInfo.tsx b/server/sonar-web/src/main/js/apps/overview/branches/ProjectLeakPeriodInfo.tsx index 8c47ec3485d..1996f07ae95 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/ProjectLeakPeriodInfo.tsx +++ b/server/sonar-web/src/main/js/apps/overview/branches/ProjectLeakPeriodInfo.tsx @@ -18,15 +18,14 @@ * 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; } diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/ProjectLeakPeriodInfo-test.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/ProjectLeakPeriodInfo-test.tsx index eb3a9d35711..efe108afacd 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/ProjectLeakPeriodInfo-test.tsx +++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/ProjectLeakPeriodInfo-test.tsx @@ -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 })} /> ); diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/LeakPeriodInfo-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/LeakPeriodInfo-test.tsx.snap index a6a8d910dfa..1feb0477f15 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/LeakPeriodInfo-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/LeakPeriodInfo-test.tsx.snap @@ -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", diff --git a/server/sonar-web/src/main/js/apps/overview/components/LeakPeriodLegend.tsx b/server/sonar-web/src/main/js/apps/overview/components/LeakPeriodLegend.tsx index 62b725b5086..c07984784aa 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/LeakPeriodLegend.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/LeakPeriodLegend.tsx @@ -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); }; diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/LeakPeriodLegend-test.tsx b/server/sonar-web/src/main/js/apps/overview/components/__tests__/LeakPeriodLegend-test.tsx index b1ee6be8e1e..76929c951e9 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/LeakPeriodLegend-test.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/LeakPeriodLegend-test.tsx @@ -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', diff --git a/server/sonar-web/src/main/js/components/controls/DateInput.tsx b/server/sonar-web/src/main/js/components/controls/DateInput.tsx index de7cb47b4d9..c0e0517ceeb 100644 --- a/server/sonar-web/src/main/js/components/controls/DateInput.tsx +++ b/server/sonar-web/src/main/js/components/controls/DateInput.tsx @@ -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 CalendarIcon from '../../components/icons/CalendarIcon'; @@ -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; }; diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/DateInput-test.tsx.snap b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/DateInput-test.tsx.snap index 457d6cf9d2b..0cde2461ed5 100644 --- a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/DateInput-test.tsx.snap +++ b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/DateInput-test.tsx.snap @@ -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]} diff --git a/server/sonar-web/src/main/js/components/intl/DateFormatter.tsx b/server/sonar-web/src/main/js/components/intl/DateFormatter.tsx index c33b8a78ff5..ff5ed299594 100644 --- a/server/sonar-web/src/main/js/components/intl/DateFormatter.tsx +++ b/server/sonar-web/src/main/js/components/intl/DateFormatter.tsx @@ -18,18 +18,27 @@ * 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 ( diff --git a/server/sonar-web/src/main/js/components/intl/DateFromNow.tsx b/server/sonar-web/src/main/js/components/intl/DateFromNow.tsx index 713b31fdf8d..13fc3d407a6 100644 --- a/server/sonar-web/src/main/js/components/intl/DateFromNow.tsx +++ b/server/sonar-web/src/main/js/components/intl/DateFromNow.tsx @@ -19,14 +19,16 @@ */ 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> diff --git a/server/sonar-web/src/main/js/components/intl/DateTimeFormatter.tsx b/server/sonar-web/src/main/js/components/intl/DateTimeFormatter.tsx index 64394b80c58..8390bfbfca1 100644 --- a/server/sonar-web/src/main/js/components/intl/DateTimeFormatter.tsx +++ b/server/sonar-web/src/main/js/components/intl/DateTimeFormatter.tsx @@ -18,15 +18,16 @@ * 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', diff --git a/server/sonar-web/src/main/js/components/intl/TimeFormatter.tsx b/server/sonar-web/src/main/js/components/intl/TimeFormatter.tsx index 8fb5af05440..d35bcd966e6 100644 --- a/server/sonar-web/src/main/js/components/intl/TimeFormatter.tsx +++ b/server/sonar-web/src/main/js/components/intl/TimeFormatter.tsx @@ -18,18 +18,23 @@ * 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 ( diff --git a/server/sonar-web/src/main/js/components/intl/__mocks__/DateFromNow.tsx b/server/sonar-web/src/main/js/components/intl/__mocks__/DateFromNow.tsx index 76a585b4045..b06a43ee329 100644 --- a/server/sonar-web/src/main/js/components/intl/__mocks__/DateFromNow.tsx +++ b/server/sonar-web/src/main/js/components/intl/__mocks__/DateFromNow.tsx @@ -18,11 +18,11 @@ * 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) { diff --git a/server/sonar-web/src/main/js/components/intl/__tests__/DateFromNow-test.tsx b/server/sonar-web/src/main/js/components/intl/__tests__/DateFromNow-test.tsx index 901b5cbba0c..216daccdeb0 100644 --- a/server/sonar-web/src/main/js/components/intl/__tests__/DateFromNow-test.tsx +++ b/server/sonar-web/src/main/js/components/intl/__tests__/DateFromNow-test.tsx @@ -19,12 +19,16 @@ */ 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 } diff --git a/server/sonar-web/src/main/js/components/intl/__tests__/__snapshots__/DateFromNow-test.tsx.snap b/server/sonar-web/src/main/js/components/intl/__tests__/__snapshots__/DateFromNow-test.tsx.snap index 19ee5460047..f893ec98cf7 100644 --- a/server/sonar-web/src/main/js/components/intl/__tests__/__snapshots__/DateFromNow-test.tsx.snap +++ b/server/sonar-web/src/main/js/components/intl/__tests__/__snapshots__/DateFromNow-test.tsx.snap @@ -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 index 00000000000..b5187f37959 --- /dev/null +++ b/server/sonar-web/src/main/js/components/intl/__tests__/__snapshots__/dateUtils-test.ts @@ -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 index 00000000000..390d9d729b3 --- /dev/null +++ b/server/sonar-web/src/main/js/components/intl/dateUtils.ts @@ -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 + }; +} diff --git a/server/sonar-web/src/main/js/helpers/dates.ts b/server/sonar-web/src/main/js/helpers/dates.ts index f7944f3955a..1e1b23d5d78 100644 --- a/server/sonar-web/src/main/js/helpers/dates.ts +++ b/server/sonar-web/src/main/js/helpers/dates.ts @@ -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); } diff --git a/server/sonar-web/src/main/js/helpers/l10n.ts b/server/sonar-web/src/main/js/helpers/l10n.ts index a96f34682c2..a57732333ca 100644 --- a/server/sonar-web/src/main/js/helpers/l10n.ts +++ b/server/sonar-web/src/main/js/helpers/l10n.ts @@ -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 index 00000000000..8b221464815 --- /dev/null +++ b/server/sonar-web/src/main/js/types/dates.ts @@ -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; diff --git a/server/sonar-web/src/main/js/types/extension.ts b/server/sonar-web/src/main/js/types/extension.ts index 624da3e7793..38d0432c267 100644 --- a/server/sonar-web/src/main/js/types/extension.ts +++ b/server/sonar-web/src/main/js/types/extension.ts @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { 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: { |