Separate time and window
Co-authored-by: Alex Paxton <thealexpaxton@gmail.com> Co-authored-by: Daniel Campbell <metalwhirlwind@gmail.com>pull/10616/head
parent
6a35203fad
commit
ff0b3ce15f
|
@ -21,7 +21,13 @@ import {
|
|||
// getLogConfig as getLogConfigAJAX,
|
||||
// updateLogConfig as updateLogConfigAJAX,
|
||||
} from 'src/logs/api'
|
||||
import {LogsState, Filter, TableData, LogConfig} from 'src/types/logs'
|
||||
import {
|
||||
LogsState,
|
||||
Filter,
|
||||
TableData,
|
||||
LogConfig,
|
||||
TimeWindow,
|
||||
} from 'src/types/logs'
|
||||
|
||||
const defaultTableData: TableData = {
|
||||
columns: [
|
||||
|
@ -132,7 +138,7 @@ interface SetTimeRangeAction {
|
|||
interface SetTimeWindowAction {
|
||||
type: ActionTypes.SetTimeWindow
|
||||
payload: {
|
||||
timeWindow: string
|
||||
timeWindow: TimeWindow
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -251,7 +257,7 @@ const setHistogramData = (data): SetHistogramData => ({
|
|||
payload: {data},
|
||||
})
|
||||
|
||||
export const setTimeWindow = (timeWindow: string): SetTimeWindowAction => ({
|
||||
export const setTimeWindow = (timeWindow: TimeWindow): SetTimeWindowAction => ({
|
||||
type: ActionTypes.SetTimeWindow,
|
||||
payload: {timeWindow},
|
||||
})
|
||||
|
@ -472,10 +478,9 @@ export const setTimeRangeAsync = (timeRange: TimeRange) => async (
|
|||
dispatch(setTableQueryConfigAsync())
|
||||
}
|
||||
|
||||
export const setTimeWindowAsync = (timeWindow: string) => async (
|
||||
export const setTimeWindowAsync = (timeWindow: TimeWindow) => async (
|
||||
dispatch
|
||||
): Promise<void> => {
|
||||
console.log(timeWindow)
|
||||
dispatch({
|
||||
type: ActionTypes.SetTimeWindow,
|
||||
payload: {
|
||||
|
|
|
@ -9,7 +9,7 @@ import PageHeaderTitle from 'src/reusable_ui/components/page_layout/PageHeaderTi
|
|||
import TimeRangeDropdown from 'src/logs/components/TimeRangeDropdown'
|
||||
import WindowSelectorDropdown from 'src/logs/components/window_selector_dropdown/WindowSelectorDropdown'
|
||||
import Authorized, {EDITOR_ROLE} from 'src/auth/Authorized'
|
||||
import {TimeRange} from 'src/types'
|
||||
import {TimeWindow, TimeWindowOption} from 'src/types/logs'
|
||||
|
||||
interface SourceItem {
|
||||
id: string
|
||||
|
@ -21,15 +21,14 @@ interface Props {
|
|||
availableSources: Source[]
|
||||
currentSource: Source | null
|
||||
currentNamespaces: Namespace[]
|
||||
timeRange: TimeRange
|
||||
liveUpdating: boolean
|
||||
onChooseSource: (sourceID: string) => void
|
||||
onChooseNamespace: (namespace: Namespace) => void
|
||||
onChooseTimerange: (timeRange: TimeRange) => void
|
||||
onChooseTime: (time: string) => void
|
||||
onChangeLiveUpdatingStatus: () => void
|
||||
onShowOptionsOverlay: () => void
|
||||
timeWindow: string
|
||||
onChangeTimeWindow: (timeWindow: string) => void
|
||||
timeWindow: TimeWindow
|
||||
onChangeTimeWindow: (timeWindow: TimeWindowOption) => void
|
||||
}
|
||||
|
||||
class LogViewerHeader extends PureComponent<Props> {
|
||||
|
@ -54,10 +53,10 @@ class LogViewerHeader extends PureComponent<Props> {
|
|||
|
||||
private get optionsComponents(): JSX.Element {
|
||||
const {
|
||||
timeRange,
|
||||
onShowOptionsOverlay,
|
||||
timeWindow,
|
||||
onChangeTimeWindow,
|
||||
onChooseTime,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
|
@ -80,8 +79,8 @@ class LogViewerHeader extends PureComponent<Props> {
|
|||
onChangeWindow={onChangeTimeWindow}
|
||||
/>
|
||||
<TimeRangeDropdown
|
||||
onChooseTimeRange={this.handleChooseTimeRange}
|
||||
selected={timeRange}
|
||||
onChooseTime={onChooseTime}
|
||||
selectedTime={timeWindow.timeOption}
|
||||
/>
|
||||
<Authorized requiredRole={EDITOR_ROLE}>
|
||||
<button
|
||||
|
@ -116,10 +115,6 @@ class LogViewerHeader extends PureComponent<Props> {
|
|||
)
|
||||
}
|
||||
|
||||
private handleChooseTimeRange = (timerange: TimeRange) => {
|
||||
this.props.onChooseTimerange(timerange)
|
||||
}
|
||||
|
||||
private handleChooseSource = (item: SourceItem) => {
|
||||
this.props.onChooseSource(item.id)
|
||||
}
|
||||
|
|
|
@ -1,185 +1,33 @@
|
|||
import React, {Component} from 'react'
|
||||
import classnames from 'classnames'
|
||||
import moment from 'moment'
|
||||
import _ from 'lodash'
|
||||
|
||||
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
|
||||
import timeRanges from 'src/logs/data/timeRanges'
|
||||
import {DROPDOWN_MENU_MAX_HEIGHT} from 'src/shared/constants/index'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
import {ClickOutside} from 'src/shared/components/ClickOutside'
|
||||
import CustomTimeRange from 'src/shared/components/CustomTimeRange'
|
||||
|
||||
import {TimeRange} from 'src/types'
|
||||
|
||||
const dateFormat = 'YYYY-MM-DD HH:mm'
|
||||
const emptyTime = {lower: '', upper: ''}
|
||||
const format = t => moment(t.replace(/\'/g, '')).format(dateFormat)
|
||||
import Dropdown from 'src/shared/components/Dropdown'
|
||||
|
||||
interface Props {
|
||||
selected: {
|
||||
lower: string
|
||||
upper?: string
|
||||
}
|
||||
|
||||
onChooseTimeRange: (timeRange: TimeRange) => void
|
||||
preventCustomTimeRange?: boolean
|
||||
page?: string
|
||||
selectedTime: string
|
||||
onChooseTime: (time: string) => void
|
||||
}
|
||||
|
||||
interface State {
|
||||
autobind: boolean
|
||||
isOpen: boolean
|
||||
isCustomTimeRangeOpen: boolean
|
||||
customTimeRange: TimeRange
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
class TimeRangeDropdown extends Component<Props, State> {
|
||||
public static defaultProps = {
|
||||
page: 'default',
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
const {lower, upper} = props.selected
|
||||
|
||||
const isTimeValid = moment(upper).isValid() && moment(lower).isValid()
|
||||
const customTimeRange = isTimeValid ? {lower, upper} : emptyTime
|
||||
|
||||
this.state = {
|
||||
autobind: false,
|
||||
isOpen: false,
|
||||
isCustomTimeRangeOpen: false,
|
||||
customTimeRange,
|
||||
}
|
||||
}
|
||||
|
||||
class TimeRangeDropdown extends Component<Props> {
|
||||
public render() {
|
||||
const {selected, preventCustomTimeRange, page} = this.props
|
||||
const {customTimeRange, isCustomTimeRangeOpen} = this.state
|
||||
const {selectedTime} = this.props
|
||||
const items = [{text: 'now'}, {text: '2018-07-10T22:22:21.769Z'}]
|
||||
|
||||
return (
|
||||
<ClickOutside onClickOutside={this.handleClickOutside}>
|
||||
<div className="time-range-dropdown">
|
||||
<div className={this.dropdownClassName}>
|
||||
<div
|
||||
className="btn btn-sm btn-default dropdown-toggle"
|
||||
onClick={this.toggleMenu}
|
||||
>
|
||||
<span className="icon clock" />
|
||||
<span className="dropdown-selected">
|
||||
{this.findTimeRangeInputValue(selected)}
|
||||
</span>
|
||||
<span className="caret" />
|
||||
</div>
|
||||
<ul className="dropdown-menu">
|
||||
<FancyScrollbar
|
||||
autoHide={false}
|
||||
autoHeight={true}
|
||||
maxHeight={DROPDOWN_MENU_MAX_HEIGHT}
|
||||
>
|
||||
{preventCustomTimeRange ? null : (
|
||||
<div>
|
||||
<li className="dropdown-header">Absolute Time</li>
|
||||
<li
|
||||
className={
|
||||
isCustomTimeRangeOpen
|
||||
? 'active dropdown-item custom-timerange'
|
||||
: 'dropdown-item custom-timerange'
|
||||
}
|
||||
>
|
||||
<a href="#" onClick={this.showCustomTimeRange}>
|
||||
Date Picker
|
||||
</a>
|
||||
</li>
|
||||
</div>
|
||||
)}
|
||||
<li className="dropdown-header">
|
||||
{preventCustomTimeRange ? '' : 'Relative '}Time
|
||||
</li>
|
||||
{timeRanges.map(item => {
|
||||
return (
|
||||
<li className="dropdown-item" key={item.menuOption}>
|
||||
<a href="#" onClick={this.handleSelection(item)}>
|
||||
{item.menuOption}
|
||||
</a>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</FancyScrollbar>
|
||||
</ul>
|
||||
</div>
|
||||
{isCustomTimeRangeOpen ? (
|
||||
<ClickOutside onClickOutside={this.handleCloseCustomTimeRange}>
|
||||
<div className="custom-time--overlay">
|
||||
<CustomTimeRange
|
||||
onApplyTimeRange={this.handleApplyCustomTimeRange}
|
||||
timeRange={customTimeRange}
|
||||
onClose={this.handleCloseCustomTimeRange}
|
||||
isVisible={isCustomTimeRangeOpen}
|
||||
timeInterval={60}
|
||||
page={page}
|
||||
/>
|
||||
</div>
|
||||
</ClickOutside>
|
||||
) : null}
|
||||
</div>
|
||||
</ClickOutside>
|
||||
<Dropdown
|
||||
onChoose={this.handleChoose}
|
||||
buttonSize="btn-sm"
|
||||
buttonColor="btn-default"
|
||||
selected={selectedTime}
|
||||
items={items}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
private get dropdownClassName(): string {
|
||||
const {isOpen} = this.state
|
||||
private handleChoose = time => {
|
||||
const {onChooseTime} = this.props
|
||||
const {text} = time
|
||||
|
||||
const {lower, upper} = _.get(this.props, 'selected', {upper: '', lower: ''})
|
||||
|
||||
const absoluteTimeRange = !_.isEmpty(lower) && !_.isEmpty(upper)
|
||||
|
||||
return classnames('dropdown', {
|
||||
'dropdown-290': absoluteTimeRange,
|
||||
'dropdown-120': !absoluteTimeRange,
|
||||
open: isOpen,
|
||||
})
|
||||
}
|
||||
|
||||
private findTimeRangeInputValue = ({upper, lower}: TimeRange) => {
|
||||
if (upper && lower) {
|
||||
if (upper === 'now()') {
|
||||
return `${format(lower)} - Now`
|
||||
}
|
||||
|
||||
return `${format(lower)} - ${format(upper)}`
|
||||
}
|
||||
|
||||
const selected = timeRanges.find(range => range.lower === lower)
|
||||
return selected ? selected.inputValue : 'Custom'
|
||||
}
|
||||
|
||||
private handleClickOutside = () => {
|
||||
this.setState({isOpen: false})
|
||||
}
|
||||
|
||||
private handleSelection = timeRange => () => {
|
||||
this.props.onChooseTimeRange(timeRange)
|
||||
this.setState({customTimeRange: emptyTime, isOpen: false})
|
||||
}
|
||||
|
||||
private toggleMenu = () => {
|
||||
this.setState({isOpen: !this.state.isOpen})
|
||||
}
|
||||
|
||||
private showCustomTimeRange = () => {
|
||||
this.setState({isCustomTimeRangeOpen: true})
|
||||
}
|
||||
|
||||
private handleApplyCustomTimeRange = customTimeRange => {
|
||||
this.props.onChooseTimeRange({...customTimeRange})
|
||||
this.setState({customTimeRange, isOpen: false})
|
||||
}
|
||||
|
||||
private handleCloseCustomTimeRange = () => {
|
||||
this.setState({isCustomTimeRangeOpen: false})
|
||||
onChooseTime(text)
|
||||
}
|
||||
}
|
||||
|
||||
export default TimeRangeDropdown
|
||||
|
|
|
@ -1,33 +1,28 @@
|
|||
import React, {Component} from 'react'
|
||||
import Dropdown from 'src/shared/components/Dropdown'
|
||||
import {TIME_RANGE_VALUES} from 'src/logs/constants'
|
||||
import {TimeWindow, TimeWindowOption} from 'src/types/logs'
|
||||
|
||||
interface Props {
|
||||
onChangeWindow: (timeWindow: string) => void
|
||||
selectedTimeWindow: string
|
||||
onChangeWindow: (timeWindow: TimeWindowOption) => void
|
||||
selectedTimeWindow: TimeWindow
|
||||
}
|
||||
|
||||
class WindowSelectorDropdown extends Component<Props> {
|
||||
public render() {
|
||||
const {selectedTimeWindow} = this.props
|
||||
const {selectedTimeWindow, onChangeWindow} = this.props
|
||||
const {windowOption} = selectedTimeWindow
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
selected={selectedTimeWindow}
|
||||
onChoose={this.handleChoose}
|
||||
selected={windowOption}
|
||||
onChoose={onChangeWindow}
|
||||
buttonSize="btn-sm"
|
||||
buttonColor="btn-default"
|
||||
items={TIME_RANGE_VALUES}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
public handleChoose = time => {
|
||||
const {onChangeWindow} = this.props
|
||||
const {text} = time
|
||||
|
||||
onChangeWindow(text)
|
||||
}
|
||||
}
|
||||
|
||||
export default WindowSelectorDropdown
|
||||
|
|
|
@ -147,8 +147,8 @@ export enum EncodingVisibilityOptions {
|
|||
}
|
||||
|
||||
export const TIME_RANGE_VALUES = [
|
||||
{text: '1m'},
|
||||
{text: '5m'},
|
||||
{text: '10m'},
|
||||
{text: '15m'},
|
||||
{text: '1m', seconds: 60},
|
||||
{text: '5m', seconds: 300},
|
||||
{text: '10m', seconds: 600},
|
||||
{text: '15m', seconds: 900},
|
||||
]
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
import uuid from 'uuid'
|
||||
import moment from 'moment'
|
||||
import _ from 'lodash'
|
||||
import {connect} from 'react-redux'
|
||||
import {AutoSizer} from 'react-virtualized'
|
||||
|
@ -46,6 +47,8 @@ import {
|
|||
LogsTableColumn,
|
||||
LogConfig,
|
||||
TableData,
|
||||
TimeWindow,
|
||||
TimeWindowOption,
|
||||
} from 'src/types/logs'
|
||||
|
||||
// Mock
|
||||
|
@ -59,7 +62,7 @@ interface Props {
|
|||
getSource: (sourceID: string) => void
|
||||
getSources: () => void
|
||||
setTimeRangeAsync: (timeRange: TimeRange) => void
|
||||
setTimeWindowAsync: (timeWindow: string) => void
|
||||
setTimeWindowAsync: (timeWindow: TimeWindow) => void
|
||||
setNamespaceAsync: (namespace: Namespace) => void
|
||||
changeZoomAsync: (timeRange: TimeRange) => void
|
||||
executeQueriesAsync: () => void
|
||||
|
@ -71,7 +74,7 @@ interface Props {
|
|||
getConfig: (url: string) => Promise<void>
|
||||
updateConfig: (url: string, config: LogConfig) => Promise<void>
|
||||
timeRange: TimeRange
|
||||
timeWindow: string
|
||||
timeWindow: TimeWindow
|
||||
histogramData: HistogramData
|
||||
tableData: TableData
|
||||
searchTerm: string
|
||||
|
@ -257,7 +260,6 @@ class LogsPage extends PureComponent<Props, State> {
|
|||
currentSource,
|
||||
currentNamespaces,
|
||||
currentNamespace,
|
||||
timeRange,
|
||||
timeWindow,
|
||||
} = this.props
|
||||
|
||||
|
@ -266,13 +268,12 @@ class LogsPage extends PureComponent<Props, State> {
|
|||
return (
|
||||
<LogViewerHeader
|
||||
timeWindow={timeWindow}
|
||||
onChangeTimeWindow={this.handleChooseTimeWindow}
|
||||
onChangeTimeWindow={this.transformWindowToRange}
|
||||
onChooseTime={this.transformTimeToRange}
|
||||
liveUpdating={liveUpdating && !this.isSpecificTimeRange}
|
||||
availableSources={sources}
|
||||
timeRange={timeRange}
|
||||
onChooseSource={this.handleChooseSource}
|
||||
onChooseNamespace={this.handleChooseNamespace}
|
||||
onChooseTimerange={this.handleChooseTimerange}
|
||||
currentSource={currentSource}
|
||||
currentNamespaces={currentNamespaces}
|
||||
currentNamespace={currentNamespace}
|
||||
|
@ -313,12 +314,43 @@ class LogsPage extends PureComponent<Props, State> {
|
|||
this.props.executeQueriesAsync()
|
||||
}
|
||||
|
||||
private handleChooseTimerange = (timeRange: TimeRange) => {
|
||||
this.props.setTimeRangeAsync(timeRange)
|
||||
this.fetchNewDataset()
|
||||
// private handleChooseTimerange = (timeRange: TimeRange) => {
|
||||
// console.log('TIME RANGE', timeRange)
|
||||
// this.props.setTimeRangeAsync(timeRange)
|
||||
// this.fetchNewDataset()
|
||||
// }
|
||||
|
||||
private transformTimeToRange = (timeOption: string) => {
|
||||
const {seconds, windowOption} = this.props.timeWindow
|
||||
let lower = `now() - ${windowOption}`
|
||||
let upper = null
|
||||
|
||||
if (timeOption !== 'now') {
|
||||
const numberTimeOption = moment(timeOption).valueOf()
|
||||
const milliseconds = seconds * 10 / 2
|
||||
|
||||
lower = moment(numberTimeOption - milliseconds).format()
|
||||
upper = moment(numberTimeOption + milliseconds).format()
|
||||
}
|
||||
|
||||
const timeWindow = {
|
||||
...this.props.timeWindow,
|
||||
lower,
|
||||
upper,
|
||||
timeOption,
|
||||
}
|
||||
|
||||
this.props.setTimeWindowAsync(timeWindow)
|
||||
}
|
||||
|
||||
private handleChooseTimeWindow = (timeWindow: string) => {
|
||||
private transformWindowToRange = (timeWindowOption: TimeWindowOption) => {
|
||||
const {text, seconds} = timeWindowOption
|
||||
const timeWindow = {
|
||||
...this.props.timeWindow,
|
||||
seconds,
|
||||
windowOption: text,
|
||||
}
|
||||
|
||||
this.props.setTimeWindowAsync(timeWindow)
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,13 @@ export const defaultState: LogsState = {
|
|||
currentSource: null,
|
||||
currentNamespaces: [],
|
||||
timeRange: {lower: 'now() - 1m', upper: null},
|
||||
timeWindow: '1m',
|
||||
timeWindow: {
|
||||
upper: null,
|
||||
lower: 'now() - 1m',
|
||||
seconds: 60,
|
||||
windowOption: '1m',
|
||||
timeOption: 'now',
|
||||
},
|
||||
currentNamespace: null,
|
||||
histogramQueryConfig: null,
|
||||
tableQueryConfig: null,
|
||||
|
|
|
@ -20,7 +20,7 @@ export interface LogsState {
|
|||
currentNamespaces: Namespace[]
|
||||
currentNamespace: Namespace | null
|
||||
timeRange: TimeRange
|
||||
timeWindow: string
|
||||
timeWindow: TimeWindow
|
||||
histogramQueryConfig: QueryConfig | null
|
||||
histogramData: object[]
|
||||
tableQueryConfig: QueryConfig | null
|
||||
|
@ -65,3 +65,16 @@ export interface ServerEncoding {
|
|||
type: string
|
||||
value: string
|
||||
}
|
||||
|
||||
export interface TimeWindow {
|
||||
upper?: string
|
||||
lower: string
|
||||
seconds?: number
|
||||
windowOption: string
|
||||
timeOption: string
|
||||
}
|
||||
|
||||
export interface TimeWindowOption {
|
||||
seconds: number
|
||||
text: string
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue