Skip to content

Commit

Permalink
feat(ui): Add custom time range in time range dropdown
Browse files Browse the repository at this point in the history
Co-authored-by: Daniel Campbell <[email protected]>
  • Loading branch information
ischolten and mavarius committed Feb 20, 2019
1 parent b877457 commit f0e7f30
Show file tree
Hide file tree
Showing 14 changed files with 647 additions and 67 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

### Features
1. [11954](https://github.com/influxdata/influxdb/pull/11954): Add the ability to run a task manually from tasks page
1. [11990](https://github.com/influxdata/influxdb/pull/11990): Add the ability to select a custom time range in explorer and dashboard

### Bug Fixes

Expand Down
73 changes: 70 additions & 3 deletions ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@
"react": "^16.8.0",
"react-codemirror2": "^4.2.1",
"react-copy-to-clipboard": "^5.0.1",
"react-datepicker": "^2.1.0",
"react-dimensions": "^1.2.0",
"react-dnd": "^2.6.0",
"react-dnd-html5-backend": "^2.6.0",
Expand Down
4 changes: 2 additions & 2 deletions ui/src/shared/components/ClickOutside.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ interface Props {
@ErrorHandling
export class ClickOutside extends PureComponent<Props> {
public componentDidMount() {
document.addEventListener('click', this.handleClickOutside, true)
document.addEventListener('mousedown', this.handleClickOutside, true)
}

public componentWillUnmount() {
document.removeEventListener('click', this.handleClickOutside, true)
document.removeEventListener('mousedown', this.handleClickOutside, true)
}

public render() {
Expand Down
139 changes: 123 additions & 16 deletions ui/src/shared/components/TimeRangeDropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
// Libraries
import React, {PureComponent} from 'react'
import React, {PureComponent, createRef} from 'react'
import {get} from 'lodash'
import moment from 'moment'

// Components
import {Dropdown} from 'src/clockface'
import DateRangePicker from 'src/shared/components/dateRangePicker/DateRangePicker'

// Constants
import {TIME_RANGES} from 'src/shared/constants/timeRanges'
import {
TIME_RANGES,
CUSTOM_TIME_RANGE,
TIME_RANGE_FORMAT,
} from 'src/shared/constants/timeRanges'

// Types
import {TimeRange} from 'src/types'
Expand All @@ -15,34 +22,134 @@ interface Props {
onSetTimeRange: (timeRange: TimeRange) => void
}

class TimeRangeDropdown extends PureComponent<Props> {
interface State {
isDatePickerOpen: boolean
dropdownPosition: {top: number; right: number}
}

class TimeRangeDropdown extends PureComponent<Props, State> {
private dropdownRef = createRef<HTMLDivElement>()

constructor(props: Props) {
super(props)

this.state = {isDatePickerOpen: false, dropdownPosition: undefined}
}

public render() {
const timeRange = this.timeRange

return (
<>
{this.isDatePickerVisible && (
<DateRangePicker
timeRange={timeRange}
onSetTimeRange={this.handleApplyTimeRange}
onClose={this.handleHideDatePicker}
position={this.state.dropdownPosition}
/>
)}
<div ref={this.dropdownRef}>
<Dropdown
selectedID={timeRange.label}
onChange={this.handleChange}
widthPixels={this.dropdownWidth}
titleText={this.formattedCustomTimeRange}
>
{TIME_RANGES.map(({label}) => (
<Dropdown.Item key={label} value={label} id={label}>
{label}
</Dropdown.Item>
))}
</Dropdown>
</div>
</>
)
}

private get dropdownWidth(): number {
if (this.isCustomTimeRange) {
return 250
}

return 100
}

private get isCustomTimeRange(): boolean {
const {timeRange} = this.props
return (
get(timeRange, 'label', '') === CUSTOM_TIME_RANGE || !!timeRange.upper
)
}

private get formattedCustomTimeRange(): string {
const {timeRange} = this.props
if (!this.isCustomTimeRange) {
return timeRange.label
}

return `${moment(timeRange.lower).format(TIME_RANGE_FORMAT)} - ${moment(
timeRange.upper
).format(TIME_RANGE_FORMAT)}`
}

private get timeRange(): TimeRange {
const {timeRange} = this.props
const {isDatePickerOpen} = this.state

if (isDatePickerOpen) {
const date = new Date().toISOString()
const upper =
timeRange.upper && this.isCustomTimeRange ? timeRange.upper : date
const lower =
timeRange.lower && this.isCustomTimeRange ? timeRange.lower : date
return {
label: CUSTOM_TIME_RANGE,
lower,
upper,
}
}

if (this.isCustomTimeRange) {
return {
...timeRange,
label: this.formattedCustomTimeRange,
}
}

const selectedTimeRange = TIME_RANGES.find(t => t.lower === timeRange.lower)

if (!selectedTimeRange) {
throw new Error('TimeRangeDropdown passed unknown TimeRange')
}

return (
<Dropdown
selectedID={selectedTimeRange.label}
onChange={this.handleChange}
widthPixels={100}
>
{TIME_RANGES.map(({label}) => (
<Dropdown.Item key={label} value={label} id={label}>
{label}
</Dropdown.Item>
))}
</Dropdown>
)
return selectedTimeRange
}

private get isDatePickerVisible() {
return this.state.isDatePickerOpen
}

private handleApplyTimeRange = (timeRange: TimeRange) => {
this.props.onSetTimeRange(timeRange)
this.handleHideDatePicker()
}

private handleHideDatePicker = () => {
this.setState({isDatePickerOpen: false, dropdownPosition: null})
}

private handleChange = (label: string): void => {
const {onSetTimeRange} = this.props
const timeRange = TIME_RANGES.find(t => t.label === label)

if (label === CUSTOM_TIME_RANGE) {
const {top, left} = this.dropdownRef.current.getBoundingClientRect()
const right = window.innerWidth - left
this.setState({isDatePickerOpen: true, dropdownPosition: {top, right}})
return
}

onSetTimeRange(timeRange)
}
}
Expand Down
Loading

0 comments on commit f0e7f30

Please sign in to comment.