// Libraries import React, { PureComponent, memo, FormEvent } from 'react'; import { css } from 'emotion'; // Components import { Tooltip } from '../Tooltip/Tooltip'; import { TimePickerContent } from './TimeRangePicker/TimePickerContent'; import { ClickOutsideWrapper } from '../ClickOutsideWrapper/ClickOutsideWrapper'; // Utils & Services import { stylesFactory } from '../../themes/stylesFactory'; import { withTheme, useTheme } from '../../themes/ThemeContext'; // Types import { isDateTime, rangeUtil, GrafanaTheme, dateTimeFormat, timeZoneFormatUserFriendly, TimeRange, TimeZone, dateMath, } from '@grafana/data'; import { Themeable } from '../../types'; import { otherOptions, quickOptions } from './rangeOptions'; import { ButtonGroup, ToolbarButton } from '../Button'; export interface TimeRangePickerProps extends Themeable { hideText?: boolean; value: TimeRange; timeZone?: TimeZone; timeSyncButton?: JSX.Element; isSynced?: boolean; onChange: (timeRange: TimeRange) => void; onChangeTimeZone: (timeZone: TimeZone) => void; onMoveBackward: () => void; onMoveForward: () => void; onZoom: () => void; history?: TimeRange[]; hideQuickRanges?: boolean; } export interface State { isOpen: boolean; } export class UnthemedTimeRangePicker extends PureComponent { state: State = { isOpen: false, }; onChange = (timeRange: TimeRange) => { this.props.onChange(timeRange); this.setState({ isOpen: false }); }; onOpen = (event: FormEvent) => { const { isOpen } = this.state; event.stopPropagation(); event.preventDefault(); this.setState({ isOpen: !isOpen }); }; onClose = () => { this.setState({ isOpen: false }); }; render() { const { value, onMoveBackward, onMoveForward, onZoom, timeZone, timeSyncButton, isSynced, theme, history, onChangeTimeZone, hideQuickRanges, } = this.props; const { isOpen } = this.state; const styles = getStyles(theme); const hasAbsolute = isDateTime(value.raw.from) || isDateTime(value.raw.to); const variant = isSynced ? 'active' : 'default'; return ( {hasAbsolute && } } placement="bottom"> {isOpen && ( )} {timeSyncButton} {hasAbsolute && } ); } } const ZoomOutTooltip = () => ( <> Time range zoom out
CTRL+Z ); const TimePickerTooltip = ({ timeRange, timeZone }: { timeRange: TimeRange; timeZone?: TimeZone }) => { const theme = useTheme(); const styles = getLabelStyles(theme); return ( <> {dateTimeFormat(timeRange.from, { timeZone })}
to
{dateTimeFormat(timeRange.to, { timeZone })}
{timeZoneFormatUserFriendly(timeZone)}
); }; type LabelProps = Pick; export const TimePickerButtonLabel = memo(({ hideText, value, timeZone }) => { const theme = useTheme(); const styles = getLabelStyles(theme); if (hideText) { return null; } return ( {formattedRange(value, timeZone)} {rangeUtil.describeTimeRangeAbbreviation(value, timeZone)} ); }); TimePickerButtonLabel.displayName = 'TimePickerButtonLabel'; const formattedRange = (value: TimeRange, timeZone?: TimeZone) => { const adjustedTimeRange = { to: dateMath.isMathString(value.raw.to) ? value.raw.to : value.to, from: dateMath.isMathString(value.raw.from) ? value.raw.from : value.from, }; return rangeUtil.describeTimeRange(adjustedTimeRange, timeZone); }; export const TimeRangePicker = withTheme(UnthemedTimeRangePicker); const getStyles = stylesFactory((theme: GrafanaTheme) => { return { container: css` position: relative; display: flex; vertical-align: middle; `, }; }); const getLabelStyles = stylesFactory((theme: GrafanaTheme) => { return { container: css` display: flex; align-items: center; white-space: nowrap; `, utc: css` color: ${theme.palette.orange}; font-size: ${theme.typography.size.sm}; padding-left: 6px; line-height: 28px; vertical-align: bottom; font-weight: ${theme.typography.weight.semibold}; `, }; });