Adds autorefresh with play/pause
parent
955b2d278f
commit
3404d7375b
|
@ -17,9 +17,11 @@ interface Props {
|
|||
currentSource: Source | null
|
||||
currentNamespaces: Namespace[]
|
||||
timeRange: TimeRange
|
||||
liveUpdating: boolean
|
||||
onChooseSource: (sourceID: string) => void
|
||||
onChooseNamespace: (namespace: Namespace) => void
|
||||
onChooseTimerange: (timeRange: TimeRange) => void
|
||||
onChangeLiveUpdatingStatus: () => void
|
||||
}
|
||||
|
||||
class LogViewerHeader extends PureComponent<Props> {
|
||||
|
@ -29,7 +31,10 @@ class LogViewerHeader extends PureComponent<Props> {
|
|||
<div className="page-header full-width">
|
||||
<div className="page-header__container">
|
||||
<div className="page-header__left">
|
||||
<h1 className="page-header__title">Log Viewer</h1>
|
||||
{this.status}
|
||||
<h1 className="page-header__title" style={{marginLeft: '10px'}}>
|
||||
Log Viewer
|
||||
</h1>
|
||||
</div>
|
||||
<div className="page-header__right">
|
||||
<Dropdown
|
||||
|
@ -55,6 +60,29 @@ class LogViewerHeader extends PureComponent<Props> {
|
|||
)
|
||||
}
|
||||
|
||||
private get status(): JSX.Element {
|
||||
const {liveUpdating, onChangeLiveUpdatingStatus} = this.props
|
||||
if (liveUpdating) {
|
||||
return (
|
||||
<button
|
||||
className={'btn btn-sm btn-default btn-square'}
|
||||
onClick={onChangeLiveUpdatingStatus}
|
||||
>
|
||||
<span style={{marginRight: '10px'}} className="icon pause" />
|
||||
</button>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<button
|
||||
className={'btn btn-sm btn-default btn-square'}
|
||||
onClick={onChangeLiveUpdatingStatus}
|
||||
>
|
||||
<span style={{marginRight: '10px'}} className="icon refresh" />
|
||||
</button>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private handleChooseTimeRange = (timerange: TimeRange) => {
|
||||
this.props.onChooseTimerange(timerange)
|
||||
}
|
||||
|
|
|
@ -1,39 +1,64 @@
|
|||
import _ from 'lodash'
|
||||
import moment from 'moment'
|
||||
import React, {PureComponent, MouseEvent} from 'react'
|
||||
import React, {Component, MouseEvent} from 'react'
|
||||
import {Grid, AutoSizer} from 'react-virtualized'
|
||||
import {getDeep} from 'src/utils/wrappers'
|
||||
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
|
||||
|
||||
const ROW_HEIGHT = 40
|
||||
const ROW_HEIGHT = 30
|
||||
const HIGHLIGHT_COLOR = '#555'
|
||||
|
||||
interface Props {
|
||||
data: {
|
||||
columns: string[]
|
||||
values: string[]
|
||||
}
|
||||
scrolledToTop: boolean
|
||||
onScrollVertical: () => void
|
||||
onScrolledToTop: () => void
|
||||
}
|
||||
|
||||
interface State {
|
||||
scrollLeft: number
|
||||
scrollTop: number
|
||||
currentRow: number
|
||||
}
|
||||
|
||||
class LogsTable extends PureComponent<Props, State> {
|
||||
class LogsTable extends Component<Props, State> {
|
||||
public static getDerivedStateFromProps(props, state) {
|
||||
const {scrolledToTop} = props
|
||||
|
||||
let scrollTop = _.get(state, 'scrollTop', 0)
|
||||
if (scrolledToTop) {
|
||||
scrollTop = 0
|
||||
}
|
||||
|
||||
return {
|
||||
scrollTop,
|
||||
scrollLeft: 0,
|
||||
currentRow: -1,
|
||||
}
|
||||
}
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
scrollLeft: 0,
|
||||
scrollTop: 0,
|
||||
scrollLeft: 0,
|
||||
currentRow: -1,
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
const rowCount = getDeep(this.props, 'data.values.length', 0)
|
||||
const columnCount = getDeep(this.props, 'data.columns.length', 1) - 1
|
||||
|
||||
return (
|
||||
<div className="logs-viewer--table-container">
|
||||
<div
|
||||
className="logs-viewer--table-container"
|
||||
onMouseOut={this.handleMouseOut}
|
||||
>
|
||||
<AutoSizer>
|
||||
{({width}) => (
|
||||
<Grid
|
||||
|
@ -72,7 +97,7 @@ class LogsTable extends PureComponent<Props, State> {
|
|||
cellRenderer={this.cellRenderer}
|
||||
columnCount={columnCount}
|
||||
columnWidth={this.getColumnWidth}
|
||||
style={{height: 40 * rowCount}}
|
||||
style={{height: ROW_HEIGHT * rowCount}}
|
||||
/>
|
||||
</FancyScrollbar>
|
||||
)}
|
||||
|
@ -91,6 +116,12 @@ class LogsTable extends PureComponent<Props, State> {
|
|||
private handleScroll = scrollInfo => {
|
||||
const {scrollLeft, scrollTop} = scrollInfo
|
||||
|
||||
if (scrollTop === 0) {
|
||||
this.props.onScrolledToTop()
|
||||
} else if (scrollTop !== this.state.scrollTop) {
|
||||
this.props.onScrollVertical()
|
||||
}
|
||||
|
||||
this.setState({scrollLeft, scrollTop})
|
||||
}
|
||||
|
||||
|
@ -116,7 +147,7 @@ class LogsTable extends PureComponent<Props, State> {
|
|||
|
||||
switch (column) {
|
||||
case 'message':
|
||||
return 900
|
||||
return 1200
|
||||
case 'timestamp':
|
||||
return 200
|
||||
case 'procid':
|
||||
|
@ -168,7 +199,9 @@ class LogsTable extends PureComponent<Props, State> {
|
|||
''
|
||||
)
|
||||
|
||||
let value = this.props.data.values[rowIndex][columnIndex + 1]
|
||||
let value: string | JSX.Element = this.props.data.values[rowIndex][
|
||||
columnIndex + 1
|
||||
]
|
||||
|
||||
switch (column) {
|
||||
case 'timestamp':
|
||||
|
@ -181,22 +214,39 @@ class LogsTable extends PureComponent<Props, State> {
|
|||
value = _.replace(value, '\\n', '')
|
||||
break
|
||||
case 'severity':
|
||||
return (
|
||||
<div style={style} key={key}>
|
||||
<div
|
||||
className={`logs-viewer--dot ${value}-severity`}
|
||||
title={this.severityLevel(value)}
|
||||
/>
|
||||
</div>
|
||||
value = (
|
||||
<div
|
||||
className={`logs-viewer--dot ${value}-severity`}
|
||||
title={this.severityLevel(value)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
let backgroundColor = ''
|
||||
if (rowIndex === this.state.currentRow && columnIndex > 0) {
|
||||
backgroundColor = HIGHLIGHT_COLOR
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={style} key={key}>
|
||||
<div
|
||||
style={{...style, padding: '5px', backgroundColor}}
|
||||
key={key}
|
||||
onMouseOver={this.handleMouseOver}
|
||||
data-index={rowIndex}
|
||||
>
|
||||
{value}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
private handleMouseOver = (e: MouseEvent<HTMLElement>) => {
|
||||
const target = e.target as HTMLElement
|
||||
this.setState({currentRow: +target.dataset.index})
|
||||
}
|
||||
|
||||
private handleMouseOut = () => {
|
||||
this.setState({currentRow: -1})
|
||||
}
|
||||
}
|
||||
|
||||
export default LogsTable
|
||||
|
|
|
@ -51,25 +51,29 @@ interface Props {
|
|||
interface State {
|
||||
searchString: string
|
||||
filters: Filter[]
|
||||
liveUpdating: boolean
|
||||
}
|
||||
|
||||
const DUMMY_FILTERS = [
|
||||
{
|
||||
id: '0',
|
||||
key: 'host',
|
||||
value: 'prod1-rsavage.local',
|
||||
operator: '==',
|
||||
enabled: true,
|
||||
},
|
||||
// {
|
||||
// id: '0',
|
||||
// key: 'host',
|
||||
// value: 'prod1-rsavage.local',
|
||||
// operator: '==',
|
||||
// enabled: true,
|
||||
// },
|
||||
]
|
||||
|
||||
class LogsPage extends PureComponent<Props, State> {
|
||||
private interval: NodeJS.Timer
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
searchString: '',
|
||||
filters: DUMMY_FILTERS,
|
||||
liveUpdating: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,10 +89,16 @@ class LogsPage extends PureComponent<Props, State> {
|
|||
if (this.props.currentNamespace) {
|
||||
this.props.executeQueriesAsync()
|
||||
}
|
||||
|
||||
this.startUpdating()
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
clearInterval(this.interval)
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {filters} = this.state
|
||||
const {filters, liveUpdating} = this.state
|
||||
const {searchTerm} = this.props
|
||||
|
||||
const count = getDeep(this.props, 'tableData.values.length', 0)
|
||||
|
@ -107,12 +117,43 @@ class LogsPage extends PureComponent<Props, State> {
|
|||
filters={filters}
|
||||
onUpdateFilters={this.handleUpdateFilters}
|
||||
/>
|
||||
<LogsTable data={this.props.tableData} />
|
||||
<LogsTable
|
||||
data={this.props.tableData}
|
||||
onScrollVertical={this.handleVerticalScroll}
|
||||
onScrolledToTop={this.handleScrollToTop}
|
||||
scrolledToTop={liveUpdating}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
private startUpdating = () => {
|
||||
if (this.interval) {
|
||||
clearInterval(this.interval)
|
||||
}
|
||||
|
||||
this.interval = setInterval(this.handleInterval, 10000)
|
||||
this.setState({liveUpdating: true})
|
||||
}
|
||||
|
||||
private handleScrollToTop = () => {
|
||||
if (!this.state.liveUpdating) {
|
||||
this.startUpdating()
|
||||
}
|
||||
}
|
||||
|
||||
private handleVerticalScroll = () => {
|
||||
if (this.state.liveUpdating) {
|
||||
clearInterval(this.interval)
|
||||
this.setState({liveUpdating: false})
|
||||
}
|
||||
}
|
||||
|
||||
private handleInterval = () => {
|
||||
this.props.executeQueriesAsync()
|
||||
}
|
||||
|
||||
private get chart(): JSX.Element {
|
||||
const {histogramData, timeRange} = this.props
|
||||
return (
|
||||
|
@ -133,8 +174,11 @@ class LogsPage extends PureComponent<Props, State> {
|
|||
timeRange,
|
||||
} = this.props
|
||||
|
||||
const {liveUpdating} = this.state
|
||||
|
||||
return (
|
||||
<LogViewerHeader
|
||||
liveUpdating={liveUpdating}
|
||||
availableSources={sources}
|
||||
timeRange={timeRange}
|
||||
onChooseSource={this.handleChooseSource}
|
||||
|
@ -143,10 +187,22 @@ class LogsPage extends PureComponent<Props, State> {
|
|||
currentSource={currentSource}
|
||||
currentNamespaces={currentNamespaces}
|
||||
currentNamespace={currentNamespace}
|
||||
onChangeLiveUpdatingStatus={this.handleChangeLiveUpdatingStatus}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
private handleChangeLiveUpdatingStatus = (): void => {
|
||||
const {liveUpdating} = this.state
|
||||
|
||||
if (liveUpdating) {
|
||||
clearInterval(this.interval)
|
||||
this.setState({liveUpdating: false})
|
||||
} else {
|
||||
this.startUpdating()
|
||||
}
|
||||
}
|
||||
|
||||
private handleSubmitSearch = (value: string): void => {
|
||||
this.props.setSearchTermAsync(value)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue