Commit 7b183971 by Alex Khomenko Committed by GitHub

Grafana-UI: Enable empty time range (#26320)

* Grafana-UI: Enable empty time range

* Grafana-UI: Add clearable prop

* Grafana-UI: Update types

* Grafana-UI: Use InputTimeRange type

* Grafana-UI: Remove InputTimeRange type

* Grafana-UI: Fix clear icon hover color
parent f93c289f
......@@ -5,7 +5,7 @@ export interface DateTimeBuiltinFormat {
__momentBuiltinFormatBrand: any;
}
export const ISO_8601: DateTimeBuiltinFormat = moment.ISO_8601;
export type DateTimeInput = Date | string | number | Array<string | number> | DateTime; // null | undefined
export type DateTimeInput = Date | string | number | Array<string | number> | DateTime | null; // | undefined;
export type FormatInput = string | DateTimeBuiltinFormat | undefined;
export type DurationInput = string | number | DateTimeDuration;
export type DurationUnit =
......
......@@ -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
......
......@@ -29,8 +29,31 @@ export const basic = () => {
{(value, updateValue) => {
return (
<TimeRangeInput
onChangeTimeZone={tz => action('onTimeZoneChange fired')(tz)}
timeZone="browser"
value={value}
onChange={timeRange => {
action('onChange fired')(timeRange);
updateValue(timeRange);
}}
/>
);
}}
</UseState>
);
};
export const clearable = () => {
return (
<UseState
initialState={{
from: dateTime(),
to: dateTime(),
raw: { from: 'now-6h' as TimeFragment, to: 'now' as TimeFragment },
}}
>
{(value, updateValue) => {
return (
<TimeRangeInput
clearable
value={value}
onChange={timeRange => {
action('onChange fired')(timeRange);
......
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<Props> = ({
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<Props> = ({
onChange(timeRange);
};
const onRangeClear = (event: MouseEvent<HTMLDivElement>) => {
event.stopPropagation();
const from = dateTime(null);
const to = dateTime(null);
onChange({ from, to, raw: { from, to } });
};
return (
<div className={styles.container}>
<div tabIndex={0} className={styles.pickerInput} aria-label="TimePicker Open Button" onClick={onOpen}>
<TimePickerButtonLabel value={value} />
{isValidTimeRange(value) ? (
<TimePickerButtonLabel value={value as TimeRange} />
) : (
<span className={styles.placeholder}>{placeholder}</span>
)}
<span className={styles.caretIcon}>
{isValidTimeRange(value) && clearable && (
<Icon className={styles.clearIcon} name="times" size="lg" onClick={onRangeClear} />
)}
<Icon name={isOpen ? 'angle-up' : 'angle-down'} size="lg" />
</span>
</div>
......@@ -57,7 +86,7 @@ export const TimeRangeInput: FC<Props> = ({
<ClickOutsideWrapper includeButtonPress={false} onClick={onClose}>
<TimePickerContent
timeZone={timeZone}
value={value}
value={isValidTimeRange(value) ? (value as TimeRange) : defaultTimeRange}
onChange={onRangeChange}
otherOptions={otherOptions}
quickOptions={quickOptions}
......@@ -100,5 +129,15 @@ const getStyles = (theme: GrafanaTheme) => {
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;
`,
};
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment