diff --git a/CHANGELOG.md b/CHANGELOG.md index 51906e0413..d4b80c90b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### Bug Fixes 1. [#2095](https://github.com/influxdata/chronograf/pull/2095): Improve the copy in the retention policy edit page 1. [#2093](https://github.com/influxdata/chronograf/pull/2093): Fix when exporting `SHOW DATABASES` CSV has bad data +1. [#2098](https://github.com/influxdata/chronograf/pull/2098): Fix not-equal-to highlighting in Kapacitor Rule Builder ### Features 1. [#2083](https://github.com/influxdata/chronograf/pull/2083): Every dashboard can now have its own time range diff --git a/ui/src/kapacitor/components/RuleGraph.js b/ui/src/kapacitor/components/RuleGraph.js index e0a2aa56e3..b80ea80aa4 100644 --- a/ui/src/kapacitor/components/RuleGraph.js +++ b/ui/src/kapacitor/components/RuleGraph.js @@ -3,132 +3,66 @@ import buildInfluxQLQuery from 'utils/influxql' import AutoRefresh from 'shared/components/AutoRefresh' import LineGraph from 'shared/components/LineGraph' import TimeRangeDropdown from 'shared/components/TimeRangeDropdown' +import underlayCallback from 'src/kapacitor/helpers/ruleGraphUnderlay' const RefreshingLineGraph = AutoRefresh(LineGraph) const {shape, string, func} = PropTypes +const RuleGraph = ({ + query, + source, + timeRange: {lower}, + timeRange, + rule, + onChooseTimeRange, +}) => { + const autoRefreshMs = 30000 + const queryText = buildInfluxQLQuery({lower}, query) + const queries = [{host: source.links.proxy, text: queryText}] + const kapacitorLineColors = ['#4ED8A0'] -export const RuleGraph = React.createClass({ - propTypes: { - source: shape({ - links: shape({ - proxy: string.isRequired, - }).isRequired, - }).isRequired, - query: shape({}).isRequired, - rule: shape({}).isRequired, - timeRange: shape({}).isRequired, - onChooseTimeRange: func.isRequired, - }, - - render() { - const { - query, - source, - timeRange: {lower}, - timeRange, - rule, - onChooseTimeRange, - } = this.props - const autoRefreshMs = 30000 - const queryText = buildInfluxQLQuery({lower}, query) - const queries = [{host: source.links.proxy, text: queryText}] - const kapacitorLineColors = ['#4ED8A0'] - - if (!queryText) { - return ( -
-

- Select a Time-Series to preview on a graph -

-
- ) - } - + if (!queryText) { return ( -
-
-

Preview Data from

- -
- +
+

+ Select a Time-Series to preview on a graph +

) - }, + } - createUnderlayCallback() { - const {rule} = this.props - return (canvas, area, dygraph) => { - if (rule.trigger !== 'threshold' || rule.values.value === '') { - return - } + return ( +
+
+

Preview Data from

+ +
+ +
+ ) +} - const theOnePercent = 0.01 - let highlightStart = 0 - let highlightEnd = 0 - - switch (rule.values.operator) { - case 'equal to or greater': - case 'greater than': { - highlightStart = rule.values.value - highlightEnd = dygraph.yAxisRange()[1] - break - } - - case 'equal to or less than': - case 'less than': { - highlightStart = dygraph.yAxisRange()[0] - highlightEnd = rule.values.value - break - } - - case 'not equal to': - case 'equal to': { - const width = - theOnePercent * (dygraph.yAxisRange()[1] - dygraph.yAxisRange()[0]) - highlightStart = +rule.values.value - width - highlightEnd = +rule.values.value + width - break - } - - case 'outside range': { - const {rangeValue, value} = rule.values - highlightStart = Math.min(+value, +rangeValue) - highlightEnd = Math.max(+value, +rangeValue) - - canvas.fillStyle = 'rgba(78, 216, 160, 0.3)' - canvas.fillRect(area.x, area.y, area.w, area.h) - break - } - case 'inside range': { - const {rangeValue, value} = rule.values - highlightStart = Math.min(+value, +rangeValue) - highlightEnd = Math.max(+value, +rangeValue) - break - } - } - - const bottom = dygraph.toDomYCoord(highlightStart) - const top = dygraph.toDomYCoord(highlightEnd) - - canvas.fillStyle = - rule.values.operator === 'outside range' - ? 'rgba(41, 41, 51, 1)' - : 'rgba(78, 216, 160, 0.3)' - canvas.fillRect(area.x, top, area.w, bottom - top) - } - }, -}) +RuleGraph.propTypes = { + source: shape({ + links: shape({ + proxy: string.isRequired, + }).isRequired, + }).isRequired, + query: shape({}).isRequired, + rule: shape({}).isRequired, + timeRange: shape({}).isRequired, + onChooseTimeRange: func.isRequired, +} export default RuleGraph diff --git a/ui/src/kapacitor/components/Threshold.js b/ui/src/kapacitor/components/Threshold.js index 5136c3ea6f..462ee2d804 100644 --- a/ui/src/kapacitor/components/Threshold.js +++ b/ui/src/kapacitor/components/Threshold.js @@ -4,6 +4,7 @@ import Dropdown from 'shared/components/Dropdown' const mapToItems = (arr, type) => arr.map(text => ({text, type})) const operators = mapToItems(OPERATORS, 'operator') +const noopSubmit = e => e.preventDefault() const Threshold = ({ rule: {values: {operator, value, rangeValue}}, @@ -24,7 +25,7 @@ const Threshold = ({ selected={operator} onChoose={onDropdownChange} /> -
+ { + const backgroundColor = BACKGROUND + const highlightColor = HIGHLIGHT + + if (operator === OUTSIDE_RANGE) { + return backgroundColor + } + + if (operator === NOT_EQUAL_TO) { + return backgroundColor + } + + return highlightColor +} + +const underlayCallback = rule => (canvas, area, dygraph) => { + const {values} = rule + const {operator, value} = values + + if (rule.trigger !== 'threshold' || value === '' || !isFinite(value)) { + return + } + + const theOnePercent = 0.01 + let highlightStart = 0 + let highlightEnd = 0 + + switch (operator) { + case `${EQUAL_TO_OR_GREATER_THAN}`: + case `${GREATER_THAN}`: { + highlightStart = value + highlightEnd = dygraph.yAxisRange()[1] + break + } + + case `${EQUAL_TO_OR_LESS_THAN}`: + case `${LESS_THAN}`: { + highlightStart = dygraph.yAxisRange()[0] + highlightEnd = value + break + } + + case `${EQUAL_TO}`: { + const width = + theOnePercent * (dygraph.yAxisRange()[1] - dygraph.yAxisRange()[0]) + highlightStart = +value - width + highlightEnd = +value + width + break + } + + case `${NOT_EQUAL_TO}`: { + const width = + theOnePercent * (dygraph.yAxisRange()[1] - dygraph.yAxisRange()[0]) + highlightStart = +value - width + highlightEnd = +value + width + + canvas.fillStyle = HIGHLIGHT + canvas.fillRect(area.x, area.y, area.w, area.h) + break + } + + case `${OUTSIDE_RANGE}`: { + highlightStart = Math.min(+value, +values.rangeValue) + highlightEnd = Math.max(+value, +values.rangeValue) + + canvas.fillStyle = HIGHLIGHT + canvas.fillRect(area.x, area.y, area.w, area.h) + break + } + + case `${INSIDE_RANGE}`: { + highlightStart = Math.min(+value, +values.rangeValue) + highlightEnd = Math.max(+value, +values.rangeValue) + break + } + } + + const bottom = dygraph.toDomYCoord(highlightStart) + const top = dygraph.toDomYCoord(highlightEnd) + + const fillColor = getFillColor(operator) + canvas.fillStyle = fillColor + canvas.fillRect(area.x, top, area.w, bottom - top) +} + +export default underlayCallback diff --git a/ui/src/shared/parsing/getRangeForDygraph.js b/ui/src/shared/parsing/getRangeForDygraph.js index a95384f114..f3664899b5 100644 --- a/ui/src/shared/parsing/getRangeForDygraph.js +++ b/ui/src/shared/parsing/getRangeForDygraph.js @@ -3,6 +3,8 @@ import BigNumber from 'bignumber.js' const ADD_FACTOR = 1.1 const SUB_FACTOR = 0.9 +const checkNumeric = num => (isFinite(num) ? num : null) + const considerEmpty = (userNumber, number) => { if (userNumber) { return +userNumber @@ -17,13 +19,15 @@ const getRange = ( ruleValues = {value: null, rangeValue: null, operator: ''} ) => { const {value, rangeValue, operator} = ruleValues - const [userMin, userMax] = userSelectedRange + const [uMin, uMax] = userSelectedRange + const userMin = checkNumeric(uMin) + const userMax = checkNumeric(uMax) const addPad = bigNum => bigNum.times(ADD_FACTOR).toNumber() const subPad = bigNum => bigNum.times(SUB_FACTOR).toNumber() const pad = v => { - if (v === null || v === '' || v === undefined) { + if (v === null || v === '' || !isFinite(v)) { return null }