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, 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 OptIn from 'shared/components/OptIn'
import Input from 'src/dashboards/components/DisplayOptionsInput' 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 {LINEAR, LOG, BASE_2, BASE_10} = DISPLAY_OPTIONS
const getInputMin = scale => (scale === LOG ? '0' : null) const getInputMin = scale => (scale === LOG ? '0' : null)
const AxesOptions = ({ import {updateAxes} from 'src/dashboards/actions/cellEditorOverlay'
axes: {y: {bounds, label, prefix, suffix, base, scale, defaultYLabel}},
onSetBase,
onSetScale,
onSetLabel,
onSetPrefixSuffix,
onSetYAxisBoundMin,
onSetYAxisBoundMax,
cellType,
}) => {
const [min, max] = bounds
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 ( const newAxes = {
<FancyScrollbar ...axes,
className="display-options--cell y-axis-controls" y: {
autoHide={false} ...axes.y,
> prefix: prefix.value,
<div className="display-options--cell-wrapper"> suffix: suffix.value,
<h5 className="display-options--header"> },
{menuOption} Controls }
</h5>
<form autoComplete="off" style={{margin: '0 -6px'}}> handleUpdateAxes(newAxes)
<div className="form-group col-sm-12"> }
<label htmlFor="prefix">Title</label>
<OptIn handleSetYAxisBoundMin = min => {
customPlaceholder={defaultYLabel || 'y-axis title'} const {handleUpdateAxes, axes} = this.props
customValue={label} const {y: {bounds: [, max]}} = this.props.axes
onSetValue={onSetLabel} const newAxes = {...axes, y: {...axes.y, bounds: [min, max]}}
type="text"
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> <Input
<div className="form-group col-sm-6"> name="suffix"
<label htmlFor="min">Min</label> id="suffix"
<OptIn value={suffix}
customPlaceholder={'min'} labelText="Y-Value's Suffix"
customValue={min} onChange={this.handleSetPrefixSuffix}
onSetValue={onSetYAxisBoundMin}
type="number"
min={getInputMin(scale)}
/> />
</div> <Tabber
<div className="form-group col-sm-6"> labelText="Y-Value's Format"
<label htmlFor="max">Max</label> tipID="Y-Values's Format"
<OptIn tipContent={TOOLTIP_CONTENT.FORMAT}
customPlaceholder={'max'} >
customValue={max} <Tab
onSetValue={onSetYAxisBoundMax} text="K/M/B"
type="number" isActive={base === BASE_10}
min={getInputMin(scale)} onClickTab={this.handleSetBase(BASE_10)}
/> />
</div> <Tab
<Input text="K/M/G"
name="prefix" isActive={base === BASE_2}
id="prefix" onClickTab={this.handleSetBase(BASE_2)}
value={prefix} />
labelText="Y-Value's Prefix" </Tabber>
onChange={onSetPrefixSuffix} <Tabber labelText="Scale">
/> <Tab
<Input text="Linear"
name="suffix" isActive={scale === LINEAR}
id="suffix" onClickTab={this.handleSetScale(LINEAR)}
value={suffix} />
labelText="Y-Value's Suffix" <Tab
onChange={onSetPrefixSuffix} text="Logarithmic"
/> isActive={scale === LOG}
<Tabber onClickTab={this.handleSetScale(LOG)}
labelText="Y-Value's Format" />
tipID="Y-Values's Format" </Tabber>
tipContent={TOOLTIP_CONTENT.FORMAT} </form>
> </div>
<Tab </FancyScrollbar>
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>
)
} }
const {arrayOf, func, shape, string} = PropTypes const {arrayOf, func, shape, string} = PropTypes
@ -128,13 +183,7 @@ AxesOptions.defaultProps = {
} }
AxesOptions.propTypes = { AxesOptions.propTypes = {
cellType: string.isRequired, type: string.isRequired,
onSetPrefixSuffix: func.isRequired,
onSetYAxisBoundMin: func.isRequired,
onSetYAxisBoundMax: func.isRequired,
onSetLabel: func.isRequired,
onSetScale: func.isRequired,
onSetBase: func.isRequired,
axes: shape({ axes: shape({
y: shape({ y: shape({
bounds: arrayOf(string), bounds: arrayOf(string),
@ -142,6 +191,16 @@ AxesOptions.propTypes = {
defaultYLabel: string, defaultYLabel: string,
}), }),
}).isRequired, }).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) { constructor(props) {
super(props) super(props)
const {cell: {queries, axes}, sources} = props const {cell: {queries}, sources} = props
let source = _.get(queries, ['0', 'source'], null) let source = _.get(queries, ['0', 'source'], null)
source = sources.find(s => s.links.self === source) || props.source source = sources.find(s => s.links.self === source) || props.source
@ -45,7 +45,6 @@ class CellEditorOverlay extends Component {
queriesWorkingDraft, queriesWorkingDraft,
activeQueryIndex: 0, activeQueryIndex: 0,
isDisplayOptionsTabActive: false, isDisplayOptionsTabActive: false,
axes,
} }
} }
@ -67,7 +66,7 @@ class CellEditorOverlay extends Component {
} }
handleSetSuffix = e => { handleSetSuffix = e => {
const {axes} = this.state const {axes} = this.props.cell
this.setState({ this.setState({
axes: { axes: {
@ -96,46 +95,6 @@ class CellEditorOverlay extends Component {
this.setState({queriesWorkingDraft: nextQueries}) 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 = () => { handleAddQuery = () => {
const {queriesWorkingDraft} = this.state const {queriesWorkingDraft} = this.state
const newIndex = queriesWorkingDraft.length const newIndex = queriesWorkingDraft.length
@ -157,7 +116,7 @@ class CellEditorOverlay extends Component {
} }
handleSaveCell = () => { handleSaveCell = () => {
const {queriesWorkingDraft, axes} = this.state const {queriesWorkingDraft} = this.state
const {cell, singleStatColors, gaugeColors} = this.props const {cell, singleStatColors, gaugeColors} = this.props
@ -185,7 +144,6 @@ class CellEditorOverlay extends Component {
this.props.onSave({ this.props.onSave({
...cell, ...cell,
queries, queries,
axes,
colors, colors,
}) })
} }
@ -198,34 +156,6 @@ class CellEditorOverlay extends Component {
this.setState({activeQueryIndex}) 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 => { handleSetQuerySource = source => {
const queriesWorkingDraft = this.state.queriesWorkingDraft.map(q => ({ const queriesWorkingDraft = this.state.queriesWorkingDraft.map(q => ({
..._.cloneDeep(q), ..._.cloneDeep(q),
@ -325,7 +255,6 @@ class CellEditorOverlay extends Component {
} = this.props } = this.props
const { const {
axes,
activeQueryIndex, activeQueryIndex,
isDisplayOptionsTabActive, isDisplayOptionsTabActive,
queriesWorkingDraft, queriesWorkingDraft,
@ -355,7 +284,6 @@ class CellEditorOverlay extends Component {
initialBottomHeight={INITIAL_HEIGHTS.queryMaker} initialBottomHeight={INITIAL_HEIGHTS.queryMaker}
> >
<Visualization <Visualization
axes={axes}
timeRange={timeRange} timeRange={timeRange}
templates={templates} templates={templates}
autoRefresh={autoRefresh} autoRefresh={autoRefresh}
@ -376,20 +304,8 @@ class CellEditorOverlay extends Component {
/> />
{isDisplayOptionsTabActive {isDisplayOptionsTabActive
? <DisplayOptions ? <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} queryConfigs={queriesWorkingDraft}
onSetPrefixSuffix={this.handleSetPrefixSuffix}
onSetSuffix={this.handleSetSuffix} onSetSuffix={this.handleSetSuffix}
onSetYAxisBoundMin={this.handleSetYAxisBoundMin}
onSetYAxisBoundMax={this.handleSetYAxisBoundMax}
/> />
: <QueryMaker : <QueryMaker
source={this.getSource()} source={this.getSource()}

View File

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

View File

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

View File

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