Fix logs histogram bar click (#4863)
* Fix logs table rendering * Fix histogram bars * Add test for finding time option row index * Remove logs table query counting * Remove histogram chart fixes Removes the histogram chart axes changes and bar chart changes. * Update state query count * Fix histogram centering * update changelogpull/4874/head
parent
1728f2c5e2
commit
d508deecec
|
@ -10,6 +10,7 @@
|
|||
1. [4846](https://github.com/influxdata/chronograf/pull/4846): Fix missing data and type in refreshing graph
|
||||
1. [4861](https://github.com/influxdata/chronograf/pull/4861): Fix logs stuck in loading state
|
||||
1. [4847](https://github.com/influxdata/chronograf/pull/4847): Improve display of Flux Wizard on small screens
|
||||
1. [4863](https://github.com/influxdata/chronograf/pull/4863): Update logs histogram data on click and new search
|
||||
|
||||
### UI Improvements
|
||||
1. [#4809](https://github.com/influxdata/chronograf/pull/4809): Add loading spinners while fetching protoboards
|
||||
|
|
|
@ -57,6 +57,18 @@ export const saveToLocalStorage = ({
|
|||
'histogramData',
|
||||
'queryCount',
|
||||
'tableInfiniteData',
|
||||
'newRowsAdded',
|
||||
'searchStatus',
|
||||
'queryCount',
|
||||
'nextOlderUpperBound',
|
||||
'nextOlderLowerBound',
|
||||
'nextNewerUpperBound',
|
||||
'nextNewerLowerBound',
|
||||
'currentTailUpperBound',
|
||||
'nextTailLowerBound',
|
||||
'tailChunkDurationMs',
|
||||
'olderChunkDurationMs',
|
||||
'newerChunkDurationMs',
|
||||
])
|
||||
|
||||
window.localStorage.setItem(
|
||||
|
|
|
@ -52,6 +52,7 @@ import {
|
|||
import {INITIAL_LIMIT} from 'src/logs/actions'
|
||||
|
||||
interface Props {
|
||||
queryCount: number
|
||||
filters: Filter[]
|
||||
data: TableData
|
||||
isTruncated: boolean
|
||||
|
@ -86,7 +87,6 @@ interface State {
|
|||
isMessageVisible: boolean
|
||||
visibleColumnsCount: number
|
||||
searchPattern: string
|
||||
infiniteLoaderQueryCount: number
|
||||
}
|
||||
|
||||
const calculateScrollTop = scrollToRow => {
|
||||
|
@ -168,7 +168,6 @@ class LogsTable extends Component<Props, State> {
|
|||
scrollTop: 0,
|
||||
scrollLeft: 0,
|
||||
currentMessageWidth: 0,
|
||||
infiniteLoaderQueryCount: 0,
|
||||
isMessageVisible,
|
||||
visibleColumnsCount,
|
||||
}
|
||||
|
@ -302,6 +301,7 @@ class LogsTable extends Component<Props, State> {
|
|||
onSectionRendered: this.handleRowRender(onRowsRendered),
|
||||
columnCount,
|
||||
columnWidth: this.getColumnWidth,
|
||||
overscanRowCount: 50,
|
||||
ref: (ref: Grid) => {
|
||||
registerChild(ref)
|
||||
this.grid = ref
|
||||
|
@ -353,33 +353,11 @@ class LogsTable extends Component<Props, State> {
|
|||
}
|
||||
|
||||
private loadMoreAboveRows = async () => {
|
||||
try {
|
||||
this.incrementLoaderQueryCount()
|
||||
await this.props.fetchNewer()
|
||||
} finally {
|
||||
this.decrementLoaderQueryCount()
|
||||
}
|
||||
await this.props.fetchNewer()
|
||||
}
|
||||
|
||||
private loadMoreBelowRows = async () => {
|
||||
try {
|
||||
this.incrementLoaderQueryCount()
|
||||
await this.props.fetchMore()
|
||||
} finally {
|
||||
this.decrementLoaderQueryCount()
|
||||
}
|
||||
}
|
||||
|
||||
private incrementLoaderQueryCount() {
|
||||
this.setState(({infiniteLoaderQueryCount}) => ({
|
||||
infiniteLoaderQueryCount: infiniteLoaderQueryCount + 1,
|
||||
}))
|
||||
}
|
||||
|
||||
private decrementLoaderQueryCount() {
|
||||
this.setState(({infiniteLoaderQueryCount}) => ({
|
||||
infiniteLoaderQueryCount: infiniteLoaderQueryCount - 1,
|
||||
}))
|
||||
await this.props.fetchMore()
|
||||
}
|
||||
|
||||
private rowCount = (): number => {
|
||||
|
@ -664,7 +642,7 @@ class LogsTable extends Component<Props, State> {
|
|||
}
|
||||
|
||||
private get isLoadingMore(): boolean {
|
||||
return this.state.infiniteLoaderQueryCount > 0
|
||||
return this.props.queryCount > 0
|
||||
}
|
||||
|
||||
private get scrollLoadingIndicator(): JSX.Element {
|
||||
|
|
|
@ -27,6 +27,7 @@ import {colorForSeverity} from 'src/logs/utils/colors'
|
|||
import {
|
||||
applyChangesToTableData,
|
||||
isEmptyInfiniteData,
|
||||
findTimeOptionRow,
|
||||
} from 'src/logs/utils/table'
|
||||
import extentBy from 'src/utils/extentBy'
|
||||
import {computeTimeBounds} from 'src/logs/utils/timeBounds'
|
||||
|
@ -160,6 +161,7 @@ interface State {
|
|||
histogramColors: HistogramColor[]
|
||||
hasScrolled: boolean
|
||||
isLoadingNewer: boolean
|
||||
queryCount: number
|
||||
}
|
||||
|
||||
class LogsPage extends Component<Props, State> {
|
||||
|
@ -192,6 +194,7 @@ class LogsPage extends Component<Props, State> {
|
|||
isOverlayVisible: false,
|
||||
histogramColors: [],
|
||||
hasScrolled: false,
|
||||
queryCount: 0,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -279,6 +282,7 @@ class LogsPage extends Component<Props, State> {
|
|||
isTruncated={this.isTruncated}
|
||||
/>
|
||||
<LogsTable
|
||||
queryCount={this.state.queryCount}
|
||||
count={this.histogramTotal}
|
||||
data={this.tableData}
|
||||
onScrollVertical={this.handleVerticalScroll}
|
||||
|
@ -441,6 +445,8 @@ class LogsPage extends Component<Props, State> {
|
|||
chunkOptions
|
||||
)
|
||||
|
||||
this.updateQueryCount()
|
||||
|
||||
try {
|
||||
await this.currentNewerChunksGenerator.promise
|
||||
} catch (error) {
|
||||
|
@ -449,6 +455,7 @@ class LogsPage extends Component<Props, State> {
|
|||
|
||||
this.setState({isLoadingNewer: false})
|
||||
this.currentNewerChunksGenerator = null
|
||||
this.updateQueryCount()
|
||||
}
|
||||
|
||||
private startFetchingOlder = async () => {
|
||||
|
@ -462,6 +469,8 @@ class LogsPage extends Component<Props, State> {
|
|||
chunkOptions
|
||||
)
|
||||
|
||||
this.updateQueryCount()
|
||||
|
||||
try {
|
||||
await this.currentOlderChunksGenerator.promise
|
||||
} catch (error) {
|
||||
|
@ -469,6 +478,7 @@ class LogsPage extends Component<Props, State> {
|
|||
}
|
||||
|
||||
this.currentOlderChunksGenerator = null
|
||||
this.updateQueryCount()
|
||||
}
|
||||
|
||||
private clearTailInterval = () => {
|
||||
|
@ -491,14 +501,20 @@ class LogsPage extends Component<Props, State> {
|
|||
|
||||
this.currentNewerChunksGenerator = null
|
||||
this.currentOlderChunksGenerator = null
|
||||
this.setState({queryCount: 0})
|
||||
}
|
||||
|
||||
private get tableScrollToRow() {
|
||||
const {
|
||||
timeRange: {timeOption},
|
||||
} = this.props
|
||||
if (this.isLiveUpdating === true && !this.state.hasScrolled) {
|
||||
return 0
|
||||
}
|
||||
|
||||
if (this.state.isLoadingNewer && this.props.newRowsAdded) {
|
||||
if (!this.isLiveUpdating && timeOption && !this.state.hasScrolled) {
|
||||
return findTimeOptionRow(timeOption, this.props.tableInfiniteData, 0)
|
||||
} else if (this.state.isLoadingNewer && this.props.newRowsAdded) {
|
||||
return this.props.newRowsAdded || 0
|
||||
}
|
||||
|
||||
|
@ -902,6 +918,9 @@ class LogsPage extends Component<Props, State> {
|
|||
private fetchNewDataset = async () => {
|
||||
if (this.isLiveUpdating && this.shouldLiveUpdate) {
|
||||
this.startLogsTailFetchingInterval()
|
||||
} else if (!this.shouldLiveUpdate) {
|
||||
this.props.executeHistogramQueryAsync()
|
||||
this.handleFetchNewerChunk()
|
||||
}
|
||||
|
||||
await this.handleFetchOlderChunk()
|
||||
|
@ -1032,6 +1051,17 @@ class LogsPage extends Component<Props, State> {
|
|||
private get isMeasurementInNamespace(): boolean {
|
||||
return this.props.searchStatus !== SearchStatus.MeasurementMissing
|
||||
}
|
||||
|
||||
private updateQueryCount() {
|
||||
this.setState({queryCount: this.countCurrentQueries()})
|
||||
}
|
||||
|
||||
private countCurrentQueries(): number {
|
||||
return _.compact([
|
||||
this.currentNewerChunksGenerator,
|
||||
this.currentOlderChunksGenerator,
|
||||
]).length
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = ({
|
||||
|
|
|
@ -197,3 +197,24 @@ export const isEmptyInfiniteData = (data: {
|
|||
const isEmptyTableData = (data: TableData): boolean => {
|
||||
return getDeep(data, 'values.length', 0) === 0
|
||||
}
|
||||
|
||||
export const findTimeOptionRow = (
|
||||
timeOption: string,
|
||||
data: {
|
||||
forward: TableData
|
||||
backward: TableData
|
||||
},
|
||||
defaultIndex: number = 0
|
||||
): number => {
|
||||
const {forward, backward} = data
|
||||
const selectedTime = new Date(timeOption).valueOf()
|
||||
const timeColumn = forward.columns.indexOf('time')
|
||||
const tableData = [...forward.values, ...backward.values]
|
||||
const rowIndex = tableData.findIndex(row => row[timeColumn] <= selectedTime)
|
||||
|
||||
if (rowIndex < 0) {
|
||||
return defaultIndex
|
||||
}
|
||||
|
||||
return rowIndex
|
||||
}
|
||||
|
|
|
@ -17,15 +17,19 @@ export const computeTimeBounds = (
|
|||
const period = seconds * SECONDS_TO_MS
|
||||
const [lowerExtent] = extentTimes
|
||||
|
||||
if (!isValidExtent(extentTimes, period)) {
|
||||
if (!isValidExtent(numberTimeOption, extentTimes, period)) {
|
||||
return centerTimeBounds(numberTimeOption, period)
|
||||
} else {
|
||||
return offsetTimeBounds(lowerExtent, numberTimeOption, period)
|
||||
}
|
||||
}
|
||||
|
||||
const isValidExtent = ([t0, t1]: number[], period: number): boolean => {
|
||||
return t1 - t0 < period
|
||||
export const isValidExtent = (
|
||||
numberTimeOption: number,
|
||||
[t0, t1]: number[],
|
||||
period: number
|
||||
): boolean => {
|
||||
return t1 - t0 < period && t0 <= numberTimeOption && t1 >= numberTimeOption
|
||||
}
|
||||
|
||||
const centerTimeBounds = (center: number, period: number): TimeBounds => {
|
||||
|
|
|
@ -53,9 +53,8 @@ class HistogramChartAxes extends PureComponent<Props> {
|
|||
|
||||
private get xTickData() {
|
||||
const {margins, xScale, width, height} = this.props
|
||||
|
||||
const y = height - margins.bottom + X_TICK_PADDING_TOP
|
||||
const formatTime = xScale.tickFormat()
|
||||
const y = height - margins.bottom + X_TICK_PADDING_TOP
|
||||
|
||||
return xScale
|
||||
.ticks(X_TICK_COUNT)
|
||||
|
|
|
@ -77,6 +77,7 @@ const getBarGroups = ({
|
|||
|
||||
return timeGroups.map(timeGroup => {
|
||||
const time = timeGroup[0].time
|
||||
|
||||
const x = xScale(time) - barWidth / 2
|
||||
const total = _.sumBy(timeGroup, 'value')
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
import {findTimeOptionRow} from 'src/logs/utils/table'
|
||||
|
||||
describe('Logs.Utils.Table', () => {
|
||||
const infiniteTableData = {
|
||||
forward: {
|
||||
columns: ['time', 'noise'],
|
||||
values: [[8, 'beep'], [7, 'boop']],
|
||||
},
|
||||
backward: {
|
||||
columns: ['time', 'noise'],
|
||||
values: [[6, 'bloop'], [5, 'bleep']],
|
||||
},
|
||||
}
|
||||
|
||||
it('can find the most recent row index', () => {
|
||||
const timeOption = new Date(6).toISOString()
|
||||
|
||||
const actual = findTimeOptionRow(timeOption, infiniteTableData, 0)
|
||||
|
||||
expect(actual).toEqual(2)
|
||||
})
|
||||
})
|
|
@ -0,0 +1,36 @@
|
|||
import {isValidExtent} from 'src/logs/utils/timeBounds'
|
||||
|
||||
describe('Logs.Utils.TimeBounds', () => {
|
||||
describe('isValidExtent', () => {
|
||||
const extents = [1, 3]
|
||||
const period = 4
|
||||
|
||||
it('can invalidate a timeOption less than the extent', () => {
|
||||
const timeOption = 0
|
||||
const actual = isValidExtent(timeOption, extents, period)
|
||||
|
||||
expect(actual).toEqual(false)
|
||||
})
|
||||
|
||||
it('can invalidate a timeOption greater than the extent', () => {
|
||||
const timeOption = 4
|
||||
const actual = isValidExtent(timeOption, extents, period)
|
||||
|
||||
expect(actual).toEqual(false)
|
||||
})
|
||||
|
||||
it('can validate an in bounds timeOption', () => {
|
||||
const timeOption = 2
|
||||
const actual = isValidExtent(timeOption, extents, period)
|
||||
|
||||
expect(actual).toEqual(true)
|
||||
})
|
||||
|
||||
it('can invalidate an extent larger than the period', () => {
|
||||
const timeOption = 2
|
||||
const actual = isValidExtent(timeOption, [0, 200], 1)
|
||||
|
||||
expect(actual).toEqual(false)
|
||||
})
|
||||
})
|
||||
})
|
Loading…
Reference in New Issue