Skip to content

Commit

Permalink
fix(ui): improve single stat computation
Browse files Browse the repository at this point in the history
The method we used to compute a single stat / gauge value previously had
a few issues:

- If the latest value was part of a numeric column but was null/NaN/not
  defined, the single stat computation would fail and a user would see an
  error message "Could not display single stat because your values are
  non-numeric"
- If there were multiple latest values, an arbitrary selection would be
  made

This commit updates the single stat computation to find the latest
*defined* numeric values.

If multiple latest valid numeric values are found, we will either:

- Display an error message if using the compuation within a single stat
  visualization
- Display nothing if using the computation within a within a line +
  single stat visualization (i.e. display the line vis only)

The behavior is similar if no latest numeric value is found.

This commit also updates the single stat computation to use the
@influxdata/vis `Table` format as an intermediate/parsed representation
of a Flux CSV response. This unlocks the possibility for performance
gains in our CSV parsing. See #13852.

Closes #13824
  • Loading branch information
chnn committed May 8, 2019
1 parent aa5c774 commit 5390d35
Show file tree
Hide file tree
Showing 15 changed files with 307 additions and 499 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
1. [13800](https://github.com/influxdata/influxdb/pull/13800): Generate more idiomatic Flux in query builder
1. [13797](https://github.com/influxdata/influxdb/pull/13797): Expand tab key presses to 2 spaces in the Flux editor
1. [13823](https://github.com/influxdata/influxdb/pull/13823): Prevent dragging of Variable Dropdowns when dragging a scrollbar inside the dropdown
1. [13853](https://github.com/influxdata/influxdb/pull/13853): Improve single stat computation

### UI Improvements
1. [#13835](https://github.com/influxdata/influxdb/pull/13835): Render checkboxes in query builder tag selection lists
Expand Down
41 changes: 11 additions & 30 deletions ui/package-lock.json

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

80 changes: 19 additions & 61 deletions ui/src/shared/components/GaugeChart.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,71 +4,29 @@ import Gauge from 'src/shared/components/Gauge'
import GaugeChart from 'src/shared/components/GaugeChart'
import {ViewType, ViewShape, GaugeView} from 'src/types/dashboards'

const tables = [
{
id: '54797afd-734d-4ca3-94b6-3a7870c53b27',
data: [
['', 'result', 'table', '_time', 'mean', '_measurement'],
['', '', '0', '2018-09-27T16:50:10Z', '2', 'cpu'],
],
name: '_measurement=cpu',
groupKey: {
_measurement: 'cpu',
},
dataTypes: {
'': '#datatype',
result: 'string',
table: 'long',
_time: 'dateTime:RFC3339',
mean: 'double',
_measurement: 'string',
},
},
]

const properties: GaugeView = {
queries: [],
colors: [],
shape: ViewShape.ChronografV2,
type: ViewType.Gauge,
prefix: '',
suffix: '',
note: '',
showNoteWhenEmpty: false,
decimalPlaces: {
digits: 10,
isEnforced: false,
},
}

const defaultProps = {
tables: [],
properties,
}

const setup = (overrides = {}) => {
const props = {
...defaultProps,
...overrides,
}

return shallow(<GaugeChart {...props} />)
}

describe('GaugeChart', () => {
describe('render', () => {
describe('when data is empty', () => {
it('renders the correct number', () => {
const wrapper = setup()

expect(wrapper.find(Gauge).exists()).toBe(true)
expect(wrapper.find(Gauge).props().gaugePosition).toBe(0)
})
})

describe('when data has a value', () => {
it('renders the correct number', () => {
const wrapper = setup({tables})
const props = {
value: 2,
properties: {
queries: [],
colors: [],
shape: ViewShape.ChronografV2,
type: ViewType.Gauge,
prefix: '',
suffix: '',
note: '',
showNoteWhenEmpty: false,
decimalPlaces: {
digits: 10,
isEnforced: false,
},
} as GaugeView,
}

const wrapper = shallow(<GaugeChart {...props} />)

expect(wrapper.find(Gauge).exists()).toBe(true)
expect(wrapper.find(Gauge).props().gaugePosition).toBe(2)
Expand Down
15 changes: 3 additions & 12 deletions ui/src/shared/components/GaugeChart.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,26 @@
// Libraries
import React, {PureComponent} from 'react'
import memoizeOne from 'memoize-one'
import _ from 'lodash'

// Components
import Gauge from 'src/shared/components/Gauge'

// Parsing
import {lastValue} from 'src/shared/parsing/flux/lastValue'

// Types
import {FluxTable} from 'src/types'
import {GaugeView} from 'src/types/dashboards'

import {ErrorHandling} from 'src/shared/decorators/errors'

interface Props {
tables: FluxTable[]
value: number
properties: GaugeView
}

@ErrorHandling
class GaugeChart extends PureComponent<Props> {
private lastValue = memoizeOne(lastValue)

public render() {
const {tables} = this.props
const {value} = this.props
const {colors, prefix, suffix, decimalPlaces} = this.props.properties

const lastValue = this.lastValue(tables) || 0

return (
<div className="single-stat">
<Gauge
Expand All @@ -38,7 +29,7 @@ class GaugeChart extends PureComponent<Props> {
colors={colors}
prefix={prefix}
suffix={suffix}
gaugePosition={lastValue}
gaugePosition={value}
decimalPlaces={decimalPlaces}
/>
</div>
Expand Down
42 changes: 42 additions & 0 deletions ui/src/shared/components/LatestValueTransform.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Libraries
import React, {useMemo, FunctionComponent} from 'react'
import {Table} from '@influxdata/vis'

// Components
import EmptyGraphMessage from 'src/shared/components/EmptyGraphMessage'

// Utils
import {latestValues as getLatestValues} from 'src/shared/utils/latestValues'

interface Props {
table: Table
children: (latestValue: number) => JSX.Element

// If `quiet` is set and a single latest value can't be found, this component
// will display nothing instead of an empty graph error message
quiet?: boolean
}

const LatestValueTransform: FunctionComponent<Props> = ({
table,
quiet = false,
children,
}) => {
const latestValues = useMemo(() => getLatestValues(table), [table])

if (latestValues.length !== 1 && quiet) {
return null
}

if (latestValues.length === 0) {
return <EmptyGraphMessage message="No latest value found" />
}

if (latestValues.length > 1) {
return <EmptyGraphMessage message="Multiple latest values found" />
}

return children(latestValues[0])
}

export default LatestValueTransform
Loading

0 comments on commit 5390d35

Please sign in to comment.