From 274f47473ecd3ac206cba48fdcd18e51429939e0 Mon Sep 17 00:00:00 2001 From: Jordan <51442161+JordanSh@users.noreply.github.com> Date: Wed, 13 Oct 2021 18:57:18 +0300 Subject: [PATCH] fixed super date picker crash (#5263) --- CHANGELOG.md | 4 +- .../super_date_picker/date_modes.test.ts | 9 ++++- .../super_date_picker/date_modes.ts | 6 +++ .../date_popover/relative_tab.tsx | 39 ++++++++++++++++--- .../super_date_picker/pretty_duration.ts | 6 ++- .../super_date_picker/super_date_picker.tsx | 18 ++++----- 6 files changed, 63 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ccd873cbb6a..d9cefe57ac0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ ## [`master`](https://github.com/elastic/eui/tree/master) -No public interface changes since `39.1.0`. +**Bug fixes** + +- Fixed `SuperDatePicker` from crashing due to invalid time input ([#5263](https://github.com/elastic/eui/pull/5263)) ## [`39.1.0`](https://github.com/elastic/eui/tree/v39.1.0) diff --git a/src/components/date_picker/super_date_picker/date_modes.test.ts b/src/components/date_picker/super_date_picker/date_modes.test.ts index 3134ec904ac..016340041b4 100644 --- a/src/components/date_picker/super_date_picker/date_modes.test.ts +++ b/src/components/date_picker/super_date_picker/date_modes.test.ts @@ -6,7 +6,12 @@ * Side Public License, v 1. */ -import { getDateMode, toAbsoluteString, toRelativeString } from './date_modes'; +import { + getDateMode, + INVALID_DATE, + toAbsoluteString, + toRelativeString, +} from './date_modes'; jest.mock('@elastic/datemath', () => { const moment = jest.requireActual('moment'); @@ -40,6 +45,8 @@ describe('dateMode', () => { expect(toAbsoluteString('now+y', true)).toBe('2020-03-19T00:00:00.000Z'); expect(toAbsoluteString('now-1w')).toBe('2019-03-12T00:00:00.000Z'); expect(toAbsoluteString('now-1w', true)).toBe('2019-03-12T00:00:00.000Z'); + expect(toAbsoluteString('now-999999y', true)).toBe(INVALID_DATE); // invalid time ranges cannot be parsed to ISO strings + expect(toAbsoluteString('now+999999y', true)).toBe(INVALID_DATE); }); test('toRelativeString', () => { diff --git a/src/components/date_picker/super_date_picker/date_modes.ts b/src/components/date_picker/super_date_picker/date_modes.ts index a23d6ff4078..8cf5e1388fe 100644 --- a/src/components/date_picker/super_date_picker/date_modes.ts +++ b/src/components/date_picker/super_date_picker/date_modes.ts @@ -17,6 +17,7 @@ import { NowDateMode, ShortDate, } from '../types'; +import moment from 'moment'; export const DATE_MODES: { ABSOLUTE: AbsoluteDateMode; @@ -28,6 +29,8 @@ export const DATE_MODES: { NOW: 'now', }; +export const INVALID_DATE = 'invalid_date'; + export function getDateMode(value: ShortDate) { if (value === 'now') { return DATE_MODES.NOW; @@ -45,6 +48,9 @@ export function toAbsoluteString(value: string, roundUp: boolean = false) { if (!valueAsMoment) { return value; } + if (!moment(valueAsMoment).isValid()) { + return INVALID_DATE; + } return valueAsMoment.toISOString(); } diff --git a/src/components/date_picker/super_date_picker/date_popover/relative_tab.tsx b/src/components/date_picker/super_date_picker/date_popover/relative_tab.tsx index 1bd58c13737..d613de70c58 100644 --- a/src/components/date_picker/super_date_picker/date_popover/relative_tab.tsx +++ b/src/components/date_picker/super_date_picker/date_popover/relative_tab.tsx @@ -34,6 +34,7 @@ import { EuiI18n } from '../../../i18n'; import { RelativeParts, TimeUnitId } from '../../types'; import { LocaleSpecifier } from 'moment'; // eslint-disable-line import/named import { EuiDatePopoverContentProps } from './date_popover_content'; +import { INVALID_DATE } from '../date_modes'; export interface EuiRelativeTabProps { dateFormat: string; @@ -106,16 +107,33 @@ export class EuiRelativeTab extends Component< render() { const { count, unit } = this.state; - const isInvalid = count === undefined || count < 0; + const invalidDate = this.props.value === INVALID_DATE; + const invalidValue = count === undefined || count < 0; + const isInvalid = invalidValue || invalidDate; + const parsedValue = dateMath.parse(this.props.value, { roundUp: this.props.roundUp, }); - const formatedValue = + + const formattedValue = isInvalid || !parsedValue || !parsedValue.isValid() ? '' : parsedValue .locale(this.props.locale || 'en') .format(this.props.dateFormat); + + const getErrorMessage = ({ + numberInputError, + dateInputError, + }: { + numberInputError: string; + dateInputError: string; + }) => { + if (invalidValue) return numberInputError; + if (invalidDate) return dateInputError; + return null; + }; + return ( @@ -124,13 +142,22 @@ export class EuiRelativeTab extends Component< tokens={[ 'euiRelativeTab.numberInputError', 'euiRelativeTab.numberInputLabel', + 'euiRelativeTab.dateInputError', + ]} + defaults={[ + 'Must be >= 0', + 'Time span amount', + 'Must be a valid range', ]} - defaults={['Must be >= 0', 'Time span amount']} > - {([numberInputError, numberInputLabel]: string[]) => ( + {([ + numberInputError, + numberInputLabel, + dateInputError, + ]: string[]) => ( diff --git a/src/components/date_picker/super_date_picker/pretty_duration.ts b/src/components/date_picker/super_date_picker/pretty_duration.ts index 82030da96ab..29f496cd6d0 100644 --- a/src/components/date_picker/super_date_picker/pretty_duration.ts +++ b/src/components/date_picker/super_date_picker/pretty_duration.ts @@ -47,7 +47,7 @@ export function formatTimeString( dateFormat: string, roundUp = false, locale: LocaleSpecifier = 'en' -) { +): string { const timeAsMoment = moment(timeString, ISO_FORMAT, true); if (timeAsMoment.isValid()) { return timeAsMoment.locale(locale).format(dateFormat); @@ -58,6 +58,10 @@ export function formatTimeString( } const tryParse = dateMath.parse(timeString, { roundUp: roundUp }); + if (!moment(tryParse).isValid()) { + return 'Invalid Date'; + } + if (moment.isMoment(tryParse)) { return `~ ${tryParse.locale(locale).fromNow()}`; } diff --git a/src/components/date_picker/super_date_picker/super_date_picker.tsx b/src/components/date_picker/super_date_picker/super_date_picker.tsx index 701666a7568..abdb3c6c43a 100644 --- a/src/components/date_picker/super_date_picker/super_date_picker.tsx +++ b/src/components/date_picker/super_date_picker/super_date_picker.tsx @@ -40,7 +40,7 @@ import { QuickSelectPanel, } from '../types'; import { EuiDatePopoverContentProps } from './date_popover/date_popover_content'; -import { LocaleSpecifier } from 'moment'; // eslint-disable-line import/named +import moment, { LocaleSpecifier } from 'moment'; // eslint-disable-line import/named export { prettyDuration, commonDurationRanges }; @@ -147,19 +147,17 @@ function isRangeInvalid(start: ShortDate, end: ShortDate) { const startMoment = dateMath.parse(start); const endMoment = dateMath.parse(end, { roundUp: true }); - if ( + + const isInvalid = !startMoment || !endMoment || !startMoment.isValid() || - !endMoment.isValid() - ) { - return true; - } - if (startMoment.isAfter(endMoment)) { - return true; - } + !endMoment.isValid() || + !moment(startMoment).isValid() || + !moment(endMoment).isValid() || + startMoment.isAfter(endMoment); - return false; + return isInvalid; } export class EuiSuperDatePicker extends Component<