fix(ui): fix decimalPlaces with wrapper (#5073)
parent
0913f97b67
commit
ca9f8ace80
|
@ -1,8 +1,9 @@
|
|||
## v1.7.8 [2019-02-08]
|
||||
### Bug Fixes
|
||||
1. [#5068](https://github.com/influxdata/chronograf/pull/5068): Escape injected meta query values
|
||||
1. [#5073](https://github.com/influxdata/chronograf/pull/5073): Fix out of range decimal places
|
||||
|
||||
## v1.7.7 [2019-01-16]
|
||||
## v1.7.7 [2018-01-16]
|
||||
|
||||
### Bug Fixes
|
||||
1. [#5045](https://github.com/influxdata/chronograf/pull/5045): Use JWT in enterprise for authentication in flux
|
||||
|
|
|
@ -15,6 +15,7 @@ import {
|
|||
} from 'src/types/dashboards'
|
||||
import {TimeSeriesValue, InfluxQLQueryType} from 'src/types/series'
|
||||
import {DataType} from 'src/shared/constants'
|
||||
import {isTruncatedNumber, toFixed} from 'src/shared/utils/decimalPlaces'
|
||||
|
||||
const calculateSize = (message: string): number => {
|
||||
return message.length * 7
|
||||
|
@ -89,8 +90,8 @@ const updateMaxWidths = (
|
|||
let colValue = `${col}`
|
||||
if (foundField && foundField.displayName) {
|
||||
colValue = foundField.displayName
|
||||
} else if (_.isNumber(col) && decimalPlaces.isEnforced) {
|
||||
colValue = col.toFixed(decimalPlaces.digits)
|
||||
} else if (isTruncatedNumber(col, decimalPlaces)) {
|
||||
colValue = toFixed(col, decimalPlaces)
|
||||
}
|
||||
|
||||
const columnLabel = topRow[c]
|
||||
|
@ -301,5 +302,18 @@ export const transformTableData = (
|
|||
- `parseFloat('02abc')` is 2
|
||||
|
||||
*/
|
||||
export const isNumerical = (x: any): boolean =>
|
||||
!isNaN(Number(x)) && !isNaN(parseFloat(x))
|
||||
export const isNumerical = <T>(x: T | string): x is string =>
|
||||
!isNaN(Number(x)) && !isNaN(parseFloat(x as string))
|
||||
|
||||
export const formatNumericCell = (
|
||||
cellData: string,
|
||||
decimalPlaces: DecimalPlaces
|
||||
) => {
|
||||
const cellValue = parseFloat(cellData)
|
||||
|
||||
if (isTruncatedNumber(cellValue, decimalPlaces)) {
|
||||
return toFixed(cellValue, decimalPlaces)
|
||||
}
|
||||
|
||||
return `${cellValue}`
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ import uuid from 'uuid'
|
|||
import ClickOutsideInput from 'src/shared/components/ClickOutsideInput'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
import {toValueInRange} from 'src/shared/utils/decimalPlaces'
|
||||
|
||||
interface Props {
|
||||
min?: string
|
||||
max?: string
|
||||
|
@ -123,10 +125,18 @@ export default class OptIn extends Component<Props, State> {
|
|||
this.useCustomValue()
|
||||
}
|
||||
|
||||
// Typing into number inputs does not enforce min/max
|
||||
private handleChangeCustomValue = (
|
||||
e: ChangeEvent<HTMLInputElement>
|
||||
): void => {
|
||||
this.setCustomValue(e.target.value)
|
||||
const {min, max} = this.props
|
||||
const {value} = e.target
|
||||
|
||||
if (value === '') {
|
||||
this.setCustomValue('')
|
||||
} else {
|
||||
this.setCustomValue(toValueInRange(value, min, max))
|
||||
}
|
||||
}
|
||||
|
||||
private handleKeyDownCustomValueInput = (
|
||||
|
|
|
@ -18,6 +18,7 @@ import {
|
|||
} from 'src/shared/graphs/helpers'
|
||||
import getLastValues from 'src/shared/parsing/lastValues'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
import {isTruncatedNumber, toFixed} from 'src/shared/utils/decimalPlaces'
|
||||
|
||||
// Constants
|
||||
import {DYGRAPH_CONTAINER_V_MARGIN} from 'src/shared/constants'
|
||||
|
@ -155,8 +156,8 @@ class SingleStat extends PureComponent<Props, State> {
|
|||
|
||||
let roundedValue = `${this.lastValue}`
|
||||
|
||||
if (decimalPlaces.isEnforced && _.isNumber(this.lastValue)) {
|
||||
roundedValue = this.lastValue.toFixed(decimalPlaces.digits)
|
||||
if (isTruncatedNumber(this.lastValue, decimalPlaces)) {
|
||||
roundedValue = toFixed(this.lastValue, decimalPlaces)
|
||||
}
|
||||
|
||||
return this.formatToLocale(+roundedValue)
|
||||
|
|
|
@ -12,7 +12,11 @@ import {MultiGrid, PropsMultiGrid} from 'src/shared/components/MultiGrid'
|
|||
// Utils
|
||||
import {fastReduce} from 'src/utils/fast'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
import {getDefaultTimeField, isNumerical} from 'src/dashboards/utils/tableGraph'
|
||||
import {
|
||||
getDefaultTimeField,
|
||||
isNumerical,
|
||||
formatNumericCell,
|
||||
} from 'src/dashboards/utils/tableGraph'
|
||||
|
||||
// Constants
|
||||
import {
|
||||
|
@ -443,12 +447,8 @@ class TableGraph extends PureComponent<Props, State> {
|
|||
return _.defaultTo(fieldName, '').toString()
|
||||
}
|
||||
|
||||
if (
|
||||
isNumerical(cellData) &&
|
||||
decimalPlaces.isEnforced &&
|
||||
decimalPlaces.digits < 100
|
||||
) {
|
||||
return parseFloat(cellData as any).toFixed(decimalPlaces.digits)
|
||||
if (isNumerical(cellData)) {
|
||||
return formatNumericCell(cellData, decimalPlaces)
|
||||
}
|
||||
|
||||
return _.defaultTo(cellData, '').toString()
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
import {DecimalPlaces} from 'src/types/dashboards'
|
||||
import {isNumerical} from 'src/dashboards/utils/tableGraph'
|
||||
import {isFinite} from 'lodash'
|
||||
|
||||
export const isTruncatedNumber = <T>(
|
||||
value: T | number,
|
||||
decimalPlaces: DecimalPlaces
|
||||
): value is number => isFinite(value) && decimalPlaces.isEnforced
|
||||
|
||||
export const toFixed = (
|
||||
value: number,
|
||||
decimalPlaces: DecimalPlaces
|
||||
): string => {
|
||||
const {digits} = decimalPlaces
|
||||
|
||||
if (!isFinite(digits)) {
|
||||
return `${value}`
|
||||
} else if (digits < 0) {
|
||||
return value.toFixed(0)
|
||||
} else if (digits > 20) {
|
||||
return value.toFixed(20)
|
||||
}
|
||||
|
||||
return value.toFixed(digits)
|
||||
}
|
||||
|
||||
export const toValueInRange = (
|
||||
stringValue: string,
|
||||
min: string,
|
||||
max: string
|
||||
): string => {
|
||||
if (!isNumerical(stringValue)) {
|
||||
return min
|
||||
}
|
||||
|
||||
const value = +parseFloat(stringValue).toFixed(0)
|
||||
|
||||
if (value < +min) {
|
||||
return min
|
||||
} else if (value > +max) {
|
||||
return max
|
||||
} else {
|
||||
return `${value}`
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
import {
|
||||
isTruncatedNumber,
|
||||
toFixed,
|
||||
toValueInRange,
|
||||
} from 'src/shared/utils/decimalPlaces'
|
||||
|
||||
describe('decimalPlaces', () => {
|
||||
const digits = (d: number) => ({isEnforced: true, digits: d})
|
||||
describe('.toFixed', () => {
|
||||
it('can skip fixing nonFinite digits', () => {
|
||||
expect(toFixed(20.123456789, digits(Infinity))).toBe('20.123456789')
|
||||
expect(toFixed(20.123456789, digits(-Infinity))).toBe('20.123456789')
|
||||
expect(toFixed(20.123456789, digits(NaN))).toBe('20.123456789')
|
||||
})
|
||||
|
||||
it('caps fixed digits to 20 decimal places', () => {
|
||||
const value = 0.000000000931322574615478515625
|
||||
expect(toFixed(value, digits(25))).toBe('0.00000000093132257462')
|
||||
})
|
||||
|
||||
it('treats negative decimal places as 0', () => {
|
||||
expect(toFixed(1234.56, digits(-1))).toBe('1235')
|
||||
expect(toFixed(1234.12, digits(-1))).toBe('1234')
|
||||
})
|
||||
})
|
||||
|
||||
describe('.isTruncatedNumber', () => {
|
||||
it('can return false for non finite numbers', () => {
|
||||
expect(isTruncatedNumber(Infinity, digits(0))).toBe(false)
|
||||
expect(isTruncatedNumber(-Infinity, digits(0))).toBe(false)
|
||||
expect(isTruncatedNumber(-NaN, digits(0))).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('.toValueInRange', () => {
|
||||
it('can return an integer value when provided a float', () => {
|
||||
expect(toValueInRange('1.2', '0', '10')).toBe('1')
|
||||
})
|
||||
|
||||
it('can enforce the min', () => {
|
||||
expect(toValueInRange('1', '5', '10')).toBe('5')
|
||||
})
|
||||
|
||||
it('can enforce the max', () => {
|
||||
expect(toValueInRange('11', '-5', '0')).toBe('0')
|
||||
})
|
||||
|
||||
it('can default to min', () => {
|
||||
expect(toValueInRange('', '9999', '10000')).toBe('9999')
|
||||
expect(toValueInRange('----', '9999', '10000')).toBe('9999')
|
||||
expect(toValueInRange('-++++', '9999', '10000')).toBe('9999')
|
||||
})
|
||||
})
|
||||
})
|
Loading…
Reference in New Issue