diff --git a/packages/grafana-data/src/datetime/moment_wrapper.ts b/packages/grafana-data/src/datetime/moment_wrapper.ts index b4980c1d8e3..994bc395890 100644 --- a/packages/grafana-data/src/datetime/moment_wrapper.ts +++ b/packages/grafana-data/src/datetime/moment_wrapper.ts @@ -5,7 +5,7 @@ export interface DateTimeBuiltinFormat { __momentBuiltinFormatBrand: any; } export const ISO_8601: DateTimeBuiltinFormat = moment.ISO_8601; -export type DateTimeInput = Date | string | number | Array | DateTime; // null | undefined +export type DateTimeInput = Date | string | number | Array | DateTime | null; // | undefined; export type FormatInput = string | DateTimeBuiltinFormat | undefined; export type DurationInput = string | number | DateTimeDuration; export type DurationUnit = diff --git a/packages/grafana-ui/src/components/TimePicker/TimeRangeInput.mdx b/packages/grafana-ui/src/components/TimePicker/TimeRangeInput.mdx index d5096ec9e67..6ce63f083b7 100644 --- a/packages/grafana-ui/src/components/TimePicker/TimeRangeInput.mdx +++ b/packages/grafana-ui/src/components/TimePicker/TimeRangeInput.mdx @@ -5,6 +5,22 @@ import { TimeRangeInput } from './TimeRangeInput'; A variant of `TimeRangePicker` for use in forms. +`dateTime(null)` can be used to provide empty time range value. The shape of the return value on input clear is: + +```javascript +{ + from: dateTime(null), + to: dateTime(null), + raw: { + from: dateTime(null), + to: dateTime(null), + }, +}; +``` + +`dateMath.isValid()` from `@grafana/data` can be used to check for a valid time range value. + + ### Usage ```jsx diff --git a/packages/grafana-ui/src/components/TimePicker/TimeRangeInput.story.tsx b/packages/grafana-ui/src/components/TimePicker/TimeRangeInput.story.tsx index f29ccde50b0..d426397b1f8 100644 --- a/packages/grafana-ui/src/components/TimePicker/TimeRangeInput.story.tsx +++ b/packages/grafana-ui/src/components/TimePicker/TimeRangeInput.story.tsx @@ -29,8 +29,31 @@ export const basic = () => { {(value, updateValue) => { return ( action('onTimeZoneChange fired')(tz)} - timeZone="browser" + value={value} + onChange={timeRange => { + action('onChange fired')(timeRange); + updateValue(timeRange); + }} + /> + ); + }} + + ); +}; + +export const clearable = () => { + return ( + + {(value, updateValue) => { + return ( + { action('onChange fired')(timeRange); diff --git a/packages/grafana-ui/src/components/TimePicker/TimeRangeInput.tsx b/packages/grafana-ui/src/components/TimePicker/TimeRangeInput.tsx index 7abb9165c3f..f073ca5cc52 100644 --- a/packages/grafana-ui/src/components/TimePicker/TimeRangeInput.tsx +++ b/packages/grafana-ui/src/components/TimePicker/TimeRangeInput.tsx @@ -1,6 +1,6 @@ -import React, { FC, FormEvent, useState } from 'react'; +import React, { FC, FormEvent, MouseEvent, useState } from 'react'; import { css, cx } from 'emotion'; -import { GrafanaTheme, TimeRange, TimeZone } from '@grafana/data'; +import { dateTime, GrafanaTheme, TimeRange, TimeZone, dateMath } from '@grafana/data'; import { useStyles } from '../../themes/ThemeContext'; import { ClickOutsideWrapper } from '../ClickOutsideWrapper/ClickOutsideWrapper'; import { Icon } from '../Icon/Icon'; @@ -10,12 +10,24 @@ import { TimePickerButtonLabel } from './TimeRangePicker'; import { TimePickerContent } from './TimeRangePicker/TimePickerContent'; import { otherOptions, quickOptions } from './rangeOptions'; +export const defaultTimeRange: TimeRange = { + from: dateTime().subtract(6, 'hour'), + to: dateTime(), + raw: { from: 'now-6h', to: 'now' }, +}; + +const isValidTimeRange = (range: any) => { + return dateMath.isValid(range.from) && dateMath.isValid(range.to); +}; + export interface Props { value: TimeRange; timeZone?: TimeZone; onChange: (timeRange: TimeRange) => void; onChangeTimeZone?: (timeZone: TimeZone) => void; hideTimeZone?: boolean; + placeholder?: string; + clearable?: boolean; } const noop = () => {}; @@ -24,8 +36,10 @@ export const TimeRangeInput: FC = ({ value, onChange, onChangeTimeZone, + clearable, hideTimeZone = true, timeZone = 'browser', + placeholder = 'Select time range', }) => { const [isOpen, setIsOpen] = useState(false); const styles = useStyles(getStyles); @@ -45,11 +59,26 @@ export const TimeRangeInput: FC = ({ onChange(timeRange); }; + const onRangeClear = (event: MouseEvent) => { + event.stopPropagation(); + const from = dateTime(null); + const to = dateTime(null); + onChange({ from, to, raw: { from, to } }); + }; + return (
- + {isValidTimeRange(value) ? ( + + ) : ( + {placeholder} + )} + + {isValidTimeRange(value) && clearable && ( + + )}
@@ -57,7 +86,7 @@ export const TimeRangeInput: FC = ({ { margin-left: ${theme.spacing.xs}; ` ), + clearIcon: css` + margin-right: ${theme.spacing.xs}; + &:hover { + color: ${theme.colors.linkHover}; + } + `, + placeholder: css` + color: ${theme.colors.formInputPlaceholderText}; + opacity: 1; + `, }; };