Merge pull request #3162 from influxdata/fix/graph-threshold-size

Only send threshold value to parent on blur
feature/cell-notes
Brandon Farmer 2018-04-10 11:38:34 -07:00 committed by GitHub
commit e2f7fcfe1a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 219 additions and 148 deletions

View File

@ -30,6 +30,7 @@
1. [#3144](https://github.com/influxdata/chronograf/pull/3144): Ensure correct basepath prefix in URL pathname when passing InfluxQL query param to Data Explorer
1. [#3128](https://github.com/influxdata/chronograf/pull/3128): Fix type error bug in Kapacitor Alert Config page and persist deleting of team and recipient in OpsGenieConfig
1. [#3149](https://github.com/influxdata/chronograf/pull/3149): Fixes errors caused by switching query tabs in CEO
1. [#3162](https://github.com/influxdata/chronograf/pull/3162): Only send threshold value to parent on blur
## v1.4.3.1 [2018-04-02]

View File

@ -123,7 +123,7 @@ class GaugeOptions extends Component {
)
const isUnique = !colorsWithoutMinOrMax.some(
color => color.value === targetValue
color => color.value === targetValue && color.id !== threshold.id
)
allowedToUpdate = greaterThanMin && lessThanMax && isUnique
@ -146,11 +146,11 @@ class GaugeOptions extends Component {
handleUpdateAxes(newAxes)
}
handleSortColors = () => {
const {gaugeColors, handleUpdateGaugeColors} = this.props
const sortedColors = _.sortBy(gaugeColors, color => color.value)
get sortedGaugeColors() {
const {gaugeColors} = this.props
const sortedColors = _.sortBy(gaugeColors, 'value')
handleUpdateGaugeColors(sortedColors)
return sortedColors
}
render() {
@ -174,12 +174,10 @@ class GaugeOptions extends Component {
>
<span className="icon plus" /> Add Threshold
</button>
{gaugeColors.map(color => (
{this.sortedGaugeColors.map((color, index) => (
<Threshold
isMin={color.value === gaugeColors[0].value}
isMax={
color.value === gaugeColors[gaugeColors.length - 1].value
}
isMin={index === 0}
isMax={index === gaugeColors.length - 1}
visualizationType="gauge"
threshold={color}
key={uuid.v4()}
@ -188,7 +186,6 @@ class GaugeOptions extends Component {
onValidateColorValue={this.handleValidateColorValue}
onUpdateColorValue={this.handleUpdateColorValue}
onDeleteThreshold={this.handleDeleteThreshold}
onSortColors={this.handleSortColors}
/>
))}
</div>

View File

@ -1,131 +0,0 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import ColorDropdown from 'shared/components/ColorDropdown'
import {THRESHOLD_COLORS} from 'shared/constants/thresholds'
class Threshold extends Component {
constructor(props) {
super(props)
this.state = {
workingValue: this.props.threshold.value,
valid: true,
}
}
handleChangeWorkingValue = e => {
const {threshold, onValidateColorValue, onUpdateColorValue} = this.props
const targetValue = Number(e.target.value)
const valid = onValidateColorValue(threshold, targetValue)
if (valid) {
onUpdateColorValue(threshold, targetValue)
}
this.setState({valid, workingValue: targetValue})
}
handleBlur = () => {
this.setState({workingValue: this.props.threshold.value, valid: true})
this.props.onSortColors()
}
handleKeyUp = e => {
if (e.key === 'Enter') {
this.thresholdInputRef.blur()
}
}
render() {
const {
visualizationType,
threshold,
threshold: {hex, name},
disableMaxColor,
onChooseColor,
onDeleteThreshold,
isMin,
isMax,
} = this.props
const {workingValue, valid} = this.state
const selectedColor = {hex, name}
let label = 'Threshold'
let labelClass = 'threshold-item--label__editable'
let canBeDeleted = true
if (visualizationType === 'gauge') {
labelClass =
isMin || isMax
? 'threshold-item--label'
: 'threshold-item--label__editable'
canBeDeleted = !(isMin || isMax)
}
if (isMin && visualizationType === 'gauge') {
label = 'Minimum'
}
if (isMax && visualizationType === 'gauge') {
label = 'Maximum'
}
const inputClass = valid
? 'form-control input-sm threshold-item--input'
: 'form-control input-sm threshold-item--input form-volcano'
return (
<div className="threshold-item">
<div className={labelClass}>{label}</div>
{canBeDeleted ? (
<button
className="btn btn-default btn-sm btn-square"
onClick={onDeleteThreshold(threshold)}
>
<span className="icon remove" />
</button>
) : null}
<input
value={workingValue}
className={inputClass}
type="number"
onChange={this.handleChangeWorkingValue}
onBlur={this.handleBlur}
onKeyUp={this.handleKeyUp}
ref={r => (this.thresholdInputRef = r)}
/>
<ColorDropdown
colors={THRESHOLD_COLORS}
selected={selectedColor}
onChoose={onChooseColor(threshold)}
disabled={isMax && disableMaxColor}
/>
</div>
)
}
}
const {bool, func, number, shape, string} = PropTypes
Threshold.propTypes = {
visualizationType: string.isRequired,
threshold: shape({
type: string.isRequired,
hex: string.isRequired,
id: string.isRequired,
name: string.isRequired,
value: number.isRequired,
}).isRequired,
disableMaxColor: bool,
onChooseColor: func.isRequired,
onValidateColorValue: func.isRequired,
onUpdateColorValue: func.isRequired,
onDeleteThreshold: func.isRequired,
isMin: bool,
isMax: bool,
onSortColors: func.isRequired,
}
export default Threshold

View File

@ -0,0 +1,176 @@
import React, {PureComponent, ChangeEvent, KeyboardEvent} from 'react'
import ColorDropdown from 'src/shared/components/ColorDropdown'
import {THRESHOLD_COLORS} from 'src/shared/constants/thresholds'
interface SelectedColor {
hex: string
name: string
}
interface ThresholdProps {
type: string
hex: string
id: string
name: string
value: number
}
interface Props {
visualizationType: string
threshold: ThresholdProps
disableMaxColor: boolean
onChooseColor: (threshold: ThresholdProps) => void
onValidateColorValue: (
threshold: ThresholdProps,
targetValue: number
) => boolean
onUpdateColorValue: (threshold: ThresholdProps, targetValue: number) => void
onDeleteThreshold: (threshold: ThresholdProps) => void
isMin: boolean
isMax: boolean
}
interface State {
workingValue: number
valid: boolean
}
class Threshold extends PureComponent<Props, State> {
private thresholdInputRef: HTMLInputElement
constructor(props) {
super(props)
this.state = {
workingValue: this.props.threshold.value,
valid: true,
}
}
public render() {
const {threshold, disableMaxColor, onChooseColor, isMax} = this.props
const {workingValue} = this.state
return (
<div className="threshold-item">
<div className={this.labelClass}>{this.label}</div>
{this.canBeDeleted ? (
<button
className="btn btn-default btn-sm btn-square"
onClick={this.handleDelete}
>
<span className="icon remove" />
</button>
) : null}
<input
value={workingValue}
className={this.inputClass}
type="number"
onChange={this.handleChangeWorkingValue}
onBlur={this.handleBlur}
onKeyUp={this.handleKeyUp}
ref={this.handleInputRef}
/>
<ColorDropdown
colors={THRESHOLD_COLORS}
selected={this.selectedColor}
onChoose={onChooseColor(threshold)}
disabled={isMax && disableMaxColor}
/>
</div>
)
}
private get selectedColor(): SelectedColor {
const {threshold: {hex, name}} = this.props
return {hex, name}
}
private get inputClass(): string {
const {valid} = this.state
const inputClass = valid
? 'form-control input-sm threshold-item--input'
: 'form-control input-sm threshold-item--input form-volcano'
return inputClass
}
private get canBeDeleted(): boolean {
const {visualizationType, isMax, isMin} = this.props
let canBeDeleted = true
if (visualizationType === 'gauge') {
canBeDeleted = !(isMin || isMax)
}
return canBeDeleted
}
private get labelClass(): string {
const {visualizationType, isMax, isMin} = this.props
let labelClass = 'threshold-item--label__editable'
if (visualizationType === 'gauge') {
labelClass =
isMin || isMax
? 'threshold-item--label'
: 'threshold-item--label__editable'
}
return labelClass
}
private get label(): string {
let label = 'Threshold'
const {visualizationType, isMax, isMin} = this.props
if (isMin && visualizationType === 'gauge') {
label = 'Minimum'
}
if (isMax && visualizationType === 'gauge') {
label = 'Maximum'
}
return label
}
private handleChangeWorkingValue = (e: ChangeEvent<HTMLInputElement>) => {
const {threshold, onValidateColorValue} = this.props
const targetValue = Number(e.target.value)
const valid = onValidateColorValue(threshold, targetValue)
this.setState({valid, workingValue: targetValue})
}
private handleBlur = () => {
const {valid, workingValue} = this.state
const {threshold, onUpdateColorValue} = this.props
if (valid) {
onUpdateColorValue(threshold, workingValue)
} else {
this.setState({workingValue: threshold.value, valid: true})
}
}
private handleKeyUp = (e: KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') {
this.thresholdInputRef.blur()
}
}
private handleInputRef = (ref: HTMLInputElement) => {
this.thresholdInputRef = ref
}
private handleDelete = () => {
const {threshold, onDeleteThreshold} = this.props
onDeleteThreshold(threshold)
}
}
export default Threshold

View File

@ -113,11 +113,11 @@ class ThresholdsList extends Component {
return !sortedColors.some(color => color.value === targetValue)
}
handleSortColors = () => {
const {thresholdsListColors, handleUpdateThresholdsListColors} = this.props
const sortedColors = _.sortBy(thresholdsListColors, color => color.value)
get sortedColors() {
const {thresholdsListColors} = this.props
const sortedColors = _.sortBy(thresholdsListColors, 'value')
handleUpdateThresholdsListColors(sortedColors)
return sortedColors
}
render() {
@ -138,7 +138,7 @@ class ThresholdsList extends Component {
>
<span className="icon plus" /> Add Threshold
</button>
{thresholdsListColors.map(
{this.sortedColors.map(
color =>
color.id === THRESHOLD_TYPE_BASE ? (
<div className="threshold-item" key={uuid.v4()}>
@ -159,7 +159,6 @@ class ThresholdsList extends Component {
onValidateColorValue={this.handleValidateColorValue}
onUpdateColorValue={this.handleUpdateColorValue}
onDeleteThreshold={this.handleDeleteThreshold}
onSortColors={this.handleSortColors}
/>
)
)}

View File

@ -0,0 +1,29 @@
import ThresholdProps from 'src/dashboards/components/Threshold'
import React from 'react'
import {shallow} from 'enzyme'
describe('Threshold', () => {
it('renders without an error', () => {
const props = {
visualizationType: 'gauge',
threshold: {
type: 'color',
hex: '#444444',
id: 'id',
name: 'name',
value: 2,
},
disableMaxColor: true,
onChooseColor: () => {},
onValidateColorValue: () => true,
onUpdateColorValue: () => {},
onDeleteThreshold: () => {},
isMin: false,
isMax: true,
}
const wrapper = shallow(<ThresholdProps {...props} />)
expect(wrapper.exists()).toBe(true)
})
})