diff --git a/ui/.eslintrc b/ui/.eslintrc
index e5a27f5133..360af5a034 100644
--- a/ui/.eslintrc
+++ b/ui/.eslintrc
@@ -110,7 +110,6 @@
'no-new': 2,
'no-octal-escape': 2,
'no-octal': 2,
- 'no-param-reassign': 2,
'no-proto': 2,
'no-redeclare': 2,
'no-script-url': 2,
diff --git a/ui/src/kapacitor/components/RuleGraph.js b/ui/src/kapacitor/components/RuleGraph.js
index 4a27b8f0fd..d4b7e87542 100644
--- a/ui/src/kapacitor/components/RuleGraph.js
+++ b/ui/src/kapacitor/components/RuleGraph.js
@@ -4,7 +4,6 @@ import AutoRefresh from 'shared/components/AutoRefresh';
import LineGraph from 'shared/components/LineGraph';
const RefreshingLineGraph = AutoRefresh(LineGraph);
-const OUT_OF_RANGE = "out of range";
export const RuleGraph = React.createClass({
propTypes: {
source: PropTypes.shape({
@@ -40,32 +39,14 @@ export const RuleGraph = React.createClass({
);
}
- const {value, rangeValue, operator} = rule.values;
- const tenPercent = 0.1;
- let lower, upper;
- let upperRange, lowerRange;
-
- if (value !== "" && operator === OUT_OF_RANGE) {
- lower = Math.min(+rule.values.rangeValue, +rule.values.value);
- lowerRange = lower ? lower + lower * tenPercent : null;
- }
-
- if (rangeValue !== "" && operator === OUT_OF_RANGE) {
- upper = Math.max(+rule.values.rangeValue, +rule.values.value);
- upperRange = upper ? upper + upper * tenPercent : null;
- }
-
- // if either value is null, Dygraph will choose a sensible default
- const range = {y: [lowerRange, upperRange]};
-
return (
);
},
diff --git a/ui/src/shared/components/Dygraph.js b/ui/src/shared/components/Dygraph.js
index dead72b1cf..1496d2abd3 100644
--- a/ui/src/shared/components/Dygraph.js
+++ b/ui/src/shared/components/Dygraph.js
@@ -2,7 +2,13 @@
import React, {PropTypes} from 'react';
import Dygraph from '../../external/dygraph';
-const {arrayOf, object, array, number, bool, shape} = PropTypes;
+const {
+ array,
+ arrayOf,
+ number,
+ bool,
+ shape,
+} = PropTypes;
const LINE_COLORS = [
'#00C9FF',
@@ -28,13 +34,14 @@ export default React.createClass({
y: arrayOf(number),
y2: arrayOf(number),
}),
- timeSeries: array.isRequired, // eslint-disable-line react/forbid-prop-types
- labels: array.isRequired, // eslint-disable-line react/forbid-prop-types
- options: object, // eslint-disable-line react/forbid-prop-types
- containerStyle: object, // eslint-disable-line react/forbid-prop-types
+ timeSeries: array.isRequired,
+ labels: array.isRequired,
+ options: shape({}),
+ containerStyle: shape({}),
isGraphFilled: bool,
overrideLineColors: array,
dygraphSeries: shape({}).isRequired,
+ ruleValues: shape({}),
},
getDefaultProps() {
@@ -54,7 +61,7 @@ export default React.createClass({
componentDidMount() {
const timeSeries = this.getTimeSeries();
// dygraphSeries is a legend label and its corresponding y-axis e.g. {legendLabel1: 'y', legendLabel2: 'y2'};
- const {ranges, dygraphSeries} = this.props;
+ const {ranges, dygraphSeries, ruleValues} = this.props;
const refs = this.refs;
const graphContainerNode = refs.graphContainer;
@@ -81,7 +88,7 @@ export default React.createClass({
series: dygraphSeries,
axes: {
y: {
- valueRange: getRange(timeSeries, ranges.y),
+ valueRange: getRange(timeSeries, ranges.y, ruleValues.value, ruleValues.rangeValue),
},
y2: {
valueRange: getRange(timeSeries, ranges.y2),
@@ -141,14 +148,14 @@ export default React.createClass({
}
const timeSeries = this.getTimeSeries();
- const {labels, ranges, options, dygraphSeries} = this.props;
+ const {labels, ranges, options, dygraphSeries, ruleValues} = this.props;
dygraph.updateOptions({
labels,
file: timeSeries,
axes: {
y: {
- valueRange: getRange(timeSeries, ranges.y),
+ valueRange: getRange(timeSeries, ranges.y, ruleValues.value, ruleValues.rangeValue),
},
y2: {
valueRange: getRange(timeSeries, ranges.y2),
@@ -172,15 +179,28 @@ export default React.createClass({
},
});
-function getRange(timeSeries, override) {
+const TEN_PERCENT = 0.1;
+
+function getRange(timeSeries, override, value = null, rangeValue = null) {
if (override) {
return override;
}
- let max = null;
- let min = null;
+ const addPadding = (val) => {
+ if (val === null || val === '') {
+ return null;
+ }
- timeSeries.forEach((series) => {
+ if (val < 0) {
+ return val - val * TEN_PERCENT;
+ }
+
+ return val + val * TEN_PERCENT;
+ };
+
+ const points = [...timeSeries, [null, addPadding(value)], [null, addPadding(rangeValue)]];
+
+ const range = points.reduce(([min, max], series) => {
for (let i = 1; i < series.length; i++) {
const val = series[i];
@@ -196,13 +216,15 @@ function getRange(timeSeries, override) {
min = Math.min(min, val);
max = Math.max(max, val);
}
+
+ return [min, max];
}
- });
+ }, [null, null]);
// Dygraph will not reliably plot X / Y axis labels if min and max are both 0
- if (min === 0 && max === 0) {
+ if (range[0] === 0 && range[1] === 0) {
return [null, null];
}
- return [min, max];
+ return range;
}
diff --git a/ui/src/shared/components/LineGraph.js b/ui/src/shared/components/LineGraph.js
index bd0af12420..85e9ff9aec 100644
--- a/ui/src/shared/components/LineGraph.js
+++ b/ui/src/shared/components/LineGraph.js
@@ -7,23 +7,34 @@ import _ from 'lodash';
import timeSeriesToDygraph from 'utils/timeSeriesToDygraph';
import lastValues from 'src/shared/parsing/lastValues';
+const {
+ array,
+ arrayOf,
+ number,
+ bool,
+ shape,
+ string,
+ func,
+} = PropTypes;
+
export default React.createClass({
displayName: 'LineGraph',
propTypes: {
- data: PropTypes.arrayOf(PropTypes.shape({}).isRequired).isRequired,
- ranges: PropTypes.shape({
- y: PropTypes.arrayOf(PropTypes.number),
- y2: PropTypes.arrayOf(PropTypes.number),
+ data: arrayOf(shape({}).isRequired).isRequired,
+ ranges: shape({
+ y: arrayOf(number),
+ y2: arrayOf(number),
}),
- title: PropTypes.string,
- isFetchingInitially: PropTypes.bool,
- isRefreshing: PropTypes.bool,
- underlayCallback: PropTypes.func,
- isGraphFilled: PropTypes.bool,
- overrideLineColors: PropTypes.array,
- queries: PropTypes.arrayOf(PropTypes.shape({}).isRequired).isRequired,
- showSingleStat: PropTypes.bool,
- activeQueryIndex: PropTypes.number,
+ title: string,
+ isFetchingInitially: bool,
+ isRefreshing: bool,
+ underlayCallback: func,
+ isGraphFilled: bool,
+ overrideLineColors: array,
+ queries: arrayOf(shape({}).isRequired).isRequired,
+ showSingleStat: bool,
+ activeQueryIndex: number,
+ ruleValues: shape({}),
},
getDefaultProps() {
@@ -50,7 +61,7 @@ export default React.createClass({
},
render() {
- const {data, ranges, isFetchingInitially, isRefreshing, isGraphFilled, overrideLineColors, title, underlayCallback, queries, showSingleStat} = this.props;
+ const {data, ranges, isFetchingInitially, isRefreshing, isGraphFilled, overrideLineColors, title, underlayCallback, queries, showSingleStat, ruleValues} = this.props;
const {labels, timeSeries, dygraphSeries} = this._timeSeries;
// If data for this graph is being fetched for the first time, show a graph-wide spinner.
@@ -99,6 +110,7 @@ export default React.createClass({
options={options}
dygraphSeries={dygraphSeries}
ranges={ranges || this.getRanges()}
+ ruleValues={ruleValues}
/>
{showSingleStat ?
{roundedValue}
: null}