WIP encorporate new shape for yRanges => axes

pull/1797/head
Andrew Watkins 2017-07-24 15:01:23 -07:00
parent 38b7d17df3
commit 11d0ecac8b
10 changed files with 107 additions and 96 deletions

View File

@ -35,7 +35,7 @@ class CellEditorOverlay extends Component {
this.handleEditRawText = ::this.handleEditRawText
this.handleSetRange = ::this.handleSetRange
const {cell: {name, type, queries, yRanges}} = props
const {cell: {name, type, queries, axes}} = props
const queriesWorkingDraft = _.cloneDeep(
queries.map(({queryConfig}) => ({...queryConfig, id: uuid.v4()}))
@ -47,9 +47,7 @@ class CellEditorOverlay extends Component {
queriesWorkingDraft,
activeQueryIndex: 0,
isDisplayOptionsTabOpen: false,
yRanges: {
y: yRanges && yRanges.y ? yRanges.y : ['', ''],
},
axes,
}
}
@ -82,9 +80,12 @@ class CellEditorOverlay extends Component {
handleSetRange(e) {
const {min, max} = e.target.form
this.setState({
yRanges: {
y: [min.value, max.value],
axes: {
y: {
bounds: [min.value, max.value],
},
},
})
e.preventDefault()
@ -108,7 +109,7 @@ class CellEditorOverlay extends Component {
queriesWorkingDraft,
cellWorkingType: type,
cellWorkingName: name,
yRanges,
axes,
} = this.state
const {cell} = this.props
@ -125,7 +126,13 @@ class CellEditorOverlay extends Component {
}
})
this.props.onSave({...cell, name, type, queries, yRanges})
this.props.onSave({
...cell,
name,
type,
queries,
axes,
})
}
handleSelectGraphType(graphType) {
@ -174,7 +181,7 @@ class CellEditorOverlay extends Component {
cellWorkingType,
isDisplayOptionsTabOpen,
queriesWorkingDraft,
yRanges,
axes,
} = this.state
const queryActions = {
@ -205,7 +212,7 @@ class CellEditorOverlay extends Component {
cellType={cellWorkingType}
cellName={cellWorkingName}
editQueryStatus={editQueryStatus}
yRanges={yRanges}
axes={axes}
views={[]}
/>
<div className="overlay-technology--editor">
@ -221,7 +228,7 @@ class CellEditorOverlay extends Component {
selectedGraphType={cellWorkingType}
onSelectGraphType={this.handleSelectGraphType}
onSetRange={this.handleSetRange}
yRanges={yRanges}
axes={axes}
/>
: <QueryMaker
source={source}

View File

@ -7,26 +7,23 @@ const DisplayOptions = ({
selectedGraphType,
onSelectGraphType,
onSetRange,
yRanges,
axes,
}) =>
<div className="display-options">
<GraphTypeSelector
selectedGraphType={selectedGraphType}
onSelectGraphType={onSelectGraphType}
/>
<Ranger onSetRange={onSetRange} yRanges={yRanges} />
<Ranger onSetRange={onSetRange} axes={axes} />
</div>
const {array, func, shape, string} = PropTypes
const {func, shape, string} = PropTypes
DisplayOptions.propTypes = {
selectedGraphType: string.isRequired,
onSelectGraphType: func.isRequired,
onSetRange: func.isRequired,
yRanges: shape({
y: array,
y2: array,
}).isRequired,
axes: shape({}).isRequired,
}
export default DisplayOptions

View File

@ -1,29 +1,34 @@
import React, {PropTypes} from 'react'
import _ from 'lodash'
const Ranger = ({onSetRange, yRanges}) =>
const Ranger = ({onSetRange, axes}) =>
<div className="display-options--cell">
<h5 className="display-options--header">Y Axis Controls</h5>
<form autoComplete="off">
<div className="display-options--row">
<label htmlFor="min" style={{width: '40px'}}>Min</label>
<label htmlFor="min" style={{width: '40px'}}>
Min
</label>
<input
className="form-control input-sm"
type="text"
type="number"
name="min"
id="min"
value={yRanges.y[0]}
value={_.get(axes, ['y', 'bounds', '0'], '')}
onChange={onSetRange}
placeholder="auto"
/>
</div>
<div className="display-options--row">
<label htmlFor="max" style={{width: '40px'}}>Max</label>
<label htmlFor="max" style={{width: '40px'}}>
Max
</label>
<input
className="form-control input-sm"
type="text"
type="number"
name="max"
id="max"
value={yRanges.y[1]}
value={_.get(axes, ['y', 'bounds', '1'], '')}
onChange={onSetRange}
placeholder="auto"
/>
@ -35,9 +40,10 @@ const {array, func, shape} = PropTypes
Ranger.propTypes = {
onSetRange: func.isRequired,
yRanges: shape({
y: array,
y2: array,
axes: shape({
y: shape({
bounds: array,
}),
}).isRequired,
}

View File

@ -1,23 +1,18 @@
import React, {PropTypes} from 'react'
import Table from './Table'
import AutoRefresh from 'shared/components/AutoRefresh'
import LineGraph from 'shared/components/LineGraph'
import SingleStat from 'shared/components/SingleStat'
const RefreshingLineGraph = AutoRefresh(LineGraph)
const RefreshingSingleStat = AutoRefresh(SingleStat)
import RefreshingGraph from 'shared/components/RefreshingGraph'
const VisView = ({
axes,
view,
queries,
yRanges,
cellType,
templates,
autoRefresh,
heightPixels,
editQueryStatus,
activeQueryIndex,
isInDataExplorer,
}) => {
const activeQuery = queries[activeQueryIndex]
const defaultQuery = queries[0]
@ -41,42 +36,23 @@ const VisView = ({
)
}
if (cellType === 'single-stat') {
return (
<RefreshingSingleStat
queries={queries.length ? [queries[0]] : []}
autoRefresh={autoRefresh}
templates={templates}
/>
)
}
const displayOptions = {
stepPlot: cellType === 'line-stepplot',
stackedGraph: cellType === 'line-stacked',
}
return (
<RefreshingLineGraph
<RefreshingGraph
axes={axes}
type={cellType}
queries={queries}
yRanges={yRanges}
templates={templates}
cellHeight={heightPixels}
autoRefresh={autoRefresh}
activeQueryIndex={activeQueryIndex}
isInDataExplorer={isInDataExplorer}
showSingleStat={cellType === 'line-plus-single-stat'}
isBarGraph={cellType === 'bar'}
displayOptions={displayOptions}
editQueryStatus={editQueryStatus}
/>
)
}
const {arrayOf, bool, func, number, shape, string} = PropTypes
const {arrayOf, func, number, shape, string} = PropTypes
VisView.propTypes = {
view: string.isRequired,
yRanges: shape(),
axes: shape().isRequired,
queries: arrayOf(shape()).isRequired,
cellType: string,
templates: arrayOf(shape()),
@ -84,7 +60,6 @@ VisView.propTypes = {
heightPixels: number,
editQueryStatus: func.isRequired,
activeQueryIndex: number,
isInDataExplorer: bool,
}
export default VisView

View File

@ -6,7 +6,7 @@ import VisView from 'src/data_explorer/components/VisView'
import {GRAPH, TABLE} from 'shared/constants'
import _ from 'lodash'
const {arrayOf, bool, func, number, shape, string} = PropTypes
const {array, arrayOf, bool, func, number, shape, string} = PropTypes
const META_QUERY_REGEX = /^show/i
const Visualization = React.createClass({
@ -26,7 +26,11 @@ const Visualization = React.createClass({
heightPixels: number,
editQueryStatus: func.isRequired,
views: arrayOf(string).isRequired,
yRanges: shape(),
axes: shape({
y: shape({
bounds: array,
}),
}),
},
contextTypes: {
@ -77,9 +81,9 @@ const Visualization = React.createClass({
render() {
const {
axes,
views,
height,
yRanges,
cellType,
cellName,
timeRange,
@ -118,7 +122,7 @@ const Visualization = React.createClass({
>
<VisView
view={view}
yRanges={yRanges}
axes={axes}
queries={queries}
templates={templates}
cellType={cellType}

View File

@ -4,6 +4,7 @@ import {fetchTimeSeriesAsync} from 'shared/actions/timeSeries'
import {removeUnselectedTemplateValues} from 'src/dashboards/constants'
const {
array,
arrayOf,
bool,
element,
@ -43,9 +44,11 @@ const AutoRefresh = ComposedComponent => {
text: string,
}).isRequired
).isRequired,
yRanges: shape({
y: arrayOf(string),
y2: arrayOf(string),
axes: shape({
bounds: shape({
y: array,
y2: array,
}),
}),
editQueryStatus: func,
},
@ -173,7 +176,8 @@ const AutoRefresh = ComposedComponent => {
}
if (
this._noResultsForQuery(timeSeries) || !this.state.lastQuerySuccessful
this._noResultsForQuery(timeSeries) ||
!this.state.lastQuerySuccessful
) {
return this.renderNoResults()
}

View File

@ -54,7 +54,7 @@ export default class Dygraph extends Component {
const timeSeries = this.getTimeSeries()
// dygraphSeries is a legend label and its corresponding y-axis e.g. {legendLabel1: 'y', legendLabel2: 'y2'};
const {
ranges,
axes,
dygraphSeries,
ruleValues,
overrideLineColors,
@ -71,6 +71,9 @@ export default class Dygraph extends Component {
finalLineColors = LINE_COLORS
}
const yAxis = _.get(axes, ['y', 'bounds'], [null, null])
const y2Axis = _.get(axes, ['y2', 'bounds'], undefined)
const defaultOptions = {
plugins: [
new Dygraphs.Plugins.Crosshair({
@ -92,10 +95,10 @@ export default class Dygraph extends Component {
series: dygraphSeries,
axes: {
y: {
valueRange: getRange(timeSeries, ranges && ranges.y, ruleValues),
valueRange: getRange(timeSeries, yAxis, ruleValues),
},
y2: {
valueRange: getRange(timeSeries, ranges && ranges.y2),
valueRange: getRange(timeSeries, y2Axis),
},
},
highlightSeriesOpts: {
@ -235,7 +238,7 @@ export default class Dygraph extends Component {
componentDidUpdate() {
const {
labels,
ranges,
axes,
options,
dygraphSeries,
ruleValues,
@ -249,16 +252,19 @@ export default class Dygraph extends Component {
)
}
const y = _.get(axes, ['y', 'bounds'], [null, null])
const y2 = _.get(axes, ['y2', 'bounds'], undefined)
const timeSeries = this.getTimeSeries()
const updateOptions = {
labels,
file: timeSeries,
axes: {
y: {
valueRange: getRange(timeSeries, ranges && ranges.y, ruleValues),
valueRange: getRange(timeSeries, y, ruleValues),
},
y2: {
valueRange: getRange(timeSeries, ranges && ranges.y2),
valueRange: getRange(timeSeries, y2),
},
},
stepPlot: options.stepPlot,
@ -343,7 +349,7 @@ export default class Dygraph extends Component {
isAscending={isAscending}
onSnip={this.handleSnipLabel}
onSort={this.handleSortLegend}
legendRef={el => this.legendRef = el}
legendRef={el => (this.legendRef = el)}
onInputChange={this.handleLegendInputChange}
onToggleFilter={this.handleToggleFilter}
/>
@ -359,12 +365,16 @@ export default class Dygraph extends Component {
}
}
const {array, arrayOf, func, bool, shape, string} = PropTypes
const {array, bool, func, shape, string} = PropTypes
Dygraph.propTypes = {
ranges: shape({
y: arrayOf(string),
y2: arrayOf(string),
axes: shape({
y: shape({
bounds: array,
}),
y2: shape({
bounds: array,
}),
}),
timeSeries: array.isRequired,
labels: array.isRequired,

View File

@ -15,9 +15,13 @@ export default React.createClass({
displayName: 'LineGraph',
propTypes: {
data: arrayOf(shape({}).isRequired).isRequired,
yRanges: shape({
y: arrayOf(string),
y2: arrayOf(string),
axes: shape({
y: shape({
bounds: array,
}),
y2: shape({
bounds: array,
}),
}),
title: string,
isFetchingInitially: bool,
@ -67,7 +71,8 @@ export default React.createClass({
componentWillUpdate(nextProps) {
const {data, activeQueryIndex} = this.props
if (
data !== nextProps.data || activeQueryIndex !== nextProps.activeQueryIndex
data !== nextProps.data ||
activeQueryIndex !== nextProps.activeQueryIndex
) {
this._timeSeries = timeSeriesToDygraph(
nextProps.data,
@ -80,7 +85,7 @@ export default React.createClass({
render() {
const {
data,
yRanges,
axes,
isFetchingInitially,
isRefreshing,
isGraphFilled,
@ -159,6 +164,7 @@ export default React.createClass({
>
{isRefreshing ? this.renderSpinner() : null}
<Dygraph
axes={axes}
containerStyle={{width: '100%', height: '100%'}}
overrideLineColors={
showSingleStat ? singleStatLineColors : overrideLineColors
@ -169,7 +175,6 @@ export default React.createClass({
labels={labels}
options={showSingleStat ? singleStatOptions : options}
dygraphSeries={dygraphSeries}
ranges={yRanges}
ruleValues={ruleValues}
synchronizer={synchronizer}
timeRange={timeRange}
@ -182,7 +187,9 @@ export default React.createClass({
'single-stat--small': cellHeight === SMALL_CELL_HEIGHT,
})}
>
<span className="single-stat--shadow">{roundedValue}</span>
<span className="single-stat--shadow">
{roundedValue}
</span>
</span>
</div>
: null}

View File

@ -15,7 +15,7 @@ const RefreshingGraph = ({
type,
queries,
cellHeight,
yRanges,
axes,
}) => {
if (type === 'single-stat') {
return (
@ -43,7 +43,7 @@ const RefreshingGraph = ({
isBarGraph={type === 'bar'}
displayOptions={displayOptions}
synchronizer={synchronizer}
yRanges={yRanges}
axes={axes}
/>
)
}
@ -59,11 +59,8 @@ RefreshingGraph.propTypes = {
synchronizer: func,
type: string.isRequired,
queries: arrayOf(shape()).isRequired,
cellHeight: number.isRequired,
yRanges: shape({
y: arrayOf(string),
y2: arrayOf(string),
}),
cellHeight: number,
axes: shape(),
}
export default RefreshingGraph

View File

@ -1,8 +1,12 @@
const PADDING_FACTOR = 0.1
const considerZero = (userNumber, number) => {
if (typeof userNumber === 'number') {
return userNumber
if (userNumber === '') {
return null
}
if (userNumber) {
return +userNumber
}
return number