WIP encorporate new shape for yRanges => axes
parent
38b7d17df3
commit
11d0ecac8b
|
@ -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}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue