Skip to content

Commit

Permalink
fixed super date picker crash (elastic#5263)
Browse files Browse the repository at this point in the history
  • Loading branch information
JordanSh authored and ym committed Oct 29, 2021
1 parent 24a79c2 commit f576d6a
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 19 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -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', () => {
Expand Down
6 changes: 6 additions & 0 deletions src/components/date_picker/super_date_picker/date_modes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
NowDateMode,
ShortDate,
} from '../types';
import moment from 'moment';

export const DATE_MODES: {
ABSOLUTE: AbsoluteDateMode;
Expand All @@ -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;
Expand All @@ -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();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 (
<EuiForm className="euiDatePopoverContent__padded">
<EuiFlexGroup gutterSize="s" responsive={false}>
Expand All @@ -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[]) => (
<EuiFormRow
isInvalid={isInvalid}
error={isInvalid ? numberInputError : null}
error={getErrorMessage({ numberInputError, dateInputError })}
>
<EuiFieldNumber
compressed
Expand Down Expand Up @@ -184,7 +211,7 @@ export class EuiRelativeTab extends Component<
<EuiSpacer size="m" />
<EuiFieldText
compressed
value={formatedValue}
value={formattedValue}
readOnly
prepend={
<EuiFormLabel>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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()}`;
}
Expand Down
18 changes: 8 additions & 10 deletions src/components/date_picker/super_date_picker/super_date_picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 };

Expand Down Expand Up @@ -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<
Expand Down

0 comments on commit f576d6a

Please sign in to comment.