|
|
|
@ -1,5 +1,6 @@ |
|
|
|
|
import { css, cx } from '@emotion/css'; |
|
|
|
|
import React, { FormEvent, useCallback, useState } from 'react'; |
|
|
|
|
import { usePopper } from 'react-popper'; |
|
|
|
|
|
|
|
|
|
import { RelativeTimeRange, GrafanaTheme2, TimeOption } from '@grafana/data'; |
|
|
|
|
|
|
|
|
@ -11,6 +12,7 @@ import CustomScrollbar from '../../CustomScrollbar/CustomScrollbar'; |
|
|
|
|
import { Field } from '../../Forms/Field'; |
|
|
|
|
import { Icon } from '../../Icon/Icon'; |
|
|
|
|
import { getInputStyles, Input } from '../../Input/Input'; |
|
|
|
|
import { Portal } from '../../Portal/Portal'; |
|
|
|
|
import { Tooltip } from '../../Tooltip/Tooltip'; |
|
|
|
|
import { TimePickerTitle } from '../TimeRangePicker/TimePickerTitle'; |
|
|
|
|
import { TimeRangeList } from '../TimeRangePicker/TimeRangeList'; |
|
|
|
@ -50,6 +52,12 @@ export function RelativeTimeRangePicker(props: RelativeTimeRangePickerProps) { |
|
|
|
|
const [from, setFrom] = useState<InputState>({ value: timeOption.from, validation: isRangeValid(timeOption.from) }); |
|
|
|
|
const [to, setTo] = useState<InputState>({ value: timeOption.to, validation: isRangeValid(timeOption.to) }); |
|
|
|
|
|
|
|
|
|
const [markerElement, setMarkerElement] = useState<HTMLDivElement | null>(null); |
|
|
|
|
const [selectorElement, setSelectorElement] = useState<HTMLDivElement | null>(null); |
|
|
|
|
const popper = usePopper(markerElement, selectorElement, { |
|
|
|
|
placement: 'auto-start', |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
const styles = useStyles2(getStyles(from.validation.errorMessage, to.validation.errorMessage)); |
|
|
|
|
|
|
|
|
|
const onChangeTimeOption = (option: TimeOption) => { |
|
|
|
@ -94,7 +102,7 @@ export function RelativeTimeRangePicker(props: RelativeTimeRangePickerProps) { |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
<div className={styles.container}> |
|
|
|
|
<div className={styles.container} ref={setMarkerElement}> |
|
|
|
|
<button className={styles.pickerInput} onClick={onOpen}> |
|
|
|
|
<span className={styles.clockIcon}> |
|
|
|
|
<Icon name="clock-nine" /> |
|
|
|
@ -107,52 +115,59 @@ export function RelativeTimeRangePicker(props: RelativeTimeRangePickerProps) { |
|
|
|
|
</span> |
|
|
|
|
</button> |
|
|
|
|
{isOpen && ( |
|
|
|
|
<ClickOutsideWrapper includeButtonPress={false} onClick={onClose}> |
|
|
|
|
<div className={styles.content}> |
|
|
|
|
<div className={styles.body}> |
|
|
|
|
<CustomScrollbar className={styles.leftSide} hideHorizontalTrack> |
|
|
|
|
<TimeRangeList |
|
|
|
|
title={t('time-picker.time-range.example-title', 'Example time ranges')} |
|
|
|
|
options={validOptions} |
|
|
|
|
onChange={onChangeTimeOption} |
|
|
|
|
value={timeOption} |
|
|
|
|
/> |
|
|
|
|
</CustomScrollbar> |
|
|
|
|
<div className={styles.rightSide}> |
|
|
|
|
<div className={styles.title}> |
|
|
|
|
<TimePickerTitle> |
|
|
|
|
<Tooltip content={<TooltipContent />} placement="bottom" theme="info"> |
|
|
|
|
<div> |
|
|
|
|
<Trans i18nKey="time-picker.time-range.specify"> |
|
|
|
|
Specify time range <Icon name="info-circle" /> |
|
|
|
|
</Trans> |
|
|
|
|
</div> |
|
|
|
|
</Tooltip> |
|
|
|
|
</TimePickerTitle> |
|
|
|
|
</div> |
|
|
|
|
<Field label="From" invalid={!from.validation.isValid} error={from.validation.errorMessage}> |
|
|
|
|
<Input |
|
|
|
|
onClick={(event) => event.stopPropagation()} |
|
|
|
|
onBlur={() => setFrom({ ...from, validation: isRangeValid(from.value) })} |
|
|
|
|
onChange={(event) => setFrom({ ...from, value: event.currentTarget.value })} |
|
|
|
|
value={from.value} |
|
|
|
|
<Portal> |
|
|
|
|
<ClickOutsideWrapper includeButtonPress={false} onClick={onClose}> |
|
|
|
|
<div |
|
|
|
|
className={styles.content} |
|
|
|
|
ref={setSelectorElement} |
|
|
|
|
style={popper.styles.popper} |
|
|
|
|
{...popper.attributes} |
|
|
|
|
> |
|
|
|
|
<div className={styles.body}> |
|
|
|
|
<CustomScrollbar className={styles.leftSide} hideHorizontalTrack> |
|
|
|
|
<TimeRangeList |
|
|
|
|
title={t('time-picker.time-range.example-title', 'Example time ranges')} |
|
|
|
|
options={validOptions} |
|
|
|
|
onChange={onChangeTimeOption} |
|
|
|
|
value={timeOption} |
|
|
|
|
/> |
|
|
|
|
</Field> |
|
|
|
|
<Field label="To" invalid={!to.validation.isValid} error={to.validation.errorMessage}> |
|
|
|
|
<Input |
|
|
|
|
onClick={(event) => event.stopPropagation()} |
|
|
|
|
onBlur={() => setTo({ ...to, validation: isRangeValid(to.value) })} |
|
|
|
|
onChange={(event) => setTo({ ...to, value: event.currentTarget.value })} |
|
|
|
|
value={to.value} |
|
|
|
|
/> |
|
|
|
|
</Field> |
|
|
|
|
<Button aria-label="TimePicker submit button" onClick={onApply}> |
|
|
|
|
Apply time range |
|
|
|
|
</Button> |
|
|
|
|
</CustomScrollbar> |
|
|
|
|
<div className={styles.rightSide}> |
|
|
|
|
<div className={styles.title}> |
|
|
|
|
<TimePickerTitle> |
|
|
|
|
<Tooltip content={<TooltipContent />} placement="bottom" theme="info"> |
|
|
|
|
<div> |
|
|
|
|
<Trans i18nKey="time-picker.time-range.specify"> |
|
|
|
|
Specify time range <Icon name="info-circle" /> |
|
|
|
|
</Trans> |
|
|
|
|
</div> |
|
|
|
|
</Tooltip> |
|
|
|
|
</TimePickerTitle> |
|
|
|
|
</div> |
|
|
|
|
<Field label="From" invalid={!from.validation.isValid} error={from.validation.errorMessage}> |
|
|
|
|
<Input |
|
|
|
|
onClick={(event) => event.stopPropagation()} |
|
|
|
|
onBlur={() => setFrom({ ...from, validation: isRangeValid(from.value) })} |
|
|
|
|
onChange={(event) => setFrom({ ...from, value: event.currentTarget.value })} |
|
|
|
|
value={from.value} |
|
|
|
|
/> |
|
|
|
|
</Field> |
|
|
|
|
<Field label="To" invalid={!to.validation.isValid} error={to.validation.errorMessage}> |
|
|
|
|
<Input |
|
|
|
|
onClick={(event) => event.stopPropagation()} |
|
|
|
|
onBlur={() => setTo({ ...to, validation: isRangeValid(to.value) })} |
|
|
|
|
onChange={(event) => setTo({ ...to, value: event.currentTarget.value })} |
|
|
|
|
value={to.value} |
|
|
|
|
/> |
|
|
|
|
</Field> |
|
|
|
|
<Button aria-label="TimePicker submit button" onClick={onApply}> |
|
|
|
|
Apply time range |
|
|
|
|
</Button> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
</ClickOutsideWrapper> |
|
|
|
|
</ClickOutsideWrapper> |
|
|
|
|
</Portal> |
|
|
|
|
)} |
|
|
|
|
</div> |
|
|
|
|
); |
|
|
|
|