Refactor axes into redux state instead of CEO state

pull/10616/head
Alex P 2018-02-20 23:39:38 -08:00
parent 7770017f4e
commit 9336326199
6 changed files with 193 additions and 223 deletions

View File

@ -43,3 +43,10 @@ export const updateGaugeColors = gaugeColors => ({
gaugeColors,
},
})
export const updateAxes = axes => ({
type: 'UPDATE_AXES',
payload: {
axes,
},
})

View File

@ -1,4 +1,6 @@
import React, {PropTypes} from 'react'
import React, {Component, PropTypes} from 'react'
import {connect} from 'react-redux'
import {bindActionCreators} from 'redux'
import OptIn from 'shared/components/OptIn'
import Input from 'src/dashboards/components/DisplayOptionsInput'
@ -11,105 +13,158 @@ import {GRAPH_TYPES} from 'src/dashboards/graphics/graph'
const {LINEAR, LOG, BASE_2, BASE_10} = DISPLAY_OPTIONS
const getInputMin = scale => (scale === LOG ? '0' : null)
const AxesOptions = ({
axes: {y: {bounds, label, prefix, suffix, base, scale, defaultYLabel}},
onSetBase,
onSetScale,
onSetLabel,
onSetPrefixSuffix,
onSetYAxisBoundMin,
onSetYAxisBoundMax,
cellType,
}) => {
const [min, max] = bounds
import {updateAxes} from 'src/dashboards/actions/cellEditorOverlay'
const {menuOption} = GRAPH_TYPES.find(graph => graph.type === cellType)
class AxesOptions extends Component {
handleSetPrefixSuffix = e => {
const {handleUpdateAxes, axes} = this.props
const {prefix, suffix} = e.target.form
return (
<FancyScrollbar
className="display-options--cell y-axis-controls"
autoHide={false}
>
<div className="display-options--cell-wrapper">
<h5 className="display-options--header">
{menuOption} Controls
</h5>
<form autoComplete="off" style={{margin: '0 -6px'}}>
<div className="form-group col-sm-12">
<label htmlFor="prefix">Title</label>
<OptIn
customPlaceholder={defaultYLabel || 'y-axis title'}
customValue={label}
onSetValue={onSetLabel}
type="text"
const newAxes = {
...axes,
y: {
...axes.y,
prefix: prefix.value,
suffix: suffix.value,
},
}
handleUpdateAxes(newAxes)
}
handleSetYAxisBoundMin = min => {
const {handleUpdateAxes, axes} = this.props
const {y: {bounds: [, max]}} = this.props.axes
const newAxes = {...axes, y: {...axes.y, bounds: [min, max]}}
handleUpdateAxes(newAxes)
}
handleSetYAxisBoundMax = max => {
const {handleUpdateAxes, axes} = this.props
const {y: {bounds: [min]}} = axes
const newAxes = {...axes, y: {...axes.y, bounds: [min, max]}}
handleUpdateAxes(newAxes)
}
handleSetLabel = label => {
const {handleUpdateAxes, axes} = this.props
const newAxes = {...axes, y: {...axes.y, label}}
handleUpdateAxes(newAxes)
}
handleSetScale = scale => () => {
const {handleUpdateAxes, axes} = this.props
const newAxes = {...axes, y: {...axes.y, scale}}
handleUpdateAxes(newAxes)
}
handleSetBase = base => () => {
const {handleUpdateAxes, axes} = this.props
const newAxes = {...axes, y: {...axes.y, base}}
handleUpdateAxes(newAxes)
}
render() {
const {
axes: {y: {bounds, label, prefix, suffix, base, scale, defaultYLabel}},
type,
} = this.props
const [min, max] = bounds
const {menuOption} = GRAPH_TYPES.find(graph => graph.type === type)
return (
<FancyScrollbar
className="display-options--cell y-axis-controls"
autoHide={false}
>
<div className="display-options--cell-wrapper">
<h5 className="display-options--header">
{menuOption} Controls
</h5>
<form autoComplete="off" style={{margin: '0 -6px'}}>
<div className="form-group col-sm-12">
<label htmlFor="prefix">Title</label>
<OptIn
customPlaceholder={defaultYLabel || 'y-axis title'}
customValue={label}
onSetValue={this.handleSetLabel}
type="text"
/>
</div>
<div className="form-group col-sm-6">
<label htmlFor="min">Min</label>
<OptIn
customPlaceholder={'min'}
customValue={min}
onSetValue={this.handleSetYAxisBoundMin}
type="number"
min={getInputMin(scale)}
/>
</div>
<div className="form-group col-sm-6">
<label htmlFor="max">Max</label>
<OptIn
customPlaceholder={'max'}
customValue={max}
onSetValue={this.handleSetYAxisBoundMax}
type="number"
min={getInputMin(scale)}
/>
</div>
<Input
name="prefix"
id="prefix"
value={prefix}
labelText="Y-Value's Prefix"
onChange={this.handleSetPrefixSuffix}
/>
</div>
<div className="form-group col-sm-6">
<label htmlFor="min">Min</label>
<OptIn
customPlaceholder={'min'}
customValue={min}
onSetValue={onSetYAxisBoundMin}
type="number"
min={getInputMin(scale)}
<Input
name="suffix"
id="suffix"
value={suffix}
labelText="Y-Value's Suffix"
onChange={this.handleSetPrefixSuffix}
/>
</div>
<div className="form-group col-sm-6">
<label htmlFor="max">Max</label>
<OptIn
customPlaceholder={'max'}
customValue={max}
onSetValue={onSetYAxisBoundMax}
type="number"
min={getInputMin(scale)}
/>
</div>
<Input
name="prefix"
id="prefix"
value={prefix}
labelText="Y-Value's Prefix"
onChange={onSetPrefixSuffix}
/>
<Input
name="suffix"
id="suffix"
value={suffix}
labelText="Y-Value's Suffix"
onChange={onSetPrefixSuffix}
/>
<Tabber
labelText="Y-Value's Format"
tipID="Y-Values's Format"
tipContent={TOOLTIP_CONTENT.FORMAT}
>
<Tab
text="K/M/B"
isActive={base === BASE_10}
onClickTab={onSetBase(BASE_10)}
/>
<Tab
text="K/M/G"
isActive={base === BASE_2}
onClickTab={onSetBase(BASE_2)}
/>
</Tabber>
<Tabber labelText="Scale">
<Tab
text="Linear"
isActive={scale === LINEAR}
onClickTab={onSetScale(LINEAR)}
/>
<Tab
text="Logarithmic"
isActive={scale === LOG}
onClickTab={onSetScale(LOG)}
/>
</Tabber>
</form>
</div>
</FancyScrollbar>
)
<Tabber
labelText="Y-Value's Format"
tipID="Y-Values's Format"
tipContent={TOOLTIP_CONTENT.FORMAT}
>
<Tab
text="K/M/B"
isActive={base === BASE_10}
onClickTab={this.handleSetBase(BASE_10)}
/>
<Tab
text="K/M/G"
isActive={base === BASE_2}
onClickTab={this.handleSetBase(BASE_2)}
/>
</Tabber>
<Tabber labelText="Scale">
<Tab
text="Linear"
isActive={scale === LINEAR}
onClickTab={this.handleSetScale(LINEAR)}
/>
<Tab
text="Logarithmic"
isActive={scale === LOG}
onClickTab={this.handleSetScale(LOG)}
/>
</Tabber>
</form>
</div>
</FancyScrollbar>
)
}
}
const {arrayOf, func, shape, string} = PropTypes
@ -128,13 +183,7 @@ AxesOptions.defaultProps = {
}
AxesOptions.propTypes = {
cellType: string.isRequired,
onSetPrefixSuffix: func.isRequired,
onSetYAxisBoundMin: func.isRequired,
onSetYAxisBoundMax: func.isRequired,
onSetLabel: func.isRequired,
onSetScale: func.isRequired,
onSetBase: func.isRequired,
type: string.isRequired,
axes: shape({
y: shape({
bounds: arrayOf(string),
@ -142,6 +191,16 @@ AxesOptions.propTypes = {
defaultYLabel: string,
}),
}).isRequired,
handleUpdateAxes: func.isRequired,
}
export default AxesOptions
const mapStateToProps = ({cellEditorOverlay: {cell: {axes, type}}}) => ({
axes,
type,
})
const mapDispatchToProps = dispatch => ({
handleUpdateAxes: bindActionCreators(updateAxes, dispatch),
})
export default connect(mapStateToProps, mapDispatchToProps)(AxesOptions)

View File

@ -28,7 +28,7 @@ class CellEditorOverlay extends Component {
constructor(props) {
super(props)
const {cell: {queries, axes}, sources} = props
const {cell: {queries}, sources} = props
let source = _.get(queries, ['0', 'source'], null)
source = sources.find(s => s.links.self === source) || props.source
@ -45,7 +45,6 @@ class CellEditorOverlay extends Component {
queriesWorkingDraft,
activeQueryIndex: 0,
isDisplayOptionsTabActive: false,
axes,
}
}
@ -67,7 +66,7 @@ class CellEditorOverlay extends Component {
}
handleSetSuffix = e => {
const {axes} = this.state
const {axes} = this.props.cell
this.setState({
axes: {
@ -96,46 +95,6 @@ class CellEditorOverlay extends Component {
this.setState({queriesWorkingDraft: nextQueries})
}
handleSetYAxisBoundMin = min => {
const {axes} = this.state
const {y: {bounds: [, max]}} = axes
this.setState({
axes: {...axes, y: {...axes.y, bounds: [min, max]}},
})
}
handleSetYAxisBoundMax = max => {
const {axes} = this.state
const {y: {bounds: [min]}} = axes
this.setState({
axes: {...axes, y: {...axes.y, bounds: [min, max]}},
})
}
handleSetLabel = label => {
const {axes} = this.state
this.setState({axes: {...axes, y: {...axes.y, label}}})
}
handleSetPrefixSuffix = e => {
const {axes} = this.state
const {prefix, suffix} = e.target.form
this.setState({
axes: {
...axes,
y: {
...axes.y,
prefix: prefix.value,
suffix: suffix.value,
},
},
})
}
handleAddQuery = () => {
const {queriesWorkingDraft} = this.state
const newIndex = queriesWorkingDraft.length
@ -157,7 +116,7 @@ class CellEditorOverlay extends Component {
}
handleSaveCell = () => {
const {queriesWorkingDraft, axes} = this.state
const {queriesWorkingDraft} = this.state
const {cell, singleStatColors, gaugeColors} = this.props
@ -185,7 +144,6 @@ class CellEditorOverlay extends Component {
this.props.onSave({
...cell,
queries,
axes,
colors,
})
}
@ -198,34 +156,6 @@ class CellEditorOverlay extends Component {
this.setState({activeQueryIndex})
}
handleSetBase = base => () => {
const {axes} = this.state
this.setState({
axes: {
...axes,
y: {
...axes.y,
base,
},
},
})
}
handleSetScale = scale => () => {
const {axes} = this.state
this.setState({
axes: {
...axes,
y: {
...axes.y,
scale,
},
},
})
}
handleSetQuerySource = source => {
const queriesWorkingDraft = this.state.queriesWorkingDraft.map(q => ({
..._.cloneDeep(q),
@ -325,7 +255,6 @@ class CellEditorOverlay extends Component {
} = this.props
const {
axes,
activeQueryIndex,
isDisplayOptionsTabActive,
queriesWorkingDraft,
@ -355,7 +284,6 @@ class CellEditorOverlay extends Component {
initialBottomHeight={INITIAL_HEIGHTS.queryMaker}
>
<Visualization
axes={axes}
timeRange={timeRange}
templates={templates}
autoRefresh={autoRefresh}
@ -376,20 +304,8 @@ class CellEditorOverlay extends Component {
/>
{isDisplayOptionsTabActive
? <DisplayOptions
axes={axes}
onChooseColor={this.handleChooseColor}
onValidateColorValue={this.handleValidateColorValue}
onUpdateColorValue={this.handleUpdateColorValue}
onAddGaugeThreshold={this.handleAddGaugeThreshold}
onDeleteThreshold={this.handleDeleteThreshold}
onSetBase={this.handleSetBase}
onSetLabel={this.handleSetLabel}
onSetScale={this.handleSetScale}
queryConfigs={queriesWorkingDraft}
onSetPrefixSuffix={this.handleSetPrefixSuffix}
onSetSuffix={this.handleSetSuffix}
onSetYAxisBoundMin={this.handleSetYAxisBoundMin}
onSetYAxisBoundMax={this.handleSetYAxisBoundMax}
/>
: <QueryMaker
source={this.getSource()}

View File

@ -35,17 +35,7 @@ class DisplayOptions extends Component {
}
renderOptions = () => {
const {
cell,
onSetBase,
onSetScale,
onSetLabel,
onSetPrefixSuffix,
onSetYAxisBoundMin,
onSetYAxisBoundMax,
onSetSuffix,
} = this.props
const {axes, axes: {y: {suffix}}} = this.state
const {cell, cell: {axes: {y: {suffix}}}, onSetSuffix} = this.props
switch (cell.type) {
case 'gauge':
@ -53,18 +43,7 @@ class DisplayOptions extends Component {
case 'single-stat':
return <SingleStatOptions suffix={suffix} onSetSuffix={onSetSuffix} />
default:
return (
<AxesOptions
cellType={cell.type}
axes={axes}
onSetBase={onSetBase}
onSetLabel={onSetLabel}
onSetScale={onSetScale}
onSetPrefixSuffix={onSetPrefixSuffix}
onSetYAxisBoundMin={onSetYAxisBoundMin}
onSetYAxisBoundMax={onSetYAxisBoundMax}
/>
)
return <AxesOptions />
}
}
@ -83,19 +62,20 @@ DisplayOptions.propTypes = {
cell: shape({
type: string.isRequired,
}).isRequired,
onSetPrefixSuffix: func.isRequired,
axes: shape({
y: shape({
bounds: arrayOf(string),
label: string,
defaultYLabel: string,
}),
}).isRequired,
onSetSuffix: func.isRequired,
onSetYAxisBoundMin: func.isRequired,
onSetYAxisBoundMax: func.isRequired,
onSetScale: func.isRequired,
onSetLabel: func.isRequired,
onSetBase: func.isRequired,
axes: shape({}).isRequired,
queryConfigs: arrayOf(shape()).isRequired,
}
const mapStateToProps = ({cellEditorOverlay: {cell}}) => ({
const mapStateToProps = ({cellEditorOverlay: {cell, cell: {axes}}}) => ({
cell,
axes,
})
export default connect(mapStateToProps, null)(DisplayOptions)

View File

@ -90,11 +90,12 @@ DashVisualization.contextTypes = {
}
const mapStateToProps = ({
cellEditorOverlay: {singleStatColors, gaugeColors, cell: {type}},
cellEditorOverlay: {singleStatColors, gaugeColors, cell: {type, axes}},
}) => ({
gaugeColors,
singleStatColors,
type,
axes,
})
export default connect(mapStateToProps, null)(DashVisualization)

View File

@ -68,6 +68,13 @@ export default function cellEditorOverlay(state = initialState, action) {
return {...state, gaugeColors}
}
case 'UPDATE_AXES': {
const {axes} = action.payload
const cell = {...state.cell, axes}
return {...state, cell}
}
}
return state