From 35d75b5d9d864436ebd47c45294f102edd4a9d2e Mon Sep 17 00:00:00 2001 From: Hunter Trujillo Date: Wed, 28 Jun 2017 17:50:35 -0600 Subject: [PATCH] Split out CustomTimeRange date picker into its own component so it can be shared between separate Dropdown and Overlay components. --- ui/src/shared/components/CustomTimeRange.js | 97 ++++++++++++++++ .../components/CustomTimeRangeDropdown.js | 83 +++----------- .../components/CustomTimeRangeOverlay.js | 46 ++++++++ ui/src/shared/components/TimeRangeDropdown.js | 104 ++++++++++++------ 4 files changed, 227 insertions(+), 103 deletions(-) create mode 100644 ui/src/shared/components/CustomTimeRange.js create mode 100644 ui/src/shared/components/CustomTimeRangeOverlay.js diff --git a/ui/src/shared/components/CustomTimeRange.js b/ui/src/shared/components/CustomTimeRange.js new file mode 100644 index 0000000000..e1475514a2 --- /dev/null +++ b/ui/src/shared/components/CustomTimeRange.js @@ -0,0 +1,97 @@ +import React, {PropTypes, Component} from 'react' +import rome from 'rome' +import moment from 'moment' + +class CustomTimeRange extends Component { + constructor(props) { + super(props) + + this.handleClick = ::this.handleClick + this._formatTimeRange = ::this._formatTimeRange + } + + componentDidMount() { + const {timeRange} = this.props + + const lower = rome(this.lower, { + initialValue: this._formatTimeRange(timeRange.lower), + }) + const upper = rome(this.upper, { + initialValue: this._formatTimeRange(timeRange.upper), + }) + + this.lowerCal = lower + this.upperCal = upper + } + + // If there is an upper or lower time range set, set the corresponding calendar's value. + componentWillReceiveProps(nextProps) { + const {lower, upper} = nextProps.timeRange + if (lower) { + this.lowerCal.setValue(this._formatTimeRange(lower)) + } + + if (upper) { + this.upperCal.setValue(this._formatTimeRange(upper)) + } + } + + render() { + return ( +
+
+
(this.lower = r)} /> +
(this.upper = r)} /> +
+
+ Apply +
+
+ ) + } + + /* + * Upper and lower time ranges are passed in with single quotes as part of + * the string literal, i.e. "'2015-09-23T18:00:00.000Z'". Remove them + * before passing the string to be parsed. + */ + _formatTimeRange(timeRange) { + if (!timeRange) { + return '' + } + + // If the given time range is relative, create a fixed timestamp based on its value + if (timeRange.match(/^now/)) { + const match = timeRange.match(/\d+\w/)[0] + const duration = match.slice(0, match.length - 1) + const unitOfTime = match[match.length - 1] + return moment().subtract(duration, unitOfTime) + } + + return moment(timeRange.replace(/\'/g, '')).format('YYYY-MM-DD HH:mm') + } + + handleClick() { + const lower = this.lowerCal.getDate().toISOString() + const upper = this.upperCal.getDate().toISOString() + + this.props.onApplyTimeRange({lower, upper}) + this.props.onClose() + } +} + +const {func, shape, string} = PropTypes + +CustomTimeRange.propTypes = { + onApplyTimeRange: func.isRequired, + timeRange: shape({ + lower: string.isRequired, + upper: string.isRequired, + }).isRequired, + onClose: func.isRequired, +} + +export default CustomTimeRange diff --git a/ui/src/shared/components/CustomTimeRangeDropdown.js b/ui/src/shared/components/CustomTimeRangeDropdown.js index ea01b394da..22d5a25950 100644 --- a/ui/src/shared/components/CustomTimeRangeDropdown.js +++ b/ui/src/shared/components/CustomTimeRangeDropdown.js @@ -1,48 +1,28 @@ import React, {PropTypes, Component} from 'react' -import rome from 'rome' import moment from 'moment' import classnames from 'classnames' import OnClickOutside from 'react-onclickoutside' +import CustomTimeRange from 'shared/components/CustomTimeRange' + class CustomTimeRangeDropdown extends Component { constructor(props) { super(props) - - this.handleClick = ::this.handleClick } handleClickOutside() { this.props.onClose() } - componentDidMount() { - const {timeRange} = this.props - - const lower = rome(this.lower, { - initialValue: this._formatTimeRange(timeRange.lower), - }) - const upper = rome(this.upper, { - initialValue: this._formatTimeRange(timeRange.upper), - }) - - this.lowerCal = lower - this.upperCal = upper - } - - // If there is an upper or lower time range set, set the corresponding calendar's value. - componentWillReceiveProps(nextProps) { - const {lower, upper} = nextProps.timeRange - if (lower) { - this.lowerCal.setValue(this._formatTimeRange(lower)) - } - - if (upper) { - this.upperCal.setValue(this._formatTimeRange(upper)) - } - } - render() { - const {isVisible, onToggle, timeRange: {upper, lower}} = this.props + const { + isVisible, + onToggle, + onClose, + timeRange: {upper, lower}, + timeRange, + onApplyTimeRange, + } = this.props return (
-
-
(this.lower = r)} /> -
(this.upper = r)} /> -
-
- Apply -
+
) } - - handleClick() { - const lower = this.lowerCal.getDate().toISOString() - const upper = this.upperCal.getDate().toISOString() - - this.props.onApplyTimeRange({lower, upper}) - this.props.onClose() - } - /* - * Upper and lower time ranges are passed in with single quotes as part of - * the string literal, i.e. "'2015-09-23T18:00:00.000Z'". Remove them - * before passing the string to be parsed. - */ - _formatTimeRange(timeRange) { - if (!timeRange) { - return '' - } - - // If the given time range is relative, create a fixed timestamp based on its value - if (timeRange.match(/^now/)) { - const match = timeRange.match(/\d+\w/)[0] - const duration = match.slice(0, match.length - 1) - const unitOfTime = match[match.length - 1] - return moment().subtract(duration, unitOfTime) - } - - return moment(timeRange.replace(/\'/g, '')).format('YYYY-MM-DD HH:mm') - } } const {bool, func, shape, string} = PropTypes diff --git a/ui/src/shared/components/CustomTimeRangeOverlay.js b/ui/src/shared/components/CustomTimeRangeOverlay.js new file mode 100644 index 0000000000..a1a27117df --- /dev/null +++ b/ui/src/shared/components/CustomTimeRangeOverlay.js @@ -0,0 +1,46 @@ +import React, {PropTypes, Component} from 'react' +import OnClickOutside from 'react-onclickoutside' + +import CustomTimeRange from 'shared/components/CustomTimeRange' +import OverlayTechnologies from 'shared/components/OverlayTechnologies' + +class CustomTimeRangeOverlay extends Component { + constructor(props) { + super(props) + } + + handleClickOutside() { + this.props.onClose() + } + + render() { + const {onClose, timeRange, onApplyTimeRange} = this.props + + return ( + +
+ +
+
+ ) + } +} + +const {bool, func, shape, string} = PropTypes + +CustomTimeRangeOverlay.propTypes = { + onApplyTimeRange: func.isRequired, + timeRange: shape({ + lower: string.isRequired, + upper: string.isRequired, + }).isRequired, + isVisible: bool.isRequired, + onToggle: func.isRequired, + onClose: func.isRequired, +} + +export default OnClickOutside(CustomTimeRangeOverlay) diff --git a/ui/src/shared/components/TimeRangeDropdown.js b/ui/src/shared/components/TimeRangeDropdown.js index ceb0b86e89..5aa1536345 100644 --- a/ui/src/shared/components/TimeRangeDropdown.js +++ b/ui/src/shared/components/TimeRangeDropdown.js @@ -4,6 +4,7 @@ import moment from 'moment' import OnClickOutside from 'shared/components/OnClickOutside' import FancyScrollbar from 'shared/components/FancyScrollbar' +import CustomTimeRangeOverlay from 'shared/components/CustomTimeRangeOverlay' import timeRanges from 'hson!shared/data/timeRanges.hson' import {DROPDOWN_MENU_MAX_HEIGHT} from 'shared/constants/index' @@ -14,11 +15,19 @@ class TimeRangeDropdown extends Component { this.state = { autobind: false, isOpen: false, + isCustomTimeRangeOpen: false, + customTimeRange: { + lower: '', + upper: '', + }, } this.findTimeRangeInputValue = ::this.findTimeRangeInputValue this.handleSelection = ::this.handleSelection this.toggleMenu = ::this.toggleMenu this.showCustomTimeRange = ::this.showCustomTimeRange + this.handleApplyCustomTimeRange = ::this.handleApplyCustomTimeRange + this.handleToggleCustomTimeRange = ::this.handleToggleCustomTimeRange + this.handleCloseCustomTimeRange = ::this.handleCloseCustomTimeRange } findTimeRangeInputValue({upper, lower}) { @@ -50,47 +59,72 @@ class TimeRangeDropdown extends Component { this.setState({isOpen: !this.state.isOpen}) } - showCustomTimeRange() {} + showCustomTimeRange() { + this.setState({isCustomTimeRangeOpen: true}) + } + + handleApplyCustomTimeRange(timeRange) { + this.setState({timeRange}) + } + + handleToggleCustomTimeRange() { + this.setState({isCustomTimeRangeOpen: !this.state.isCustomTimeRangeOpen}) + } + + handleCloseCustomTimeRange() { + this.setState({isCustomTimeRangeOpen: false}) + } render() { const {selected} = this.props - const {isOpen} = this.state + const {isOpen, customTimeRange, isCustomTimeRangeOpen} = this.state return ( -
-
this.toggleMenu()} - > - - - {this.findTimeRangeInputValue(selected)} - - -
- + + + {this.findTimeRangeInputValue(selected)} + + +
+ +
+ {isCustomTimeRangeOpen + ? + : null}
) }