diff --git a/packages/grafana-ui/src/components/TimePicker/TimeRangePicker/TimePickerCalendar.test.tsx b/packages/grafana-ui/src/components/TimePicker/TimeRangePicker/TimePickerCalendar.test.tsx new file mode 100644 index 00000000000..59f06a6713a --- /dev/null +++ b/packages/grafana-ui/src/components/TimePicker/TimeRangePicker/TimePickerCalendar.test.tsx @@ -0,0 +1,53 @@ +import { dateTime } from '@grafana/data'; + +import { inputToValue } from './TimePickerCalendar'; + +describe('inputToValue', () => { + describe('when called with valid dates', () => { + describe('and from is after to', () => { + it('then to should be first in the result', () => { + const from = dateTime('2020-04-16T11:00:00.000Z'); + const to = dateTime('2020-04-16T10:00:00.000Z'); + + const result = inputToValue(from, to); + + expect(result).toEqual([new Date('2020-04-16T10:00:00.000Z'), new Date('2020-04-16T11:00:00.000Z')]); + }); + }); + + describe('and from is before to', () => { + it('then to should be second in the result', () => { + const from = dateTime('2020-04-16T10:00:00.000Z'); + const to = dateTime('2020-04-16T11:00:00.000Z'); + + const result = inputToValue(from, to); + + expect(result).toEqual([new Date('2020-04-16T10:00:00.000Z'), new Date('2020-04-16T11:00:00.000Z')]); + }); + }); + }); + + describe('when called with an invalid from datetime', () => { + it('then from should replaced with specified default', () => { + const from = dateTime('2020-04-32T10:00:00.000Z'); // invalid date + const to = dateTime('2020-04-16T10:00:00.000Z'); + const invalidDateDefault = new Date('2020-04-16T11:00:00.000Z'); + + const result = inputToValue(from, to, invalidDateDefault); + + expect(result).toEqual([new Date('2020-04-16T10:00:00.000Z'), new Date('2020-04-16T11:00:00.000Z')]); + }); + }); + + describe('when called with an invalid to datetime', () => { + it('then to should replaced with specified default', () => { + const from = dateTime('2020-04-16T10:00:00.000Z'); + const to = dateTime('2020-04-32T10:00:00.000Z'); // invalid date + const invalidDateDefault = new Date('2020-04-16T11:00:00.000Z'); + + const result = inputToValue(from, to, invalidDateDefault); + + expect(result).toEqual([new Date('2020-04-16T10:00:00.000Z'), new Date('2020-04-16T11:00:00.000Z')]); + }); + }); +}); diff --git a/packages/grafana-ui/src/components/TimePicker/TimeRangePicker/TimePickerCalendar.tsx b/packages/grafana-ui/src/components/TimePicker/TimeRangePicker/TimePickerCalendar.tsx index 76bf29ab2f9..6e801d27116 100644 --- a/packages/grafana-ui/src/components/TimePicker/TimeRangePicker/TimePickerCalendar.tsx +++ b/packages/grafana-ui/src/components/TimePicker/TimeRangePicker/TimePickerCalendar.tsx @@ -1,8 +1,8 @@ -import React, { memo, useState, useEffect, useCallback, FormEvent } from 'react'; +import React, { FormEvent, memo, useCallback, useEffect, useState } from 'react'; import { css } from 'emotion'; import Calendar from 'react-calendar/dist/entry.nostyle'; -import { GrafanaTheme, DateTime, TimeZone, dateTimeParse } from '@grafana/data'; -import { useTheme, stylesFactory } from '../../../themes'; +import { dateTime, DateTime, dateTimeParse, GrafanaTheme, TimeZone } from '@grafana/data'; +import { stylesFactory, useTheme } from '../../../themes'; import { TimePickerTitle } from './TimePickerTitle'; import { Button } from '../../Button'; import { Icon } from '../../Icon/Icon'; @@ -285,14 +285,16 @@ const Footer = memo(({ onClose, onApply }) => { ); }); -function inputToValue(from: DateTime, to: DateTime): Date[] { +export function inputToValue(from: DateTime, to: DateTime, invalidDateDefault: Date = new Date()): Date[] { const fromAsDate = from.toDate(); const toAsDate = to.toDate(); + const fromAsValidDate = dateTime(fromAsDate).isValid() ? fromAsDate : invalidDateDefault; + const toAsValidDate = dateTime(toAsDate).isValid() ? toAsDate : invalidDateDefault; - if (fromAsDate > toAsDate) { - return [toAsDate, fromAsDate]; + if (fromAsValidDate > toAsValidDate) { + return [toAsValidDate, fromAsValidDate]; } - return [fromAsDate, toAsDate]; + return [fromAsValidDate, toAsValidDate]; } function useOnCalendarChange(onChange: (from: DateTime, to: DateTime) => void, timeZone?: TimeZone) {