diff --git a/ui/src/dashboards/components/GaugeOptions.js b/ui/src/dashboards/components/GaugeOptions.tsx similarity index 72% rename from ui/src/dashboards/components/GaugeOptions.js rename to ui/src/dashboards/components/GaugeOptions.tsx index bb378cd57f..400d89c689 100644 --- a/ui/src/dashboards/components/GaugeOptions.js +++ b/ui/src/dashboards/components/GaugeOptions.tsx @@ -1,31 +1,124 @@ -import React, {Component} from 'react' -import PropTypes from 'prop-types' +import React, {PureComponent} from 'react' import {connect} from 'react-redux' -import {bindActionCreators} from 'redux' import _ from 'lodash' import uuid from 'uuid' -import FancyScrollbar from 'shared/components/FancyScrollbar' +import FancyScrollbar from 'src/shared/components/FancyScrollbar' import Threshold from 'src/dashboards/components/Threshold' +import GraphOptionsDecimalPlaces from 'src/dashboards/components/GraphOptionsDecimalPlaces' import { COLOR_TYPE_THRESHOLD, THRESHOLD_COLORS, MAX_THRESHOLDS, MIN_THRESHOLDS, -} from 'shared/constants/thresholds' +} from 'src/shared/constants/thresholds' import { + changeDecimalPlaces, updateGaugeColors, updateAxes, } from 'src/dashboards/actions/cellEditorOverlay' -import {colorsNumberSchema} from 'shared/schemas' import {ErrorHandling} from 'src/shared/decorators/errors' +import {Axes} from 'src/types' +import {DecimalPlaces} from 'src/types/dashboards' +import {ColorNumber} from 'src/types/colors' + +interface Props { + axes: Axes + gaugeColors: ColorNumber[] + decimalPlaces: DecimalPlaces + onResetFocus: () => void + handleUpdateAxes: (a: Axes) => void + onUpdateDecimalPlaces: (d: DecimalPlaces) => void + handleUpdateGaugeColors: (d: ColorNumber[]) => void +} @ErrorHandling -class GaugeOptions extends Component { - handleAddThreshold = () => { +class GaugeOptions extends PureComponent { + public render() { + const {gaugeColors, axes, decimalPlaces} = this.props + const {y} = axes + + return ( + +
+
Gauge Controls
+
+ + {this.sortedGaugeColors.map((color, index) => ( + + ))} +
+
+
+ + +
+
+ + +
+ +
+
+
+ ) + } + + private get disableMaxColor(): boolean { + const {gaugeColors} = this.props + return gaugeColors.length > MIN_THRESHOLDS + } + + private get disableAddThreshold(): boolean { + const {gaugeColors} = this.props + return gaugeColors.length > MAX_THRESHOLDS + } + + private handleDecimalPlacesChange = (decimalPlaces: DecimalPlaces) => { + const {onUpdateDecimalPlaces} = this.props + onUpdateDecimalPlaces(decimalPlaces) + } + + private handleAddThreshold = () => { const {gaugeColors, handleUpdateGaugeColors, onResetFocus} = this.props const sortedColors = _.sortBy(gaugeColors, color => color.value) @@ -50,7 +143,7 @@ class GaugeOptions extends Component { name: THRESHOLD_COLORS[randomColor].name, } - const updatedColors = _.sortBy( + const updatedColors: ColorNumber[] = _.sortBy( [...gaugeColors, newThreshold], color => color.value ) @@ -61,7 +154,7 @@ class GaugeOptions extends Component { } } - handleDeleteThreshold = threshold => { + private handleDeleteThreshold = threshold => { const {handleUpdateGaugeColors, onResetFocus} = this.props const gaugeColors = this.props.gaugeColors.filter( color => color.id !== threshold.id @@ -72,7 +165,7 @@ class GaugeOptions extends Component { onResetFocus() } - handleChooseColor = threshold => { + private handleChooseColor = threshold => { const {handleUpdateGaugeColors} = this.props const gaugeColors = this.props.gaugeColors.map( color => @@ -84,7 +177,7 @@ class GaugeOptions extends Component { handleUpdateGaugeColors(gaugeColors) } - handleUpdateColorValue = (threshold, value) => { + private handleUpdateColorValue = (threshold, value) => { const {handleUpdateGaugeColors} = this.props const gaugeColors = this.props.gaugeColors.map( color => (color.id === threshold.id ? {...color, value} : color) @@ -93,7 +186,7 @@ class GaugeOptions extends Component { handleUpdateGaugeColors(gaugeColors) } - handleValidateColorValue = (threshold, targetValue) => { + private handleValidateColorValue = (threshold, targetValue) => { const {gaugeColors} = this.props const thresholdValue = threshold.value @@ -134,14 +227,14 @@ class GaugeOptions extends Component { return allowedToUpdate } - handleUpdatePrefix = e => { + private handleUpdatePrefix = e => { const {handleUpdateAxes, axes} = this.props const newAxes = {...axes, y: {...axes.y, prefix: e.target.value}} handleUpdateAxes(newAxes) } - handleUpdateSuffix = e => { + private handleUpdateSuffix = e => { const {handleUpdateAxes, axes} = this.props const newAxes = {...axes, y: {...axes.y, suffix: e.target.value}} @@ -154,98 +247,23 @@ class GaugeOptions extends Component { return sortedColors } - - render() { - const { - gaugeColors, - axes: { - y: {prefix, suffix}, - }, - } = this.props - - const disableMaxColor = gaugeColors.length > MIN_THRESHOLDS - const disableAddThreshold = gaugeColors.length > MAX_THRESHOLDS - - return ( - -
-
Gauge Controls
-
- - {this.sortedGaugeColors.map((color, index) => ( - - ))} -
-
-
- - -
-
- - -
-
-
-
- ) - } -} - -const {func, shape} = PropTypes - -GaugeOptions.propTypes = { - gaugeColors: colorsNumberSchema, - handleUpdateGaugeColors: func.isRequired, - handleUpdateAxes: func.isRequired, - axes: shape({}).isRequired, - onResetFocus: func.isRequired, } const mapStateToProps = ({ cellEditorOverlay: { gaugeColors, - cell: {axes}, + cell: {axes, decimalPlaces}, }, }) => ({ + decimalPlaces, gaugeColors, axes, }) -const mapDispatchToProps = dispatch => ({ - handleUpdateGaugeColors: bindActionCreators(updateGaugeColors, dispatch), - handleUpdateAxes: bindActionCreators(updateAxes, dispatch), -}) +const mapDispatchToProps = { + handleUpdateGaugeColors: updateGaugeColors, + handleUpdateAxes: updateAxes, + onUpdateDecimalPlaces: changeDecimalPlaces, +} + export default connect(mapStateToProps, mapDispatchToProps)(GaugeOptions) diff --git a/ui/src/shared/components/Gauge.js b/ui/src/shared/components/Gauge.js index 0371d09a31..468616ba98 100644 --- a/ui/src/shared/components/Gauge.js +++ b/ui/src/shared/components/Gauge.js @@ -283,6 +283,7 @@ class Gauge extends Component { drawGaugeValue = (ctx, radius, labelValueFontSize) => { const {gaugePosition, prefix, suffix} = this.props const {valueColor} = GAUGE_SPECS + const maximumFractionDigits = 20 ctx.font = `${labelValueFontSize}px Roboto` ctx.fillStyle = valueColor @@ -290,7 +291,9 @@ class Gauge extends Component { ctx.textAlign = 'center' const textY = radius - const textContent = `${prefix}${gaugePosition.toLocaleString()}${suffix}` + const textContent = `${prefix}${gaugePosition.toLocaleString(undefined, { + maximumFractionDigits, + })}${suffix}` ctx.fillText(textContent, 0, textY) } diff --git a/ui/src/shared/components/GaugeChart.tsx b/ui/src/shared/components/GaugeChart.tsx index f2b9a82cfb..1e2fcb6dc8 100644 --- a/ui/src/shared/components/GaugeChart.tsx +++ b/ui/src/shared/components/GaugeChart.tsx @@ -8,6 +8,7 @@ import {DEFAULT_GAUGE_COLORS} from 'src/shared/constants/thresholds' import {stringifyColorValues} from 'src/shared/constants/colorOperations' import {DASHBOARD_LAYOUT_ROW_HEIGHT} from 'src/shared/constants' import {ErrorHandling} from 'src/shared/decorators/errors' +import {DecimalPlaces} from 'src/types/dashboards' interface Color { type: string @@ -19,6 +20,7 @@ interface Color { interface Props { data: TimeSeriesResponse[] + decimalPlaces: DecimalPlaces isFetchingInitially: boolean cellID: string cellHeight?: number @@ -76,11 +78,19 @@ class GaugeChart extends PureComponent { } private get lastValueForGauge(): number { - const {data} = this.props + const {data, decimalPlaces} = this.props const {lastValues} = getLastValues(data) - const precision = 100.0 + let lastValue = _.get(lastValues, 0, 0) - return Math.round(_.get(lastValues, 0, 0) * precision) / precision + if (lastValue === null) { + return 0 + } + + if (decimalPlaces.isEnforced) { + lastValue = +lastValue.toFixed(decimalPlaces.digits) + } + + return lastValue } } diff --git a/ui/src/shared/components/RefreshingGraph.js b/ui/src/shared/components/RefreshingGraph.js index 497b3058b1..1ff4a61537 100644 --- a/ui/src/shared/components/RefreshingGraph.js +++ b/ui/src/shared/components/RefreshingGraph.js @@ -83,20 +83,21 @@ const RefreshingGraph = ({ if (type === 'gauge') { return ( ) diff --git a/ui/src/shared/components/SingleStat.tsx b/ui/src/shared/components/SingleStat.tsx index 95fc2fc701..78416998e6 100644 --- a/ui/src/shared/components/SingleStat.tsx +++ b/ui/src/shared/components/SingleStat.tsx @@ -75,6 +75,11 @@ class SingleStat extends PureComponent { private get roundedLastValue(): string { const {decimalPlaces} = this.props + + if (this.lastValue === null) { + return `${0}` + } + let roundedValue = `${this.lastValue}` if (decimalPlaces.isEnforced) { @@ -85,7 +90,8 @@ class SingleStat extends PureComponent { } private formatToLocale(n: number): string { - return n.toLocaleString() + const maximumFractionDigits = 20 + return n.toLocaleString(undefined, {maximumFractionDigits}) } private get containerStyle(): CSSProperties { diff --git a/ui/test/shared/components/GaugeChart.test.tsx b/ui/test/shared/components/GaugeChart.test.tsx index 3a35e568df..f41cb13c44 100644 --- a/ui/test/shared/components/GaugeChart.test.tsx +++ b/ui/test/shared/components/GaugeChart.test.tsx @@ -26,6 +26,10 @@ const defaultProps = { cellID: '', prefix: '', suffix: '', + decimalPlaces: { + digits: 10, + isEnforced: false, + }, } const setup = (overrides = {}) => {