From 1b5f8ebd6d94527114be11b866495d6e61a313b6 Mon Sep 17 00:00:00 2001 From: Alex P Date: Wed, 28 Feb 2018 14:22:45 -0800 Subject: [PATCH 01/39] WIP color series based on quantity --- ui/src/shared/components/Dygraph.js | 22 ++++---- ui/src/shared/constants/graphColorPalettes.js | 53 +++++++++++++++++++ 2 files changed, 65 insertions(+), 10 deletions(-) create mode 100644 ui/src/shared/constants/graphColorPalettes.js diff --git a/ui/src/shared/components/Dygraph.js b/ui/src/shared/components/Dygraph.js index f30d888267..b7bf17418f 100644 --- a/ui/src/shared/components/Dygraph.js +++ b/ui/src/shared/components/Dygraph.js @@ -21,9 +21,9 @@ import { LABEL_WIDTH, CHAR_PIXELS, barPlotter, - hasherino, highlightSeriesOpts, } from 'src/shared/graphs/helpers' +import {getIdealColors} from 'src/shared/constants/graphColorPalettes' const {LINEAR, LOG, BASE_10, BASE_2} = DISPLAY_OPTIONS class Dygraph extends Component { @@ -51,7 +51,7 @@ class Dygraph extends Component { fillGraph, logscale: y.scale === LOG, colors: this.getLineColors(), - series: this.hashColorDygraphSeries(), + series: this.colorDygraphSeries(), unhighlightCallback: this.unhighlightCallback, plugins: [new Dygraphs.Plugins.Crosshair({direction: 'vertical'})], axes: { @@ -153,7 +153,7 @@ class Dygraph extends Component { }, }, colors: this.getLineColors(), - series: this.hashColorDygraphSeries(), + series: this.colorDygraphSeries(), plotter: isBarGraph ? barPlotter : null, drawCallback: this.annotationsRef.heartbeat, } @@ -193,19 +193,21 @@ class Dygraph extends Component { onZoom(this.formatTimeRange(lower), this.formatTimeRange(upper)) } - hashColorDygraphSeries = () => { + colorDygraphSeries = () => { const {dygraphSeries} = this.props - const colors = this.getLineColors() - const hashColorDygraphSeries = {} + const numSeries = Object.keys(dygraphSeries).length + const colors = getIdealColors(numSeries) + + const coloredDygraphSeries = {} for (const seriesName in dygraphSeries) { const series = dygraphSeries[seriesName] - const hashIndex = hasherino(seriesName, colors.length) - const color = colors[hashIndex] - hashColorDygraphSeries[seriesName] = {...series, color} + const color = colors[Object.keys(dygraphSeries).indexOf(seriesName)] + + coloredDygraphSeries[seriesName] = {...series, color} } - return hashColorDygraphSeries + return coloredDygraphSeries } sync = () => { diff --git a/ui/src/shared/constants/graphColorPalettes.js b/ui/src/shared/constants/graphColorPalettes.js new file mode 100644 index 0000000000..c5a3e27656 --- /dev/null +++ b/ui/src/shared/constants/graphColorPalettes.js @@ -0,0 +1,53 @@ +// Tier 5 Colors +const series1 = ['#22ADF6'] // Blue +const series2 = [...series1, '#4ED8A0'] // Green +const series3 = [...series2, '#7A65F2'] // Purple +const series4 = [...series3, '#F95F53'] // Red +const series5 = [...series4, '#FFB94A'] // Yellow +// Tier 4 Colors +const series6 = [...series5, '#00C9FF'] // Blu +const series7 = [...series6, '#7CE490'] // Green +const series8 = [...series7, '#9394FF'] // Purple +const series9 = [...series8, '#FF8564'] // Red +const series10 = [...series9, '#FFD255'] // Yellow +// Tier 6 Colors +const series11 = [...series10, '#4591ED'] // Blu +const series12 = [...series11, '#32B08C'] // Green +const series13 = [...series12, '#513CC6'] // Purple +const series14 = [...series13, '#DC4E58'] // Red +const series15 = [...series14, '#F48D38'] // Yellow +// Tier 3 Colors +const series16 = [...series15, '#6BDFFF'] // Blu +const series17 = [...series16, '#A5F3B4'] // Green +const series18 = [...series17, '#B1B6FF'] // Purple +const series19 = [...series18, '#FFB6A0'] // Red +const series20 = [...series19, '#FFE480'] // Yellow + +// All Colors +const graphColors = [ + series1, + series2, + series3, + series4, + series5, + series6, + series7, + series8, + series9, + series10, + series11, + series12, + series13, + series14, + series15, + series16, + series17, + series18, + series19, + series20, +] + +// Color Finder +export const getIdealColors = numSeries => { + return graphColors[numSeries - 1] +} From c74adab81673cff02368f46e3e4ce004d36676fc Mon Sep 17 00:00:00 2001 From: Alex P Date: Mon, 26 Mar 2018 13:14:42 -0700 Subject: [PATCH 02/39] Prototype HSL shifting color spectrum --- ui/src/shared/constants/colorOperations.js | 45 ++++++++++++++++++- ui/src/shared/constants/graphColorPalettes.js | 41 +++++++++++++++-- 2 files changed, 82 insertions(+), 4 deletions(-) diff --git a/ui/src/shared/constants/colorOperations.js b/ui/src/shared/constants/colorOperations.js index e96291e528..6747a22001 100644 --- a/ui/src/shared/constants/colorOperations.js +++ b/ui/src/shared/constants/colorOperations.js @@ -121,7 +121,7 @@ export const generateThresholdsListHexs = ( return {bgColor, textColor} } -// Handy tool for converting hexcodes to HSV values +// Handy tool for converting Hexcodes to HSL values export const HexcodeToHSL = hex => { const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex) @@ -160,3 +160,46 @@ export const HexcodeToHSL = hex => { return {hue, saturation, lightness} } + +// Handy tool for converting HSL values to Hexcode +export const HSLToHexcode = (hue, saturation, lightness) => { + hue /= 360 + saturation /= 100 + lightness /= 100 + let red, green, blue + if (saturation === 0) { + red = green = blue = lightness // achromatic + } else { + const hue2rgb = (p, q, t) => { + if (t < 0) { + t += 1 + } + if (t > 1) { + t -= 1 + } + if (t < 1 / 6) { + return p + (q - p) * 6 * t + } + if (t < 1 / 2) { + return q + } + if (t < 2 / 3) { + return p + (q - p) * (2 / 3 - t) * 6 + } + return p + } + const q = + lightness < 0.5 + ? lightness * (1 + saturation) + : lightness + saturation - lightness * saturation + const p = 2 * lightness - q + red = hue2rgb(p, q, hue + 1 / 3) + green = hue2rgb(p, q, hue) + blue = hue2rgb(p, q, hue - 1 / 3) + } + const toHex = x => { + const hex = Math.round(x * 255).toString(16) + return hex.length === 1 ? `0${hex}` : hex + } + return `#${toHex(red)}${toHex(green)}${toHex(blue)}` +} diff --git a/ui/src/shared/constants/graphColorPalettes.js b/ui/src/shared/constants/graphColorPalettes.js index 2f08559b56..c1198bd73e 100644 --- a/ui/src/shared/constants/graphColorPalettes.js +++ b/ui/src/shared/constants/graphColorPalettes.js @@ -1,4 +1,4 @@ -import {HexcodeToHSL} from 'src/shared/constants/colorOperations' +import {HexcodeToHSL, HSLToHexcode} from 'src/shared/constants/colorOperations' import _ from 'lodash' // Tier 5 Colors @@ -50,18 +50,53 @@ const graphColors = [ series20, ] +export const generateLargePalette = numSeries => { + const start = {hue: 190, saturation: 90, lightness: 50} + const end = {hue: 360, saturation: 80, lightness: 98} + const colorsHSL = [] + + for (let i = 0; i < numSeries; i++) { + const hRange = end.hue - start.hue + const hStep = hRange / (numSeries - 1) + const h = hStep * i + + const sRange = end.saturation - start.saturation + const sStep = sRange / (numSeries - 1) + const s = sStep * i + + const lRange = end.lightness - start.lightness + const lStep = lRange / (numSeries - 1) + const l = lStep * i + + colorsHSL[i] = { + hue: Math.floor(start.hue + h), + saturation: Math.floor(start.saturation + s), + lightness: Math.floor(start.lightness + l), + } + } + + const colorsHex = colorsHSL.map(color => + HSLToHexcode(color.hue, color.saturation, color.lightness) + ) + + return colorsHex +} + // Sort by hue const sortColorsByHue = colors => { return _.sortBy(colors, color => { const {hue} = HexcodeToHSL(color) - console.log(color, hue) + return hue }) } // Color Finder export const getIdealColors = numSeries => { + if (numSeries > 18) { + return generateLargePalette(numSeries) + } const colors = graphColors[numSeries - 1] - console.log(sortColorsByHue(colors)) + return sortColorsByHue(colors) } From 853a3c0d6e7335ec9214823fd47a0f05c3faf93b Mon Sep 17 00:00:00 2001 From: Alex P Date: Mon, 26 Mar 2018 16:23:46 -0700 Subject: [PATCH 03/39] Add Chroma.js Package --- ui/package.json | 3 ++- ui/yarn.lock | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ui/package.json b/ui/package.json index 6b95613217..9b6d82d3f0 100644 --- a/ui/package.json +++ b/ui/package.json @@ -116,6 +116,7 @@ "axios": "^0.13.1", "bignumber.js": "^4.0.2", "calculate-size": "^1.1.1", + "chroma-js": "^1.3.6", "classnames": "^2.2.3", "dygraphs": "2.1.0", "eslint-plugin-babel": "^4.1.2", @@ -147,4 +148,4 @@ "rome": "^2.1.22", "uuid": "^3.2.1" } -} \ No newline at end of file +} diff --git a/ui/yarn.lock b/ui/yarn.lock index 0c053dee44..b8c44de637 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -1686,6 +1686,10 @@ chownr@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" +chroma-js@^1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/chroma-js/-/chroma-js-1.3.6.tgz#22dd7220ef6b55dcfcb8ef92982baaf55dced45d" + ci-info@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.2.tgz#03561259db48d0474c8bdc90f5b47b068b6bbfb4" From a28a30d45cfc87825aa9bfb6f36b4b7a47ffb741 Mon Sep 17 00:00:00 2001 From: Alex P Date: Mon, 26 Mar 2018 16:24:15 -0700 Subject: [PATCH 04/39] Refactor color operations to use Chroma --- ui/src/shared/constants/colorOperations.js | 27 +++++----------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/ui/src/shared/constants/colorOperations.js b/ui/src/shared/constants/colorOperations.js index 2a4dedf3a4..0219ae1d29 100644 --- a/ui/src/shared/constants/colorOperations.js +++ b/ui/src/shared/constants/colorOperations.js @@ -1,36 +1,21 @@ import _ from 'lodash' +import chroma from 'chroma-js' + import { THRESHOLD_COLORS, THRESHOLD_TYPE_BASE, THRESHOLD_TYPE_TEXT, } from 'shared/constants/thresholds' -const hexToRgb = hex => { - const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex) - return result - ? { - r: parseInt(result[1], 16), - g: parseInt(result[2], 16), - b: parseInt(result[3], 16), - } - : null -} - -const averageRgbValues = valuesObject => { - const {r, g, b} = valuesObject - return (r + g + b) / 3 -} - -const trueNeutralGrey = 128 +const luminanceThreshold = 0.5 const getLegibleTextColor = bgColorHex => { - const averageBackground = averageRgbValues(hexToRgb(bgColorHex)) - const isBackgroundLight = averageBackground > trueNeutralGrey - const darkText = '#292933' const lightText = '#ffffff' - return isBackgroundLight ? darkText : lightText + return chroma(bgColorHex).luminance() < luminanceThreshold + ? darkText + : lightText } const findNearestCrossedThreshold = (colors, lastValue) => { From 635b0b91cfd79a2799208d01633bb3f40176936d Mon Sep 17 00:00:00 2001 From: Alex P Date: Mon, 26 Mar 2018 16:55:46 -0700 Subject: [PATCH 05/39] WIP Introduce a handful of color presets --- ui/src/shared/components/Dygraph.js | 4 +- ui/src/shared/constants/graphColorPalettes.js | 282 ++++++++++++------ 2 files changed, 193 insertions(+), 93 deletions(-) diff --git a/ui/src/shared/components/Dygraph.js b/ui/src/shared/components/Dygraph.js index a835bc9ab1..7fe6e70399 100644 --- a/ui/src/shared/components/Dygraph.js +++ b/ui/src/shared/components/Dygraph.js @@ -26,7 +26,7 @@ import { highlightSeriesOpts, } from 'src/shared/graphs/helpers' -import {getIdealColors} from 'src/shared/constants/graphColorPalettes' +import {generateColorScale} from 'src/shared/constants/graphColorPalettes' const {LINEAR, LOG, BASE_10, BASE_2} = AXES_SCALE_OPTIONS class Dygraph extends Component { @@ -193,7 +193,7 @@ class Dygraph extends Component { colorDygraphSeries = () => { const {dygraphSeries} = this.props const numSeries = Object.keys(dygraphSeries).length - const colors = getIdealColors(numSeries) + const colors = generateColorScale(numSeries) const coloredDygraphSeries = {} diff --git a/ui/src/shared/constants/graphColorPalettes.js b/ui/src/shared/constants/graphColorPalettes.js index c1198bd73e..ba8773c829 100644 --- a/ui/src/shared/constants/graphColorPalettes.js +++ b/ui/src/shared/constants/graphColorPalettes.js @@ -1,102 +1,202 @@ -import {HexcodeToHSL, HSLToHexcode} from 'src/shared/constants/colorOperations' import _ from 'lodash' +import chroma from 'chroma-js' -// Tier 5 Colors -const series1 = ['#22ADF6'] // Blue -const series2 = [...series1, '#4ED8A0'] // Green -const series3 = [...series2, '#7A65F2'] // Purple -const series4 = [...series3, '#F95F53'] // Red -const series5 = [...series4, '#FFB94A'] // Yellow -// Tier 4 Colors -const series6 = [...series5, '#00C9FF'] // Blu -const series7 = [...series6, '#7CE490'] // Green -const series8 = [...series7, '#9394FF'] // Purple -const series9 = [...series8, '#FF8564'] // Red -const series10 = [...series9, '#FFD255'] // Yellow -// Tier 6 Colors -const series11 = [...series10, '#4591ED'] // Blu -const series12 = [...series11, '#32B08C'] // Green -const series13 = [...series12, '#513CC6'] // Purple -const series14 = [...series13, '#DB4D4D'] // Red -const series15 = [...series14, '#F48D38'] // Yellow -// Tier 3 Colors -const series16 = [...series15, '#6BDFFF'] // Blu -const series17 = [...series16, '#A5F3B4'] // Green -const series18 = [...series17, '#B1B6FF'] // Purple -const series19 = [...series18, '#FFB6A0'] // Red -const series20 = [...series19, '#FFE480'] // Yellow - -// All Colors -const graphColors = [ - series1, - series2, - series3, - series4, - series5, - series6, - series7, - series8, - series9, - series10, - series11, - series12, - series13, - series14, - series15, - series16, - series17, - series18, - series19, - series20, +// Color Palettes +export const LINE_COLORS_A = [ + { + type: 'scale', + hex: '#31C0F6', + id: '0', + name: 'Nineteen Eighty Four', + value: 0, + }, + { + type: 'scale', + hex: '#A500A5', + id: '0', + name: 'Nineteen Eighty Four', + value: 0, + }, + { + type: 'scale', + hex: '#FF7E27', + id: '0', + name: 'Nineteen Eighty Four', + value: 0, + }, ] -export const generateLargePalette = numSeries => { - const start = {hue: 190, saturation: 90, lightness: 50} - const end = {hue: 360, saturation: 80, lightness: 98} - const colorsHSL = [] +export const LINE_COLORS_B = [ + { + type: 'scale', + hex: '#74D495', + id: '1', + name: 'Atlantis', + value: 0, + }, + { + type: 'scale', + hex: '#3F3FBA', + id: '1', + name: 'Atlantis', + value: 0, + }, + { + type: 'scale', + hex: '#EA5994', + id: '1', + name: 'Atlantis', + value: 0, + }, +] - for (let i = 0; i < numSeries; i++) { - const hRange = end.hue - start.hue - const hStep = hRange / (numSeries - 1) - const h = hStep * i +export const LINE_COLORS_C = [ + { + type: 'scale', + hex: '#8F8AF4', + id: '1', + name: 'Glarbh', + value: 0, + }, + { + type: 'scale', + hex: '#A51414', + id: '1', + name: 'Glarbh', + value: 0, + }, + { + type: 'scale', + hex: '#F4CF31', + id: '1', + name: 'Glarbh', + value: 0, + }, +] - const sRange = end.saturation - start.saturation - const sStep = sRange / (numSeries - 1) - const s = sStep * i +export const LINE_COLORS_D = [ + { + type: 'scale', + hex: '#FD7A5D', + id: '1', + name: 'Spoot', + value: 0, + }, + { + type: 'scale', + hex: '#5F1CF2', + id: '1', + name: 'Spoot', + value: 0, + }, + { + type: 'scale', + hex: '#4CE09A', + id: '1', + name: 'Spoot', + value: 0, + }, +] - const lRange = end.lightness - start.lightness - const lStep = lRange / (numSeries - 1) - const l = lStep * i +export const LINE_COLORS_E = [ + { + type: 'scale', + hex: '#FDC44F', + id: '1', + name: 'Swump', + value: 0, + }, + { + type: 'scale', + hex: '#007C76', + id: '1', + name: 'Swump', + value: 0, + }, + { + type: 'scale', + hex: '#8983FF', + id: '1', + name: 'Swump', + value: 0, + }, +] - colorsHSL[i] = { - hue: Math.floor(start.hue + h), - saturation: Math.floor(start.saturation + s), - lightness: Math.floor(start.lightness + l), - } - } +export const LINE_COLORS_F = [ + { + type: 'scale', + hex: '#DA6FF1', + id: '1', + name: 'Splort', + value: 0, + }, + { + type: 'scale', + hex: '#00717A', + id: '1', + name: 'Splort', + value: 0, + }, + { + type: 'scale', + hex: '#05B7E0', + id: '1', + name: 'Splort', + value: 0, + }, +] - const colorsHex = colorsHSL.map(color => - HSLToHexcode(color.hue, color.saturation, color.lightness) - ) +export const LINE_COLORS_G = [ + { + type: 'scale', + hex: '#F6F6F8', + id: '1', + name: 'OldTimey', + value: 0, + }, + { + type: 'scale', + hex: '#A4A8B6', + id: '1', + name: 'OldTimey', + value: 0, + }, + { + type: 'scale', + hex: '#545667', + id: '1', + name: 'OldTimey', + value: 0, + }, +] - return colorsHex -} - -// Sort by hue -const sortColorsByHue = colors => { - return _.sortBy(colors, color => { - const {hue} = HexcodeToHSL(color) - - return hue - }) -} - -// Color Finder -export const getIdealColors = numSeries => { - if (numSeries > 18) { - return generateLargePalette(numSeries) - } - const colors = graphColors[numSeries - 1] - - return sortColorsByHue(colors) +export const LINE_COLOR_SCALES = [ + LINE_COLORS_A, + LINE_COLORS_B, + LINE_COLORS_C, + LINE_COLORS_D, + LINE_COLORS_E, + LINE_COLORS_F, + LINE_COLORS_G, +].map(colorScale => { + const name = colorScale[0].name + const colors = colorScale.map(color => color.hex) + const id = colorScale[0].id + + return {name, colors, id} +}) + +const paletteA = ['#31C0F6', '#A500A5', '#FF7E27'] +const paletteB = ['#74D495', '#3F3FBA', '#EA5994'] +const paletteC = ['#8F8AF4', '#A51414', '#F4CF31'] +const paletteD = ['#FD7A5D', '#5F1CF2', '#4CE09A'] +const paletteE = ['#FDC44F', '#007C76', '#8983FF'] +const paletteF = ['#DA6FF1', '#00717A', '#05B7E0'] +const paletteG = ['#F6F6F8', '#A4A8B6', '#545667'] + +export const generateColorScale = numSeries => { + return chroma + .scale(paletteB) + .mode('lch') + .colors(numSeries) } From e0acfb91195573725ec3a200098b617f290b97ca Mon Sep 17 00:00:00 2001 From: Alex P Date: Mon, 26 Mar 2018 19:09:09 -0700 Subject: [PATCH 06/39] Add "Scale" type to accepted cell color types --- server/cells.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/cells.go b/server/cells.go index 181095478d..b8fabf2a45 100644 --- a/server/cells.go +++ b/server/cells.go @@ -113,7 +113,7 @@ func HasCorrectAxes(c *chronograf.DashboardCell) error { // HasCorrectColors verifies that the format of each color is correct func HasCorrectColors(c *chronograf.DashboardCell) error { for _, color := range c.CellColors { - if !oneOf(color.Type, "max", "min", "threshold", "text", "background") { + if !oneOf(color.Type, "max", "min", "threshold", "text", "background", "scale") { return chronograf.ErrInvalidColorType } if len(color.Hex) != 7 { From c1f3de244c5694db9e6693093646e328833a8cda Mon Sep 17 00:00:00 2001 From: Alex P Date: Mon, 26 Mar 2018 19:09:29 -0700 Subject: [PATCH 07/39] Introduce component for selecting color scales --- .../shared/components/ColorScaleDropdown.js | 118 ++++++++++++++++++ ui/src/style/components/color-dropdown.scss | 37 ++++-- 2 files changed, 145 insertions(+), 10 deletions(-) create mode 100644 ui/src/shared/components/ColorScaleDropdown.js diff --git a/ui/src/shared/components/ColorScaleDropdown.js b/ui/src/shared/components/ColorScaleDropdown.js new file mode 100644 index 0000000000..909d0bcc9e --- /dev/null +++ b/ui/src/shared/components/ColorScaleDropdown.js @@ -0,0 +1,118 @@ +import React, {Component} from 'react' +import PropTypes from 'prop-types' +import uuid from 'uuid' +import classnames from 'classnames' + +import OnClickOutside from 'shared/components/OnClickOutside' +import FancyScrollbar from 'shared/components/FancyScrollbar' + +import {LINE_COLOR_SCALES} from 'src/shared/constants/graphColorPalettes' + +class ColorScaleDropdown extends Component { + constructor(props) { + super(props) + + this.state = { + expanded: false, + } + } + + handleToggleMenu = () => { + const {disabled} = this.props + + if (disabled) { + return + } + this.setState({expanded: !this.state.expanded}) + } + + handleClickOutside = () => { + this.setState({expanded: false}) + } + + handleDropdownClick = colorScale => () => { + this.props.onChoose(colorScale) + this.setState({expanded: false}) + } + + generateGradientStyle = colors => ({ + background: `linear-gradient(to right, ${colors[0].hex} 0%,${ + colors[1].hex + } 50%,${colors[2].hex} 100%)`, + }) + + render() { + const {expanded} = this.state + const {selected, disabled, stretchToFit} = this.props + + const dropdownClassNames = classnames('color-dropdown', { + open: expanded, + 'color-dropdown--stretch': stretchToFit, + }) + const toggleClassNames = classnames( + 'btn btn-sm btn-default color-dropdown--toggle', + {active: expanded, 'color-dropdown__disabled': disabled} + ) + + return ( +
+
+
+
{selected[0].name}
+ +
+ {expanded ? ( +
+ + {LINE_COLOR_SCALES.map(colorScale => ( +
+
+ + {colorScale.name} + +
+ ))} + +
+ ) : null} +
+ ) + } +} + +const {arrayOf, bool, func, shape, string, number} = PropTypes + +ColorScaleDropdown.propTypes = { + selected: arrayOf( + shape({ + type: string.isRequired, + hex: string.isRequired, + id: string.isRequired, + name: string.isRequired, + value: number.isRequired, + }).isRequired + ).isRequired, + onChoose: func.isRequired, + stretchToFit: bool, + disabled: bool, +} + +export default OnClickOutside(ColorScaleDropdown) diff --git a/ui/src/style/components/color-dropdown.scss b/ui/src/style/components/color-dropdown.scss index b892cd0b22..99f6901f7b 100644 --- a/ui/src/style/components/color-dropdown.scss +++ b/ui/src/style/components/color-dropdown.scss @@ -4,6 +4,10 @@ */ $color-dropdown--circle: 14px; +$color-dropdown--bar: 104px; +$color-dropdown--bar-height: 10px; +$color-dropdown--left-padding: 11px; +$color-dropdown--name-padding: 20px; .color-dropdown { width: 140px; @@ -31,11 +35,11 @@ $color-dropdown--circle: 14px; position: absolute; top: 30px; left: 0; - z-index: 2; + z-index: 5; width: 100%; border-radius: 4px; box-shadow: 0 2px 5px 0.6px fade-out($g0-obsidian, 0.7); - @include gradient-h($g0-obsidian,$g2-kevlar); + @include gradient-h($g0-obsidian, $g2-kevlar); } .color-dropdown--item { @include no-user-select(); @@ -43,9 +47,7 @@ $color-dropdown--circle: 14px; height: 28px; position: relative; color: $g11-sidewalk; - transition: - color 0.25s ease, - background-color 0.25s ease; + transition: color 0.25s ease, background-color 0.25s ease; &:hover { background-color: $g4-onyx; @@ -67,6 +69,7 @@ $color-dropdown--circle: 14px; } } .color-dropdown--swatch, +.color-dropdown--swatches, .color-dropdown--name { position: absolute; top: 50%; @@ -76,21 +79,35 @@ $color-dropdown--circle: 14px; width: $color-dropdown--circle; height: $color-dropdown--circle; border-radius: 50%; - left: 11px; + left: $color-dropdown--left-padding; +} +.color-dropdown--swatches { + width: $color-dropdown--bar; + height: $color-dropdown--bar-height; + border-radius: $color-dropdown--bar-height / 2; + left: $color-dropdown--left-padding; } .color-dropdown--name { text-align: left; - right: 11px; - left: 34px; + right: $color-dropdown--name-padding; + left: $color-dropdown--circle + $color-dropdown--name-padding; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; font-weight: 600; text-transform: capitalize; + + .color-dropdown--swatches + & { + left: $color-dropdown--bar + $color-dropdown--name-padding; + } } -.color-dropdown .color-dropdown--menu .fancy-scroll--container .fancy-scroll--track-v .fancy-scroll--thumb-v { - @include gradient-v($g9-mountain,$g7-graphite); +.color-dropdown + .color-dropdown--menu + .fancy-scroll--container + .fancy-scroll--track-v + .fancy-scroll--thumb-v { + @include gradient-v($g9-mountain, $g7-graphite); } .color-dropdown--toggle.color-dropdown__disabled { color: $g7-graphite; From a3fc9b778cd69963cc6bb9126c25dd3f72e774d1 Mon Sep 17 00:00:00 2001 From: Alex P Date: Mon, 26 Mar 2018 19:10:19 -0700 Subject: [PATCH 08/39] Implement updating and rendering of line color scales --- .../dashboards/actions/cellEditorOverlay.js | 7 ++ ui/src/dashboards/components/AxesOptions.js | 2 + .../components/CellEditorOverlay.js | 9 +- ui/src/dashboards/components/Visualization.js | 34 +++++- ui/src/dashboards/containers/DashboardPage.js | 5 + .../dashboards/reducers/cellEditorOverlay.js | 15 +++ ui/src/shared/components/Dygraph.js | 44 +++++++- ui/src/shared/components/LineGraph.js | 9 +- .../components/LineGraphColorSelector.js | 59 ++++++++++ ui/src/shared/constants/graphColorPalettes.js | 106 +++++++++--------- 10 files changed, 223 insertions(+), 67 deletions(-) create mode 100644 ui/src/shared/components/LineGraphColorSelector.js diff --git a/ui/src/dashboards/actions/cellEditorOverlay.js b/ui/src/dashboards/actions/cellEditorOverlay.js index 34b4a5354e..f9efe0de08 100644 --- a/ui/src/dashboards/actions/cellEditorOverlay.js +++ b/ui/src/dashboards/actions/cellEditorOverlay.js @@ -57,3 +57,10 @@ export const updateTableOptions = tableOptions => ({ tableOptions, }, }) + +export const updateLineColors = lineColors => ({ + type: 'UPDATE_LINE_COLORS', + payload: { + lineColors, + }, +}) diff --git a/ui/src/dashboards/components/AxesOptions.js b/ui/src/dashboards/components/AxesOptions.js index c0e5019a7d..9b04de4659 100644 --- a/ui/src/dashboards/components/AxesOptions.js +++ b/ui/src/dashboards/components/AxesOptions.js @@ -7,6 +7,7 @@ import OptIn from 'shared/components/OptIn' import Input from 'src/dashboards/components/DisplayOptionsInput' import {Tabber, Tab} from 'src/dashboards/components/Tabber' import FancyScrollbar from 'shared/components/FancyScrollbar' +import LineGraphColorSelector from 'src/shared/components/LineGraphColorSelector' import { AXES_SCALE_OPTIONS, @@ -102,6 +103,7 @@ class AxesOptions extends Component { type="text" />
+
{ const {queriesWorkingDraft, staticLegend} = this.state - const {cell, thresholdsListColors, gaugeColors} = this.props + const {cell, thresholdsListColors, gaugeColors, lineColors} = this.props const queries = queriesWorkingDraft.map(q => { const timeRange = q.range || {upper: null, lower: ':dashboardTime:'} @@ -133,6 +133,12 @@ class CellEditorOverlay extends Component { colors = stringifyColorValues(thresholdsListColors) break } + case 'bar': + case 'line': + case 'line-stacked': + case 'line-stepplot': { + colors = stringifyColorValues(lineColors) + } } this.props.onSave({ @@ -392,6 +398,7 @@ CellEditorOverlay.propTypes = { thresholdsListType: string.isRequired, thresholdsListColors: arrayOf(shape({}).isRequired).isRequired, gaugeColors: arrayOf(shape({}).isRequired).isRequired, + lineColors: arrayOf(shape({}).isRequired).isRequired, } CEOBottom.propTypes = { diff --git a/ui/src/dashboards/components/Visualization.js b/ui/src/dashboards/components/Visualization.js index d84a76ed06..b9131af830 100644 --- a/ui/src/dashboards/components/Visualization.js +++ b/ui/src/dashboards/components/Visualization.js @@ -14,6 +14,7 @@ const DashVisualization = ( type, templates, timeRange, + lineColors, autoRefresh, gaugeColors, queryConfigs, @@ -26,14 +27,32 @@ const DashVisualization = ( }, {source: {links: {proxy}}} ) => { - const colors = type === 'gauge' ? gaugeColors : thresholdsListColors + let colors = [] + switch (type) { + case 'gauge': { + colors = stringifyColorValues(gaugeColors) + break + } + case 'single-stat': + case 'line-plus-single-stat': + case 'table': { + colors = stringifyColorValues(thresholdsListColors) + break + } + case 'bar': + case 'line': + case 'line-stacked': + case 'line-stepplot': { + colors = stringifyColorValues(lineColors) + } + } return (
({ gaugeColors, thresholdsListColors, + lineColors, type, axes, tableOptions, diff --git a/ui/src/dashboards/containers/DashboardPage.js b/ui/src/dashboards/containers/DashboardPage.js index 29516e202d..5df566e8ab 100644 --- a/ui/src/dashboards/containers/DashboardPage.js +++ b/ui/src/dashboards/containers/DashboardPage.js @@ -267,6 +267,7 @@ class DashboardPage extends Component { showTemplateControlBar, dashboard, dashboards, + lineColors, gaugeColors, autoRefresh, selectedCell, @@ -383,6 +384,7 @@ class DashboardPage extends Component { thresholdsListType={thresholdsListType} thresholdsListColors={thresholdsListColors} gaugeColors={gaugeColors} + lineColors={lineColors} /> ) : null} { @@ -532,6 +535,7 @@ const mapStateToProps = (state, {params: {dashboardID}}) => { thresholdsListType, thresholdsListColors, gaugeColors, + lineColors, }, } = state @@ -562,6 +566,7 @@ const mapStateToProps = (state, {params: {dashboardID}}) => { thresholdsListType, thresholdsListColors, gaugeColors, + lineColors, } } diff --git a/ui/src/dashboards/reducers/cellEditorOverlay.js b/ui/src/dashboards/reducers/cellEditorOverlay.js index 4629e89750..d51d2c503c 100644 --- a/ui/src/dashboards/reducers/cellEditorOverlay.js +++ b/ui/src/dashboards/reducers/cellEditorOverlay.js @@ -9,6 +9,11 @@ import { getThresholdsListType, } from 'shared/constants/thresholds' +import { + DEFAULT_LINE_COLORS, + validateLineColors, +} from 'src/shared/constants/graphColorPalettes' + import {initializeOptions} from 'src/dashboards/constants/cellEditor' export const initialState = { @@ -16,6 +21,7 @@ export const initialState = { thresholdsListType: THRESHOLD_TYPE_TEXT, thresholdsListColors: DEFAULT_THRESHOLDS_LIST_COLORS, gaugeColors: DEFAULT_GAUGE_COLORS, + lineColors: DEFAULT_LINE_COLORS, } export default function cellEditorOverlay(state = initialState, action) { @@ -36,12 +42,15 @@ export default function cellEditorOverlay(state = initialState, action) { initializeOptions('table') ) + const lineColors = validateLineColors(colors) + return { ...state, cell: {...cell, tableOptions}, thresholdsListType, thresholdsListColors, gaugeColors, + lineColors, } } @@ -101,6 +110,12 @@ export default function cellEditorOverlay(state = initialState, action) { return {...state, cell} } + + case 'UPDATE_LINE_COLORS': { + const {lineColors} = action.payload + + return {...state, lineColors} + } } return state diff --git a/ui/src/shared/components/Dygraph.js b/ui/src/shared/components/Dygraph.js index 7fe6e70399..e5a166093d 100644 --- a/ui/src/shared/components/Dygraph.js +++ b/ui/src/shared/components/Dygraph.js @@ -4,6 +4,7 @@ import PropTypes from 'prop-types' import {connect} from 'react-redux' import shallowCompare from 'react-addons-shallow-compare' import _ from 'lodash' +import chroma from 'chroma-js' import NanoDate from 'nano-date' import Dygraphs from 'src/external/dygraph' @@ -26,7 +27,11 @@ import { highlightSeriesOpts, } from 'src/shared/graphs/helpers' -import {generateColorScale} from 'src/shared/constants/graphColorPalettes' +import { + DEFAULT_LINE_COLORS, + validateLineColors, + transformColorsForChroma, +} from 'src/shared/constants/graphColorPalettes' const {LINEAR, LOG, BASE_10, BASE_2} = AXES_SCALE_OPTIONS class Dygraph extends Component { @@ -191,15 +196,35 @@ class Dygraph extends Component { } colorDygraphSeries = () => { - const {dygraphSeries} = this.props + const {dygraphSeries, children, colors, overrideLineColors} = this.props const numSeries = Object.keys(dygraphSeries).length - const colors = generateColorScale(numSeries) + const validatedLineColors = validateLineColors(colors) // ensures safe defaults + + let lineColors = chroma + .scale(transformColorsForChroma(validatedLineColors)) + .mode('lch') + .colors(numSeries) + + if (React.children && React.children.count(children)) { + // If graph is line-plus-single-stat then reserve colors for single stat + lineColors = chroma + .scale(transformColorsForChroma(DEFAULT_LINE_COLORS)) + .mode('lch') + .colors(numSeries) + } + + if (overrideLineColors && overrideLineColors.length > 0) { + lineColors = chroma + .scale(overrideLineColors) + .mode('lch') + .colors(numSeries) + } const coloredDygraphSeries = {} for (const seriesName in dygraphSeries) { const series = dygraphSeries[seriesName] - const color = colors[Object.keys(dygraphSeries).indexOf(seriesName)] + const color = lineColors[Object.keys(dygraphSeries).indexOf(seriesName)] coloredDygraphSeries[seriesName] = {...series, color} } @@ -423,7 +448,7 @@ Dygraph.propTypes = { isGraphFilled: bool, isBarGraph: bool, staticLegend: bool, - overrideLineColors: array, + overrideLineColors: arrayOf(string.isRequired), dygraphSeries: shape({}).isRequired, ruleValues: shape({ operator: string, @@ -440,6 +465,15 @@ Dygraph.propTypes = { onZoom: func, mode: string, children: node, + colors: arrayOf( + shape({ + type: string.isRequired, + hex: string.isRequired, + id: string.isRequired, + name: string.isRequired, + value: string.isRequired, + }).isRequired + ), } const mapStateToProps = ({annotations: {mode}}) => ({ diff --git a/ui/src/shared/components/LineGraph.js b/ui/src/shared/components/LineGraph.js index a7cabea3a1..305602b525 100644 --- a/ui/src/shared/components/LineGraph.js +++ b/ui/src/shared/components/LineGraph.js @@ -6,8 +6,6 @@ import shallowCompare from 'react-addons-shallow-compare' import SingleStat from 'src/shared/components/SingleStat' import timeSeriesToDygraph from 'utils/timeSeriesToDygraph' -import {SINGLE_STAT_LINE_COLORS} from 'src/shared/graphs/helpers' - class LineGraph extends Component { constructor(props) { super(props) @@ -84,10 +82,6 @@ class LineGraph extends Component { connectSeparatedPoints: true, } - const lineColors = showSingleStat - ? SINGLE_STAT_LINE_COLORS - : overrideLineColors - const containerStyle = { width: 'calc(100% - 32px)', height: 'calc(100% - 16px)', @@ -117,7 +111,8 @@ class LineGraph extends Component { resizeCoords={resizeCoords} dygraphSeries={dygraphSeries} setResolution={setResolution} - overrideLineColors={lineColors} + colors={colors} + overrideLineColors={overrideLineColors} containerStyle={containerStyle} staticLegend={staticLegend} isGraphFilled={showSingleStat ? false : isGraphFilled} diff --git a/ui/src/shared/components/LineGraphColorSelector.js b/ui/src/shared/components/LineGraphColorSelector.js new file mode 100644 index 0000000000..a8bfc8e06b --- /dev/null +++ b/ui/src/shared/components/LineGraphColorSelector.js @@ -0,0 +1,59 @@ +import React, {Component} from 'react' +import PropTypes from 'prop-types' +import {connect} from 'react-redux' +import {bindActionCreators} from 'redux' + +import ColorScaleDropdown from 'shared/components/ColorScaleDropdown' + +import {updateLineColors} from 'src/dashboards/actions/cellEditorOverlay' + +class LineGraphColorSelector extends Component { + handleSelectColors = colorScale => { + const {handleUpdateLineColors} = this.props + const {colors} = colorScale + + handleUpdateLineColors(colors) + } + + render() { + const {lineColors} = this.props + + return ( +
+ + +
+ ) + } +} + +const {arrayOf, func, shape, string, number} = PropTypes + +LineGraphColorSelector.propTypes = { + lineColors: arrayOf( + shape({ + type: string.isRequired, + hex: string.isRequired, + id: string.isRequired, + name: string.isRequired, + value: number.isRequired, + }).isRequired + ).isRequired, + handleUpdateLineColors: func.isRequired, +} + +const mapStateToProps = ({cellEditorOverlay: {lineColors}}) => ({ + lineColors, +}) + +const mapDispatchToProps = dispatch => ({ + handleUpdateLineColors: bindActionCreators(updateLineColors, dispatch), +}) + +export default connect(mapStateToProps, mapDispatchToProps)( + LineGraphColorSelector +) diff --git a/ui/src/shared/constants/graphColorPalettes.js b/ui/src/shared/constants/graphColorPalettes.js index ba8773c829..c7d6ed9f5c 100644 --- a/ui/src/shared/constants/graphColorPalettes.js +++ b/ui/src/shared/constants/graphColorPalettes.js @@ -1,24 +1,23 @@ -import _ from 'lodash' -import chroma from 'chroma-js' +const COLOR_TYPE_SCALE = 'scale' // Color Palettes export const LINE_COLORS_A = [ { - type: 'scale', + type: COLOR_TYPE_SCALE, hex: '#31C0F6', id: '0', name: 'Nineteen Eighty Four', value: 0, }, { - type: 'scale', + type: COLOR_TYPE_SCALE, hex: '#A500A5', id: '0', name: 'Nineteen Eighty Four', value: 0, }, { - type: 'scale', + type: COLOR_TYPE_SCALE, hex: '#FF7E27', id: '0', name: 'Nineteen Eighty Four', @@ -28,21 +27,21 @@ export const LINE_COLORS_A = [ export const LINE_COLORS_B = [ { - type: 'scale', + type: COLOR_TYPE_SCALE, hex: '#74D495', id: '1', name: 'Atlantis', value: 0, }, { - type: 'scale', + type: COLOR_TYPE_SCALE, hex: '#3F3FBA', id: '1', name: 'Atlantis', value: 0, }, { - type: 'scale', + type: COLOR_TYPE_SCALE, hex: '#EA5994', id: '1', name: 'Atlantis', @@ -52,124 +51,126 @@ export const LINE_COLORS_B = [ export const LINE_COLORS_C = [ { - type: 'scale', + type: COLOR_TYPE_SCALE, hex: '#8F8AF4', id: '1', - name: 'Glarbh', + name: 'Do Androids Dream of Electric Sheep?', value: 0, }, { - type: 'scale', + type: COLOR_TYPE_SCALE, hex: '#A51414', id: '1', - name: 'Glarbh', + name: 'Do Androids Dream of Electric Sheep?', value: 0, }, { - type: 'scale', + type: COLOR_TYPE_SCALE, hex: '#F4CF31', id: '1', - name: 'Glarbh', + name: 'Do Androids Dream of Electric Sheep?', value: 0, }, ] export const LINE_COLORS_D = [ { - type: 'scale', + type: COLOR_TYPE_SCALE, hex: '#FD7A5D', id: '1', - name: 'Spoot', + name: 'Delorean', value: 0, }, { - type: 'scale', + type: COLOR_TYPE_SCALE, hex: '#5F1CF2', id: '1', - name: 'Spoot', + name: 'Delorean', value: 0, }, { - type: 'scale', + type: COLOR_TYPE_SCALE, hex: '#4CE09A', id: '1', - name: 'Spoot', + name: 'Delorean', value: 0, }, ] export const LINE_COLORS_E = [ { - type: 'scale', + type: COLOR_TYPE_SCALE, hex: '#FDC44F', id: '1', - name: 'Swump', + name: 'Cthulhu', value: 0, }, { - type: 'scale', + type: COLOR_TYPE_SCALE, hex: '#007C76', id: '1', - name: 'Swump', + name: 'Cthulhu', value: 0, }, { - type: 'scale', + type: COLOR_TYPE_SCALE, hex: '#8983FF', id: '1', - name: 'Swump', + name: 'Cthulhu', value: 0, }, ] export const LINE_COLORS_F = [ { - type: 'scale', + type: COLOR_TYPE_SCALE, hex: '#DA6FF1', id: '1', - name: 'Splort', + name: 'Ectoplasm', value: 0, }, { - type: 'scale', + type: COLOR_TYPE_SCALE, hex: '#00717A', id: '1', - name: 'Splort', + name: 'Ectoplasm', value: 0, }, { - type: 'scale', + type: COLOR_TYPE_SCALE, hex: '#05B7E0', id: '1', - name: 'Splort', + name: 'Ectoplasm', value: 0, }, ] export const LINE_COLORS_G = [ { - type: 'scale', + type: COLOR_TYPE_SCALE, hex: '#F6F6F8', id: '1', - name: 'OldTimey', + name: 'T-Max 400 Film', value: 0, }, { - type: 'scale', + type: COLOR_TYPE_SCALE, hex: '#A4A8B6', id: '1', - name: 'OldTimey', + name: 'T-Max 400 Film', value: 0, }, { - type: 'scale', + type: COLOR_TYPE_SCALE, hex: '#545667', id: '1', - name: 'OldTimey', + name: 'T-Max 400 Film', value: 0, }, ] +export const DEFAULT_LINE_COLORS = LINE_COLORS_A + export const LINE_COLOR_SCALES = [ LINE_COLORS_A, LINE_COLORS_B, @@ -180,23 +181,24 @@ export const LINE_COLOR_SCALES = [ LINE_COLORS_G, ].map(colorScale => { const name = colorScale[0].name - const colors = colorScale.map(color => color.hex) + const colors = colorScale const id = colorScale[0].id return {name, colors, id} }) -const paletteA = ['#31C0F6', '#A500A5', '#FF7E27'] -const paletteB = ['#74D495', '#3F3FBA', '#EA5994'] -const paletteC = ['#8F8AF4', '#A51414', '#F4CF31'] -const paletteD = ['#FD7A5D', '#5F1CF2', '#4CE09A'] -const paletteE = ['#FDC44F', '#007C76', '#8983FF'] -const paletteF = ['#DA6FF1', '#00717A', '#05B7E0'] -const paletteG = ['#F6F6F8', '#A4A8B6', '#545667'] - -export const generateColorScale = numSeries => { - return chroma - .scale(paletteB) - .mode('lch') - .colors(numSeries) +export const transformColorsForChroma = colors => { + return colors.map(color => color.hex) +} + +export const validateLineColors = colors => { + if (!colors || colors.length !== 3) { + return DEFAULT_LINE_COLORS + } + + const testColorsTypes = + colors.filter(color => color.type === COLOR_TYPE_SCALE).length === + colors.length + + return testColorsTypes ? colors : DEFAULT_LINE_COLORS } From 6edb4f30e461fcfe0438dd765a8654f1d5664eb4 Mon Sep 17 00:00:00 2001 From: Alex P Date: Mon, 26 Mar 2018 19:14:06 -0700 Subject: [PATCH 09/39] Write reducer test for updating line graph colors --- ui/test/dashboards/reducers/cellEditorOverlay.test.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ui/test/dashboards/reducers/cellEditorOverlay.test.js b/ui/test/dashboards/reducers/cellEditorOverlay.test.js index 2d29ecf67b..eb11c734e0 100644 --- a/ui/test/dashboards/reducers/cellEditorOverlay.test.js +++ b/ui/test/dashboards/reducers/cellEditorOverlay.test.js @@ -8,6 +8,7 @@ import { updateThresholdsListColors, updateThresholdsListType, updateGaugeColors, + updateLineColors, updateAxes, } from 'src/dashboards/actions/cellEditorOverlay' import {DEFAULT_TABLE_OPTIONS} from 'src/shared/constants/tableGraph' @@ -17,6 +18,7 @@ import { validateThresholdsListColors, getThresholdsListType, } from 'shared/constants/thresholds' +import {validateLineColors} from 'src/shared/constants/graphColorPalettes' const defaultCellType = 'line' const defaultCellName = 'defaultCell' @@ -45,6 +47,7 @@ const defaultThresholdsListColors = validateThresholdsListColors( defaultThresholdsListType ) const defaultGaugeColors = validateGaugeColors(defaultCell.colors) +const defaultLineColors = validateLineColors(defaultCell.colors) describe('Dashboards.Reducers.cellEditorOverlay', () => { it('should show cell editor overlay', () => { @@ -117,4 +120,11 @@ describe('Dashboards.Reducers.cellEditorOverlay', () => { expect(actual.cell.axes).toBe(expected) }) + + it('should update the cell line graph colors', () => { + const actual = reducer(initialState, updateLineColors(defaultLineColors)) + const expected = defaultLineColors + + expect(actual.lineColors).toBe(expected) + }) }) From 7d08f0bf23d5e988977364d977016f66134bb80c Mon Sep 17 00:00:00 2001 From: Alex P Date: Mon, 26 Mar 2018 19:33:47 -0700 Subject: [PATCH 10/39] Remove dots from static legend --- ui/src/shared/components/StaticLegend.js | 4 ---- ui/src/style/components/static-legend.scss | 24 ++++++---------------- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/ui/src/shared/components/StaticLegend.js b/ui/src/shared/components/StaticLegend.js index f79c6cf115..7de93f177a 100644 --- a/ui/src/shared/components/StaticLegend.js +++ b/ui/src/shared/components/StaticLegend.js @@ -86,10 +86,6 @@ class StaticLegend extends Component { key={uuid.v4()} onMouseDown={this.handleClick(i)} > -
{removeMeasurement(v)}
))} diff --git a/ui/src/style/components/static-legend.scss b/ui/src/style/components/static-legend.scss index a9600a11a5..252620299d 100644 --- a/ui/src/style/components/static-legend.scss +++ b/ui/src/style/components/static-legend.scss @@ -16,17 +16,9 @@ flex-wrap: wrap; max-height: 50%; overflow: auto; - @include custom-scrollbar($g3-castle,$g6-smoke); -} -.static-legend--dot { - display: inline-block; - vertical-align: middle; - margin-right: 4px; - width: 8px; - height: 8px; - border-radius: 50%; - background-color: $g20-white; + @include custom-scrollbar($g3-castle, $g6-smoke); } + .static-legend--item, .static-legend--single { height: 22px; @@ -43,8 +35,7 @@ .static-legend--item { transition: background-color 0.25s ease, color 0.25s ease; - span, - .static-legend--dot { + span { opacity: 0.8; transition: opacity 0.25s ease; } @@ -53,8 +44,7 @@ cursor: pointer; background-color: $g6-smoke; - span, - .static-legend--dot { + span { opacity: 1; } } @@ -62,16 +52,14 @@ background-color: $g1-raven; font-style: italic; - span, - .static-legend--dot { + span { opacity: 0.35; } &:hover { background-color: $g2-kevlar; - span, - .static-legend--dot { + span { opacity: 0.65; } } From 4b4425e45c575914aded426aec38b01449c3438c Mon Sep 17 00:00:00 2001 From: Alex P Date: Tue, 27 Mar 2018 11:41:13 -0700 Subject: [PATCH 11/39] Improve color selection for graphs with 1 or 2 lines --- ui/src/shared/components/Dygraph.js | 14 +++--------- ui/src/shared/constants/graphColorPalettes.js | 22 +++++++++++++++---- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/ui/src/shared/components/Dygraph.js b/ui/src/shared/components/Dygraph.js index e5a166093d..ca6c80d02a 100644 --- a/ui/src/shared/components/Dygraph.js +++ b/ui/src/shared/components/Dygraph.js @@ -29,8 +29,7 @@ import { import { DEFAULT_LINE_COLORS, - validateLineColors, - transformColorsForChroma, + getLineColorsHexes, } from 'src/shared/constants/graphColorPalettes' const {LINEAR, LOG, BASE_10, BASE_2} = AXES_SCALE_OPTIONS @@ -198,19 +197,12 @@ class Dygraph extends Component { colorDygraphSeries = () => { const {dygraphSeries, children, colors, overrideLineColors} = this.props const numSeries = Object.keys(dygraphSeries).length - const validatedLineColors = validateLineColors(colors) // ensures safe defaults - let lineColors = chroma - .scale(transformColorsForChroma(validatedLineColors)) - .mode('lch') - .colors(numSeries) + let lineColors = getLineColorsHexes(colors, numSeries) if (React.children && React.children.count(children)) { // If graph is line-plus-single-stat then reserve colors for single stat - lineColors = chroma - .scale(transformColorsForChroma(DEFAULT_LINE_COLORS)) - .mode('lch') - .colors(numSeries) + lineColors = getLineColorsHexes(DEFAULT_LINE_COLORS, numSeries) } if (overrideLineColors && overrideLineColors.length > 0) { diff --git a/ui/src/shared/constants/graphColorPalettes.js b/ui/src/shared/constants/graphColorPalettes.js index c7d6ed9f5c..a6095e5476 100644 --- a/ui/src/shared/constants/graphColorPalettes.js +++ b/ui/src/shared/constants/graphColorPalettes.js @@ -1,3 +1,5 @@ +import chroma from 'chroma-js' + const COLOR_TYPE_SCALE = 'scale' // Color Palettes @@ -187,10 +189,6 @@ export const LINE_COLOR_SCALES = [ return {name, colors, id} }) -export const transformColorsForChroma = colors => { - return colors.map(color => color.hex) -} - export const validateLineColors = colors => { if (!colors || colors.length !== 3) { return DEFAULT_LINE_COLORS @@ -202,3 +200,19 @@ export const validateLineColors = colors => { return testColorsTypes ? colors : DEFAULT_LINE_COLORS } + +export const getLineColorsHexes = (colors, numSeries) => { + const validatedColors = validateLineColors(colors) // ensures safe defaults + const colorsHexArray = validatedColors.map(color => color.hex) + + if (numSeries === 1) { + return [colorsHexArray[0]] + } + if (numSeries === 2) { + return [colorsHexArray[0], colorsHexArray[1]] + } + return chroma + .scale(colorsHexArray) + .mode('lch') + .colors(numSeries) +} From 763ce1b353325a23972e1693550691847dddcb3f Mon Sep 17 00:00:00 2001 From: Alex P Date: Tue, 27 Mar 2018 12:03:03 -0700 Subject: [PATCH 12/39] Remove obsolete code --- ui/src/shared/constants/colorOperations.js | 83 ---------------------- 1 file changed, 83 deletions(-) diff --git a/ui/src/shared/constants/colorOperations.js b/ui/src/shared/constants/colorOperations.js index 0219ae1d29..3c745c904f 100644 --- a/ui/src/shared/constants/colorOperations.js +++ b/ui/src/shared/constants/colorOperations.js @@ -108,86 +108,3 @@ export const generateThresholdsListHexs = ({ const textColor = baseColor.hex return {bgColor, textColor} } - -// Handy tool for converting Hexcodes to HSL values -export const HexcodeToHSL = hex => { - const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex) - - const red = parseInt(result[1], 16) / 255 - const green = parseInt(result[2], 16) / 255 - const blue = parseInt(result[3], 16) / 255 - const max = Math.max(red, green, blue) - const min = Math.min(red, green, blue) - - let hue, - saturation, - lightness = (max + min) / 2 - - if (max === min) { - hue = saturation = 0 // achromatic - } else { - const d = max - min - saturation = lightness > 0.5 ? d / (2 - max - min) : d / (max + min) - switch (max) { - case red: - hue = (green - blue) / d + (green < blue ? 6 : 0) - break - case green: - hue = (blue - red) / d + 2 - break - case blue: - hue = (red - green) / d + 4 - break - } - hue /= 6 - } - - hue = Math.round(360 * hue) - saturation = Math.round(saturation * 100) - lightness = Math.round(lightness * 100) - - return {hue, saturation, lightness} -} - -// Handy tool for converting HSL values to Hexcode -export const HSLToHexcode = (hue, saturation, lightness) => { - hue /= 360 - saturation /= 100 - lightness /= 100 - let red, green, blue - if (saturation === 0) { - red = green = blue = lightness // achromatic - } else { - const hue2rgb = (p, q, t) => { - if (t < 0) { - t += 1 - } - if (t > 1) { - t -= 1 - } - if (t < 1 / 6) { - return p + (q - p) * 6 * t - } - if (t < 1 / 2) { - return q - } - if (t < 2 / 3) { - return p + (q - p) * (2 / 3 - t) * 6 - } - return p - } - const q = - lightness < 0.5 - ? lightness * (1 + saturation) - : lightness + saturation - lightness * saturation - const p = 2 * lightness - q - red = hue2rgb(p, q, hue + 1 / 3) - green = hue2rgb(p, q, hue) - blue = hue2rgb(p, q, hue - 1 / 3) - } - const toHex = x => { - const hex = Math.round(x * 255).toString(16) - return hex.length === 1 ? `0${hex}` : hex - } - return `#${toHex(red)}${toHex(green)}${toHex(blue)}` -} From cf30c773ea2dd6067763a301bdcb9ecd79364fd2 Mon Sep 17 00:00:00 2001 From: Alex P Date: Tue, 27 Mar 2018 12:05:12 -0700 Subject: [PATCH 13/39] Improve contrast of color palette --- ui/src/shared/constants/graphColorPalettes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/shared/constants/graphColorPalettes.js b/ui/src/shared/constants/graphColorPalettes.js index a6095e5476..133ccc4bc3 100644 --- a/ui/src/shared/constants/graphColorPalettes.js +++ b/ui/src/shared/constants/graphColorPalettes.js @@ -140,7 +140,7 @@ export const LINE_COLORS_F = [ }, { type: COLOR_TYPE_SCALE, - hex: '#05B7E0', + hex: '#ACFF76', id: '1', name: 'Ectoplasm', value: 0, From c32c0eb24ace208685a85550a0fb023b6d3ccc9e Mon Sep 17 00:00:00 2001 From: Alex P Date: Tue, 27 Mar 2018 12:15:45 -0700 Subject: [PATCH 14/39] Silence console error --- ui/src/dashboards/components/Visualization.js | 30 ++----------------- .../shared/components/ColorScaleDropdown.js | 3 +- .../components/LineGraphColorSelector.js | 3 +- 3 files changed, 5 insertions(+), 31 deletions(-) diff --git a/ui/src/dashboards/components/Visualization.js b/ui/src/dashboards/components/Visualization.js index b9131af830..70da958277 100644 --- a/ui/src/dashboards/components/Visualization.js +++ b/ui/src/dashboards/components/Visualization.js @@ -88,33 +88,9 @@ DashVisualization.propTypes = { }), tableOptions: shape({}), resizerTopHeight: number, - thresholdsListColors: arrayOf( - shape({ - type: string.isRequired, - hex: string.isRequired, - id: string.isRequired, - name: string.isRequired, - value: number.isRequired, - }).isRequired - ), - gaugeColors: arrayOf( - shape({ - type: string.isRequired, - hex: string.isRequired, - id: string.isRequired, - name: string.isRequired, - value: number.isRequired, - }).isRequired - ), - lineColors: arrayOf( - shape({ - type: string.isRequired, - hex: string.isRequired, - id: string.isRequired, - name: string.isRequired, - value: number.isRequired, - }).isRequired - ), + thresholdsListColors: arrayOf(shape({}).isRequired), + gaugeColors: arrayOf(shape({}).isRequired), + lineColors: arrayOf(shape({}).isRequired), staticLegend: bool, setDataLabels: func, } diff --git a/ui/src/shared/components/ColorScaleDropdown.js b/ui/src/shared/components/ColorScaleDropdown.js index 909d0bcc9e..66ca74e55d 100644 --- a/ui/src/shared/components/ColorScaleDropdown.js +++ b/ui/src/shared/components/ColorScaleDropdown.js @@ -98,7 +98,7 @@ class ColorScaleDropdown extends Component { } } -const {arrayOf, bool, func, shape, string, number} = PropTypes +const {arrayOf, bool, func, shape, string} = PropTypes ColorScaleDropdown.propTypes = { selected: arrayOf( @@ -107,7 +107,6 @@ ColorScaleDropdown.propTypes = { hex: string.isRequired, id: string.isRequired, name: string.isRequired, - value: number.isRequired, }).isRequired ).isRequired, onChoose: func.isRequired, diff --git a/ui/src/shared/components/LineGraphColorSelector.js b/ui/src/shared/components/LineGraphColorSelector.js index a8bfc8e06b..1b197c0987 100644 --- a/ui/src/shared/components/LineGraphColorSelector.js +++ b/ui/src/shared/components/LineGraphColorSelector.js @@ -31,7 +31,7 @@ class LineGraphColorSelector extends Component { } } -const {arrayOf, func, shape, string, number} = PropTypes +const {arrayOf, func, shape, string} = PropTypes LineGraphColorSelector.propTypes = { lineColors: arrayOf( @@ -40,7 +40,6 @@ LineGraphColorSelector.propTypes = { hex: string.isRequired, id: string.isRequired, name: string.isRequired, - value: number.isRequired, }).isRequired ).isRequired, handleUpdateLineColors: func.isRequired, From 7fab9b3f6498c772a0baa42eaffd0dbb47c0a4d9 Mon Sep 17 00:00:00 2001 From: Alex P Date: Tue, 27 Mar 2018 12:19:56 -0700 Subject: [PATCH 15/39] Improve color palette contrast --- ui/src/shared/constants/graphColorPalettes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/shared/constants/graphColorPalettes.js b/ui/src/shared/constants/graphColorPalettes.js index 133ccc4bc3..ea98f269ed 100644 --- a/ui/src/shared/constants/graphColorPalettes.js +++ b/ui/src/shared/constants/graphColorPalettes.js @@ -44,7 +44,7 @@ export const LINE_COLORS_B = [ }, { type: COLOR_TYPE_SCALE, - hex: '#EA5994', + hex: '#FF4D9E', id: '1', name: 'Atlantis', value: 0, From 5d3be94f04f68f6ce5a5c820d60cbbbaf9689a2e Mon Sep 17 00:00:00 2001 From: Alex P Date: Tue, 27 Mar 2018 15:33:06 -0700 Subject: [PATCH 16/39] Make RuleGraph comply with new shape of overrideColors --- ui/src/kapacitor/components/RuleGraph.js | 5 +++-- ui/src/shared/components/Dygraph.js | 15 ++++++++------- ui/src/shared/constants/graphColorPalettes.js | 14 ++++++++++++-- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/ui/src/kapacitor/components/RuleGraph.js b/ui/src/kapacitor/components/RuleGraph.js index a181243aea..585af02b62 100644 --- a/ui/src/kapacitor/components/RuleGraph.js +++ b/ui/src/kapacitor/components/RuleGraph.js @@ -8,6 +8,8 @@ import underlayCallback from 'src/kapacitor/helpers/ruleGraphUnderlay' const RefreshingLineGraph = AutoRefresh(LineGraph) +import {LINE_COLORS_RULE_GRAPH} from 'src/shared/constants/graphColorPalettes' + const {shape, string, func} = PropTypes const RuleGraph = ({ query, @@ -20,7 +22,6 @@ const RuleGraph = ({ const autoRefreshMs = 30000 const queryText = buildInfluxQLQuery({lower}, query) const queries = [{host: source.links.proxy, text: queryText}] - const kapacitorLineColors = ['#4ED8A0'] if (!queryText) { return ( @@ -47,7 +48,7 @@ const RuleGraph = ({ isGraphFilled={false} ruleValues={rule.values} autoRefresh={autoRefreshMs} - overrideLineColors={kapacitorLineColors} + overrideLineColors={LINE_COLORS_RULE_GRAPH} underlayCallback={underlayCallback(rule)} />
diff --git a/ui/src/shared/components/Dygraph.js b/ui/src/shared/components/Dygraph.js index ca6c80d02a..5b975170be 100644 --- a/ui/src/shared/components/Dygraph.js +++ b/ui/src/shared/components/Dygraph.js @@ -4,7 +4,6 @@ import PropTypes from 'prop-types' import {connect} from 'react-redux' import shallowCompare from 'react-addons-shallow-compare' import _ from 'lodash' -import chroma from 'chroma-js' import NanoDate from 'nano-date' import Dygraphs from 'src/external/dygraph' @@ -205,11 +204,8 @@ class Dygraph extends Component { lineColors = getLineColorsHexes(DEFAULT_LINE_COLORS, numSeries) } - if (overrideLineColors && overrideLineColors.length > 0) { - lineColors = chroma - .scale(overrideLineColors) - .mode('lch') - .colors(numSeries) + if (overrideLineColors) { + lineColors = getLineColorsHexes(overrideLineColors, numSeries) } const coloredDygraphSeries = {} @@ -440,7 +436,12 @@ Dygraph.propTypes = { isGraphFilled: bool, isBarGraph: bool, staticLegend: bool, - overrideLineColors: arrayOf(string.isRequired), + overrideLineColors: arrayOf( + shape({ + type: string.isRequired, + hex: string.isRequired, + }).isRequired + ), dygraphSeries: shape({}).isRequired, ruleValues: shape({ operator: string, diff --git a/ui/src/shared/constants/graphColorPalettes.js b/ui/src/shared/constants/graphColorPalettes.js index ea98f269ed..ce6b21a03b 100644 --- a/ui/src/shared/constants/graphColorPalettes.js +++ b/ui/src/shared/constants/graphColorPalettes.js @@ -171,6 +171,16 @@ export const LINE_COLORS_G = [ }, ] +export const LINE_COLORS_RULE_GRAPH = [ + { + type: COLOR_TYPE_SCALE, + hex: '#4ED8A0', + id: '1', + name: 'Rainforest', + value: 0, + }, +] + export const DEFAULT_LINE_COLORS = LINE_COLORS_A export const LINE_COLOR_SCALES = [ @@ -190,7 +200,7 @@ export const LINE_COLOR_SCALES = [ }) export const validateLineColors = colors => { - if (!colors || colors.length !== 3) { + if (!colors) { return DEFAULT_LINE_COLORS } @@ -205,7 +215,7 @@ export const getLineColorsHexes = (colors, numSeries) => { const validatedColors = validateLineColors(colors) // ensures safe defaults const colorsHexArray = validatedColors.map(color => color.hex) - if (numSeries === 1) { + if (numSeries === 1 || numSeries === 0) { return [colorsHexArray[0]] } if (numSeries === 2) { From 01463226293d10da21c00d6b1fac16e1ffd490bc Mon Sep 17 00:00:00 2001 From: Alex P Date: Tue, 27 Mar 2018 15:36:05 -0700 Subject: [PATCH 17/39] Updoot log of change --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3063f7d8c..146b1505aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ 1. [#2973](https://github.com/influxdata/chronograf/pull/2973): Add unsafe SSL to Kapacitor UI configuration 1. [#3047](https://github.com/influxdata/chronograf/pull/3047): Add server flag to grant SuperAdmin status to users authenticating from a specific Auth0 Organization +1. [#3060](https://github.com/influxdata/chronograf/pull/3060): Add ability to set a color palette for Line, Stacked, Step-Plot, and Bar graphs ### UI Improvements From a65b482419f72393238981beac2957ff9e15b7e4 Mon Sep 17 00:00:00 2001 From: Alex P Date: Wed, 28 Mar 2018 10:04:33 -0700 Subject: [PATCH 18/39] Guard against colors being passed in as an empty array --- ui/src/shared/constants/graphColorPalettes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/shared/constants/graphColorPalettes.js b/ui/src/shared/constants/graphColorPalettes.js index ce6b21a03b..079f45c023 100644 --- a/ui/src/shared/constants/graphColorPalettes.js +++ b/ui/src/shared/constants/graphColorPalettes.js @@ -200,7 +200,7 @@ export const LINE_COLOR_SCALES = [ }) export const validateLineColors = colors => { - if (!colors) { + if (!colors || colors.length === 0) { return DEFAULT_LINE_COLORS } From bde397be680d87f7174771a3981363d5d69bb8cf Mon Sep 17 00:00:00 2001 From: ebb-tide Date: Wed, 28 Mar 2018 11:00:27 -0700 Subject: [PATCH 19/39] Flip feature flag for table graphs --- ui/src/dashboards/graphics/graph.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/ui/src/dashboards/graphics/graph.js b/ui/src/dashboards/graphics/graph.js index 4038517bb8..8473a9f5b6 100644 --- a/ui/src/dashboards/graphics/graph.js +++ b/ui/src/dashboards/graphics/graph.js @@ -545,10 +545,9 @@ export const GRAPH_TYPES = [ menuOption: 'Gauge', graphic: GRAPH_SVGS.gauge, }, - // FEATURE FLAG for Table-Graph - // { - // type: 'table', - // menuOption: 'Table', - // graphic: GRAPH_SVGS.table, - // }, + { + type: 'table', + menuOption: 'Table', + graphic: GRAPH_SVGS.table, + }, ] From a5b9ee2038100a08e964ab0569791356573b5929 Mon Sep 17 00:00:00 2001 From: Luke Morris Date: Wed, 28 Mar 2018 11:18:45 -0700 Subject: [PATCH 20/39] Update PR template: Use GH Keyword; Reorganize/compact sections --- .github/PULL_REQUEST_TEMPLATE | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE b/.github/PULL_REQUEST_TEMPLATE index 2ed630156a..71061652ba 100644 --- a/.github/PULL_REQUEST_TEMPLATE +++ b/.github/PULL_REQUEST_TEMPLATE @@ -1,13 +1,10 @@ +Closes # + +_Briefly describe your proposed changes:_ +_What was the problem?_ +_What was the solution?_ - [ ] CHANGELOG.md updated with a link to the PR (not the Issue) - [ ] Rebased/mergable - [ ] Tests pass - - [ ] Sign [CLA](https://influxdata.com/community/cla/) (if not already signed) - -Connect # - -### The problem - -### The Solution - - + - [ ] Sign [CLA](https://influxdata.com/community/cla/) (if not already signed) \ No newline at end of file From f8b55255e96913dd05ccb8017f26aed48e3920c1 Mon Sep 17 00:00:00 2001 From: ebb-tide Date: Thu, 29 Mar 2018 10:02:33 -0700 Subject: [PATCH 21/39] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 458cc9f38c..7e62df60ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### Features 1. [#2526](https://github.com/influxdata/chronograf/pull/2526): Add support for RS256/JWKS verification, support for id_token parsing (as in ADFS) +1. [#3080](https://github.com/influxdata/chronograf/pull/3080): Add tabular data visualization option with features ### UI Improvements ### Bug Fixes From 2abe8db506889f123b10165be54f7a07929cea07 Mon Sep 17 00:00:00 2001 From: Alex P Date: Thu, 29 Mar 2018 10:27:06 -0700 Subject: [PATCH 22/39] Move changelog entry to 1.5 --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fedf7df23..331884c021 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,12 @@ ## v1.5.0.0 [unreleased] ### Features + 1. [#2526](https://github.com/influxdata/chronograf/pull/2526): Add support for RS256/JWKS verification, support for id_token parsing (as in ADFS) +1. [#3060](https://github.com/influxdata/chronograf/pull/3060): Add ability to set a color palette for Line, Stacked, Step-Plot, and Bar graphs ### UI Improvements + ### Bug Fixes ## v1.4.3.0 [unreleased] @@ -18,7 +21,6 @@ 1. [#2973](https://github.com/influxdata/chronograf/pull/2973): Add unsafe SSL to Kapacitor UI configuration 1. [#3047](https://github.com/influxdata/chronograf/pull/3047): Add server flag to grant SuperAdmin status to users authenticating from a specific Auth0 Organization -1. [#3060](https://github.com/influxdata/chronograf/pull/3060): Add ability to set a color palette for Line, Stacked, Step-Plot, and Bar graphs ### UI Improvements @@ -55,6 +57,7 @@ ## v1.4.2.1 [2018-02-28] ### Features + 1. [#2837](https://github.com/influxdata/chronograf/pull/2837): Prevent execution of queries in cells that are not in view on the dashboard page 1. [#2829](https://github.com/influxdata/chronograf/pull/2829): Add an optional persistent legend which can toggle series visibility to dashboard cells 1. [#2846](https://github.com/influxdata/chronograf/pull/2846): Allow user to annotate graphs via UI or API From b43d8a553be4185f52eb14d91eca157d586ca134 Mon Sep 17 00:00:00 2001 From: Alex P Date: Mon, 2 Apr 2018 10:51:36 -0700 Subject: [PATCH 23/39] Extract color formatting function into constant --- .../components/CellEditorOverlay.js | 28 +++++------------ ui/src/dashboards/components/Visualization.js | 27 +++++----------- ui/src/dashboards/constants/cellEditor.js | 31 +++++++++++++++++++ 3 files changed, 45 insertions(+), 41 deletions(-) diff --git a/ui/src/dashboards/components/CellEditorOverlay.js b/ui/src/dashboards/components/CellEditorOverlay.js index 44eb2e977d..7df14d5ae9 100644 --- a/ui/src/dashboards/components/CellEditorOverlay.js +++ b/ui/src/dashboards/components/CellEditorOverlay.js @@ -24,7 +24,7 @@ import { import {OVERLAY_TECHNOLOGY} from 'src/shared/constants/classNames' import {MINIMUM_HEIGHTS, INITIAL_HEIGHTS} from 'src/data_explorer/constants' import {AUTO_GROUP_BY} from 'src/shared/constants' -import {stringifyColorValues} from 'src/shared/constants/colorOperations' +import {getCellTypeColors} from 'src/dashboards/constants/cellEditor' class CellEditorOverlay extends Component { constructor(props) { @@ -120,26 +120,12 @@ class CellEditorOverlay extends Component { } }) - let colors = [] - - switch (cell.type) { - case 'gauge': { - colors = stringifyColorValues(gaugeColors) - break - } - case 'single-stat': - case 'line-plus-single-stat': - case 'table': { - colors = stringifyColorValues(thresholdsListColors) - break - } - case 'bar': - case 'line': - case 'line-stacked': - case 'line-stepplot': { - colors = stringifyColorValues(lineColors) - } - } + const colors = getCellTypeColors({ + cellType: cell.type, + gaugeColors, + thresholdsListColors, + lineColors, + }) this.props.onSave({ ...cell, diff --git a/ui/src/dashboards/components/Visualization.js b/ui/src/dashboards/components/Visualization.js index 70da958277..1ac3d5d196 100644 --- a/ui/src/dashboards/components/Visualization.js +++ b/ui/src/dashboards/components/Visualization.js @@ -6,7 +6,7 @@ import RefreshingGraph from 'src/shared/components/RefreshingGraph' import buildQueries from 'utils/buildQueriesForGraphs' import VisualizationName from 'src/dashboards/components/VisualizationName' -import {stringifyColorValues} from 'src/shared/constants/colorOperations' +import {getCellTypeColors} from 'src/dashboards/constants/cellEditor' const DashVisualization = ( { @@ -27,25 +27,12 @@ const DashVisualization = ( }, {source: {links: {proxy}}} ) => { - let colors = [] - switch (type) { - case 'gauge': { - colors = stringifyColorValues(gaugeColors) - break - } - case 'single-stat': - case 'line-plus-single-stat': - case 'table': { - colors = stringifyColorValues(thresholdsListColors) - break - } - case 'bar': - case 'line': - case 'line-stacked': - case 'line-stepplot': { - colors = stringifyColorValues(lineColors) - } - } + const colors = getCellTypeColors({ + cellType: type, + gaugeColors, + thresholdsListColors, + lineColors, + }) return (
diff --git a/ui/src/dashboards/constants/cellEditor.js b/ui/src/dashboards/constants/cellEditor.js index f22f51f935..7ce2754c11 100644 --- a/ui/src/dashboards/constants/cellEditor.js +++ b/ui/src/dashboards/constants/cellEditor.js @@ -1,4 +1,5 @@ import {DEFAULT_TABLE_OPTIONS} from 'src/shared/constants/tableGraph' +import {stringifyColorValues} from 'src/shared/constants/colorOperations' export const initializeOptions = cellType => { switch (cellType) { @@ -18,3 +19,33 @@ export const AXES_SCALE_OPTIONS = { export const TOOLTIP_Y_VALUE_FORMAT = '

K/M/B = Thousand / Million / Billion
K/M/G = Kilo / Mega / Giga

' + +export const getCellTypeColors = ({ + cellType, + gaugeColors, + thresholdsListColors, + lineColors, +}) => { + let colors = [] + + switch (cellType) { + case 'gauge': { + colors = stringifyColorValues(gaugeColors) + break + } + case 'single-stat': + case 'line-plus-single-stat': + case 'table': { + colors = stringifyColorValues(thresholdsListColors) + break + } + case 'bar': + case 'line': + case 'line-stacked': + case 'line-stepplot': { + colors = stringifyColorValues(lineColors) + } + } + + return colors +} From 5624ddc4312bae808e9ea24ccc517b994b53ad77 Mon Sep 17 00:00:00 2001 From: Alex P Date: Mon, 2 Apr 2018 11:27:35 -0700 Subject: [PATCH 24/39] Introduce and implement colors schema Had to address some errors that arose here and there from previous inconsistencies with the schema --- .../components/CellEditorOverlay.js | 7 +-- ui/src/dashboards/components/GaugeOptions.js | 13 ++---- ui/src/dashboards/components/Visualization.js | 7 +-- ui/src/dashboards/containers/DashboardPage.js | 7 +-- ui/src/data_explorer/components/VisView.js | 2 + ui/src/kapacitor/components/RuleGraph.js | 2 +- ui/src/shared/components/ColorDropdown.js | 2 +- ui/src/shared/components/Dygraph.js | 12 ++--- ui/src/shared/components/Gauge.js | 14 ++---- ui/src/shared/components/GaugeChart.js | 12 ++--- ui/src/shared/components/Layout.js | 12 ++--- ui/src/shared/components/LineGraph.js | 12 ++--- .../components/LineGraphColorSelector.js | 12 ++--- ui/src/shared/components/RefreshingGraph.js | 12 ++--- ui/src/shared/components/SingleStat.js | 11 +---- ui/src/shared/components/TableGraph.js | 11 +---- ui/src/shared/components/ThresholdsList.js | 13 ++---- ui/src/shared/constants/graphColorPalettes.js | 44 +++++++++---------- ui/src/shared/schemas.js | 22 +++++++++- ui/src/status/fixtures.js | 3 ++ 20 files changed, 94 insertions(+), 136 deletions(-) diff --git a/ui/src/dashboards/components/CellEditorOverlay.js b/ui/src/dashboards/components/CellEditorOverlay.js index 7df14d5ae9..8aa3b4fb8c 100644 --- a/ui/src/dashboards/components/CellEditorOverlay.js +++ b/ui/src/dashboards/components/CellEditorOverlay.js @@ -25,6 +25,7 @@ import {OVERLAY_TECHNOLOGY} from 'src/shared/constants/classNames' import {MINIMUM_HEIGHTS, INITIAL_HEIGHTS} from 'src/data_explorer/constants' import {AUTO_GROUP_BY} from 'src/shared/constants' import {getCellTypeColors} from 'src/dashboards/constants/cellEditor' +import {colorsStringSchema, colorsNumberSchema} from 'shared/schemas' class CellEditorOverlay extends Component { constructor(props) { @@ -382,9 +383,9 @@ CellEditorOverlay.propTypes = { dashboardID: string.isRequired, sources: arrayOf(shape()), thresholdsListType: string.isRequired, - thresholdsListColors: arrayOf(shape({}).isRequired).isRequired, - gaugeColors: arrayOf(shape({}).isRequired).isRequired, - lineColors: arrayOf(shape({}).isRequired).isRequired, + thresholdsListColors: colorsNumberSchema.isRequired, + gaugeColors: colorsNumberSchema.isRequired, + lineColors: colorsStringSchema.isRequired, } CEOBottom.propTypes = { diff --git a/ui/src/dashboards/components/GaugeOptions.js b/ui/src/dashboards/components/GaugeOptions.js index 3197464465..a4b2d4abe0 100644 --- a/ui/src/dashboards/components/GaugeOptions.js +++ b/ui/src/dashboards/components/GaugeOptions.js @@ -20,6 +20,7 @@ import { updateGaugeColors, updateAxes, } from 'src/dashboards/actions/cellEditorOverlay' +import {colorsNumberSchema} from 'shared/schemas' class GaugeOptions extends Component { handleAddThreshold = () => { @@ -219,18 +220,10 @@ class GaugeOptions extends Component { } } -const {arrayOf, func, number, shape, string} = PropTypes +const {func, shape} = PropTypes GaugeOptions.propTypes = { - gaugeColors: arrayOf( - shape({ - type: string.isRequired, - hex: string.isRequired, - id: string.isRequired, - name: string.isRequired, - value: number.isRequired, - }).isRequired - ), + gaugeColors: colorsNumberSchema, handleUpdateGaugeColors: func.isRequired, handleUpdateAxes: func.isRequired, axes: shape({}).isRequired, diff --git a/ui/src/dashboards/components/Visualization.js b/ui/src/dashboards/components/Visualization.js index 1ac3d5d196..5fe725856f 100644 --- a/ui/src/dashboards/components/Visualization.js +++ b/ui/src/dashboards/components/Visualization.js @@ -7,6 +7,7 @@ import buildQueries from 'utils/buildQueriesForGraphs' import VisualizationName from 'src/dashboards/components/VisualizationName' import {getCellTypeColors} from 'src/dashboards/constants/cellEditor' +import {colorsStringSchema, colorsNumberSchema} from 'shared/schemas' const DashVisualization = ( { @@ -75,9 +76,9 @@ DashVisualization.propTypes = { }), tableOptions: shape({}), resizerTopHeight: number, - thresholdsListColors: arrayOf(shape({}).isRequired), - gaugeColors: arrayOf(shape({}).isRequired), - lineColors: arrayOf(shape({}).isRequired), + thresholdsListColors: colorsNumberSchema, + gaugeColors: colorsNumberSchema, + lineColors: colorsStringSchema, staticLegend: bool, setDataLabels: func, } diff --git a/ui/src/dashboards/containers/DashboardPage.js b/ui/src/dashboards/containers/DashboardPage.js index 41154f8da6..45091183af 100644 --- a/ui/src/dashboards/containers/DashboardPage.js +++ b/ui/src/dashboards/containers/DashboardPage.js @@ -37,6 +37,7 @@ import { import {presentationButtonDispatcher} from 'shared/dispatchers' import {DASHBOARD_LAYOUT_ROW_HEIGHT} from 'shared/constants' import {notifyDashboardNotFound} from 'shared/copy/notifications' +import {colorsStringSchema, colorsNumberSchema} from 'shared/schemas' const FORMAT_INFLUXQL = 'influxql' const defaultTimeRange = { @@ -532,9 +533,9 @@ DashboardPage.propTypes = { handleDismissEditingAnnotation: func.isRequired, selectedCell: shape({}), thresholdsListType: string.isRequired, - thresholdsListColors: arrayOf(shape({}).isRequired).isRequired, - gaugeColors: arrayOf(shape({}).isRequired).isRequired, - lineColors: arrayOf(shape({}).isRequired).isRequired, + thresholdsListColors: colorsNumberSchema.isRequired, + gaugeColors: colorsNumberSchema.isRequired, + lineColors: colorsStringSchema.isRequired, } const mapStateToProps = (state, {params: {dashboardID}}) => { diff --git a/ui/src/data_explorer/components/VisView.js b/ui/src/data_explorer/components/VisView.js index 2f71af1ad0..b9359d8584 100644 --- a/ui/src/data_explorer/components/VisView.js +++ b/ui/src/data_explorer/components/VisView.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types' import Table from './Table' import RefreshingGraph from 'shared/components/RefreshingGraph' +import {DEFAULT_LINE_COLORS} from 'src/shared/constants/graphColorPalettes' const VisView = ({ axes, @@ -37,6 +38,7 @@ const VisView = ({ return (
diff --git a/ui/src/shared/components/ColorDropdown.js b/ui/src/shared/components/ColorDropdown.js index d5d4d0a1d8..ddfd5da298 100644 --- a/ui/src/shared/components/ColorDropdown.js +++ b/ui/src/shared/components/ColorDropdown.js @@ -99,7 +99,7 @@ ColorDropdown.propTypes = { shape({ hex: string.isRequired, name: string.isRequired, - }) + }).isRequired ).isRequired, stretchToFit: bool, disabled: bool, diff --git a/ui/src/shared/components/Dygraph.js b/ui/src/shared/components/Dygraph.js index 5b975170be..4ab51dfe1b 100644 --- a/ui/src/shared/components/Dygraph.js +++ b/ui/src/shared/components/Dygraph.js @@ -32,6 +32,8 @@ import { } from 'src/shared/constants/graphColorPalettes' const {LINEAR, LOG, BASE_10, BASE_2} = AXES_SCALE_OPTIONS +import {colorsStringSchema} from 'shared/schemas' + class Dygraph extends Component { constructor(props) { super(props) @@ -458,15 +460,7 @@ Dygraph.propTypes = { onZoom: func, mode: string, children: node, - colors: arrayOf( - shape({ - type: string.isRequired, - hex: string.isRequired, - id: string.isRequired, - name: string.isRequired, - value: string.isRequired, - }).isRequired - ), + colors: colorsStringSchema.isRequired, } const mapStateToProps = ({annotations: {mode}}) => ({ diff --git a/ui/src/shared/components/Gauge.js b/ui/src/shared/components/Gauge.js index 52ea1614eb..4d1e3b5692 100644 --- a/ui/src/shared/components/Gauge.js +++ b/ui/src/shared/components/Gauge.js @@ -10,6 +10,8 @@ import { MIN_THRESHOLDS, } from 'shared/constants/thresholds' +import {colorsStringSchema} from 'shared/schemas' + class Gauge extends Component { constructor(props) { super(props) @@ -325,21 +327,13 @@ class Gauge extends Component { } } -const {arrayOf, number, shape, string} = PropTypes +const {number, string} = PropTypes Gauge.propTypes = { width: string.isRequired, height: string.isRequired, gaugePosition: number.isRequired, - colors: arrayOf( - shape({ - type: string.isRequired, - hex: string.isRequired, - id: string.isRequired, - name: string.isRequired, - value: string.isRequired, - }).isRequired - ).isRequired, + colors: colorsStringSchema.isRequired, prefix: string.isRequired, suffix: string.isRequired, } diff --git a/ui/src/shared/components/GaugeChart.js b/ui/src/shared/components/GaugeChart.js index 0516d9c11d..cad6d44280 100644 --- a/ui/src/shared/components/GaugeChart.js +++ b/ui/src/shared/components/GaugeChart.js @@ -7,6 +7,8 @@ import {DEFAULT_GAUGE_COLORS} from 'src/shared/constants/thresholds' import {stringifyColorValues} from 'src/shared/constants/colorOperations' import {DASHBOARD_LAYOUT_ROW_HEIGHT} from 'src/shared/constants' +import {colorsStringSchema} from 'shared/schemas' + class GaugeChart extends PureComponent { render() { const { @@ -82,15 +84,7 @@ GaugeChart.propTypes = { cellHeight: number, resizerTopHeight: number, resizeCoords: shape(), - colors: arrayOf( - shape({ - type: string.isRequired, - hex: string.isRequired, - id: string.isRequired, - name: string.isRequired, - value: string.isRequired, - }).isRequired - ), + colors: colorsStringSchema, prefix: string.isRequired, suffix: string.isRequired, } diff --git a/ui/src/shared/components/Layout.js b/ui/src/shared/components/Layout.js index 18ade5ada1..654593492a 100644 --- a/ui/src/shared/components/Layout.js +++ b/ui/src/shared/components/Layout.js @@ -8,6 +8,8 @@ import {IS_STATIC_LEGEND} from 'src/shared/constants' import _ from 'lodash' +import {colorsStringSchema} from 'shared/schemas' + const getSource = (cell, source, sources, defaultSource) => { const s = _.get(cell, ['queries', '0', 'source'], null) if (!s) { @@ -134,15 +136,7 @@ const propTypes = { i: string.isRequired, name: string.isRequired, type: string.isRequired, - colors: arrayOf( - shape({ - type: string.isRequired, - hex: string.isRequired, - id: string.isRequired, - name: string.isRequired, - value: string.isRequired, - }).isRequired - ), + colors: colorsStringSchema, }).isRequired, templates: arrayOf(shape()), host: string, diff --git a/ui/src/shared/components/LineGraph.js b/ui/src/shared/components/LineGraph.js index 87dab79455..c4178c8f7d 100644 --- a/ui/src/shared/components/LineGraph.js +++ b/ui/src/shared/components/LineGraph.js @@ -6,6 +6,8 @@ import shallowCompare from 'react-addons-shallow-compare' import SingleStat from 'src/shared/components/SingleStat' import timeSeriesToDygraph from 'utils/timeSeriesToDygraph' +import {colorsStringSchema} from 'shared/schemas' + class LineGraph extends Component { constructor(props) { super(props) @@ -196,15 +198,7 @@ LineGraph.propTypes = { resizeCoords: shape(), queries: arrayOf(shape({}).isRequired).isRequired, data: arrayOf(shape({}).isRequired).isRequired, - colors: arrayOf( - shape({ - type: string.isRequired, - hex: string.isRequired, - id: string.isRequired, - name: string.isRequired, - value: string.isRequired, - }).isRequired - ), + colors: colorsStringSchema, } export default LineGraph diff --git a/ui/src/shared/components/LineGraphColorSelector.js b/ui/src/shared/components/LineGraphColorSelector.js index 1b197c0987..50ca3c838d 100644 --- a/ui/src/shared/components/LineGraphColorSelector.js +++ b/ui/src/shared/components/LineGraphColorSelector.js @@ -6,6 +6,7 @@ import {bindActionCreators} from 'redux' import ColorScaleDropdown from 'shared/components/ColorScaleDropdown' import {updateLineColors} from 'src/dashboards/actions/cellEditorOverlay' +import {colorsStringSchema} from 'shared/schemas' class LineGraphColorSelector extends Component { handleSelectColors = colorScale => { @@ -31,17 +32,10 @@ class LineGraphColorSelector extends Component { } } -const {arrayOf, func, shape, string} = PropTypes +const {func} = PropTypes LineGraphColorSelector.propTypes = { - lineColors: arrayOf( - shape({ - type: string.isRequired, - hex: string.isRequired, - id: string.isRequired, - name: string.isRequired, - }).isRequired - ).isRequired, + lineColors: colorsStringSchema.isRequired, handleUpdateLineColors: func.isRequired, } diff --git a/ui/src/shared/components/RefreshingGraph.js b/ui/src/shared/components/RefreshingGraph.js index 3468329eea..c3597b618d 100644 --- a/ui/src/shared/components/RefreshingGraph.js +++ b/ui/src/shared/components/RefreshingGraph.js @@ -9,6 +9,8 @@ import SingleStat from 'shared/components/SingleStat' import GaugeChart from 'shared/components/GaugeChart' import TableGraph from 'shared/components/TableGraph' +import {colorsStringSchema} from 'shared/schemas' + const RefreshingLineGraph = AutoRefresh(LineGraph) const RefreshingSingleStat = AutoRefresh(SingleStat) const RefreshingGaugeChart = AutoRefresh(GaugeChart) @@ -154,15 +156,7 @@ RefreshingGraph.propTypes = { onZoom: func, resizeCoords: shape(), grabDataForDownload: func, - colors: arrayOf( - shape({ - type: string.isRequired, - hex: string.isRequired, - id: string.isRequired, - name: string.isRequired, - value: string.isRequired, - }).isRequired - ), + colors: colorsStringSchema, cellID: string, inView: bool, tableOptions: shape({}), diff --git a/ui/src/shared/components/SingleStat.js b/ui/src/shared/components/SingleStat.js index dc91e872db..99e17e12ef 100644 --- a/ui/src/shared/components/SingleStat.js +++ b/ui/src/shared/components/SingleStat.js @@ -6,6 +6,7 @@ import lastValues from 'shared/parsing/lastValues' import {SMALL_CELL_HEIGHT} from 'shared/graphs/helpers' import {DYGRAPH_CONTAINER_V_MARGIN} from 'shared/constants' import {generateThresholdsListHexs} from 'shared/constants/colorOperations' +import {colorsStringSchema} from 'shared/schemas' class SingleStat extends PureComponent { render() { @@ -78,15 +79,7 @@ SingleStat.propTypes = { data: arrayOf(shape()).isRequired, isFetchingInitially: bool, cellHeight: number, - colors: arrayOf( - shape({ - type: string.isRequired, - hex: string.isRequired, - id: string.isRequired, - name: string.isRequired, - value: string.isRequired, - }).isRequired - ), + colors: colorsStringSchema, prefix: string, suffix: string, lineGraph: bool, diff --git a/ui/src/shared/components/TableGraph.js b/ui/src/shared/components/TableGraph.js index f2b8d98c9c..5bf928aab0 100644 --- a/ui/src/shared/components/TableGraph.js +++ b/ui/src/shared/components/TableGraph.js @@ -22,6 +22,7 @@ import { export const DEFAULT_SORT = ASCENDING import {generateThresholdsListHexs} from 'shared/constants/colorOperations' +import {colorsStringSchema} from 'shared/schemas' export const filterInvisibleColumns = (data, fieldNames) => { const visibility = {} @@ -451,15 +452,7 @@ TableGraph.propTypes = { }), hoverTime: string, onSetHoverTime: func, - colors: arrayOf( - shape({ - type: string.isRequired, - hex: string.isRequired, - id: string.isRequired, - name: string.isRequired, - value: string.isRequired, - }).isRequired - ), + colors: colorsStringSchema, setDataLabels: func, } diff --git a/ui/src/shared/components/ThresholdsList.js b/ui/src/shared/components/ThresholdsList.js index 42ba1f9821..669e23fd07 100644 --- a/ui/src/shared/components/ThresholdsList.js +++ b/ui/src/shared/components/ThresholdsList.js @@ -10,6 +10,7 @@ import Threshold from 'src/dashboards/components/Threshold' import ColorDropdown from 'shared/components/ColorDropdown' import {updateThresholdsListColors} from 'src/dashboards/actions/cellEditorOverlay' +import {colorsNumberSchema} from 'shared/schemas' import { THRESHOLD_COLORS, @@ -166,22 +167,14 @@ class ThresholdsList extends Component { ) } } -const {arrayOf, bool, func, number, shape, string} = PropTypes +const {bool, func, string} = PropTypes ThresholdsList.defaultProps = { showListHeading: false, } ThresholdsList.propTypes = { thresholdsListType: string.isRequired, - thresholdsListColors: arrayOf( - shape({ - type: string.isRequired, - hex: string.isRequired, - id: string.isRequired, - name: string.isRequired, - value: number.isRequired, - }).isRequired - ), + thresholdsListColors: colorsNumberSchema.isRequired, handleUpdateThresholdsListColors: func.isRequired, onResetFocus: func.isRequired, showListHeading: bool, diff --git a/ui/src/shared/constants/graphColorPalettes.js b/ui/src/shared/constants/graphColorPalettes.js index 079f45c023..3b3768b4cc 100644 --- a/ui/src/shared/constants/graphColorPalettes.js +++ b/ui/src/shared/constants/graphColorPalettes.js @@ -9,21 +9,21 @@ export const LINE_COLORS_A = [ hex: '#31C0F6', id: '0', name: 'Nineteen Eighty Four', - value: 0, + value: '0', }, { type: COLOR_TYPE_SCALE, hex: '#A500A5', id: '0', name: 'Nineteen Eighty Four', - value: 0, + value: '0', }, { type: COLOR_TYPE_SCALE, hex: '#FF7E27', id: '0', name: 'Nineteen Eighty Four', - value: 0, + value: '0', }, ] @@ -33,21 +33,21 @@ export const LINE_COLORS_B = [ hex: '#74D495', id: '1', name: 'Atlantis', - value: 0, + value: '0', }, { type: COLOR_TYPE_SCALE, hex: '#3F3FBA', id: '1', name: 'Atlantis', - value: 0, + value: '0', }, { type: COLOR_TYPE_SCALE, hex: '#FF4D9E', id: '1', name: 'Atlantis', - value: 0, + value: '0', }, ] @@ -57,21 +57,21 @@ export const LINE_COLORS_C = [ hex: '#8F8AF4', id: '1', name: 'Do Androids Dream of Electric Sheep?', - value: 0, + value: '0', }, { type: COLOR_TYPE_SCALE, hex: '#A51414', id: '1', name: 'Do Androids Dream of Electric Sheep?', - value: 0, + value: '0', }, { type: COLOR_TYPE_SCALE, hex: '#F4CF31', id: '1', name: 'Do Androids Dream of Electric Sheep?', - value: 0, + value: '0', }, ] @@ -81,21 +81,21 @@ export const LINE_COLORS_D = [ hex: '#FD7A5D', id: '1', name: 'Delorean', - value: 0, + value: '0', }, { type: COLOR_TYPE_SCALE, hex: '#5F1CF2', id: '1', name: 'Delorean', - value: 0, + value: '0', }, { type: COLOR_TYPE_SCALE, hex: '#4CE09A', id: '1', name: 'Delorean', - value: 0, + value: '0', }, ] @@ -105,21 +105,21 @@ export const LINE_COLORS_E = [ hex: '#FDC44F', id: '1', name: 'Cthulhu', - value: 0, + value: '0', }, { type: COLOR_TYPE_SCALE, hex: '#007C76', id: '1', name: 'Cthulhu', - value: 0, + value: '0', }, { type: COLOR_TYPE_SCALE, hex: '#8983FF', id: '1', name: 'Cthulhu', - value: 0, + value: '0', }, ] @@ -129,21 +129,21 @@ export const LINE_COLORS_F = [ hex: '#DA6FF1', id: '1', name: 'Ectoplasm', - value: 0, + value: '0', }, { type: COLOR_TYPE_SCALE, hex: '#00717A', id: '1', name: 'Ectoplasm', - value: 0, + value: '0', }, { type: COLOR_TYPE_SCALE, hex: '#ACFF76', id: '1', name: 'Ectoplasm', - value: 0, + value: '0', }, ] @@ -153,21 +153,21 @@ export const LINE_COLORS_G = [ hex: '#F6F6F8', id: '1', name: 'T-Max 400 Film', - value: 0, + value: '0', }, { type: COLOR_TYPE_SCALE, hex: '#A4A8B6', id: '1', name: 'T-Max 400 Film', - value: 0, + value: '0', }, { type: COLOR_TYPE_SCALE, hex: '#545667', id: '1', name: 'T-Max 400 Film', - value: 0, + value: '0', }, ] @@ -177,7 +177,7 @@ export const LINE_COLORS_RULE_GRAPH = [ hex: '#4ED8A0', id: '1', name: 'Rainforest', - value: 0, + value: '0', }, ] diff --git a/ui/src/shared/schemas.js b/ui/src/shared/schemas.js index 35df59a72b..5e16535433 100644 --- a/ui/src/shared/schemas.js +++ b/ui/src/shared/schemas.js @@ -1,6 +1,6 @@ import PropTypes from 'prop-types' -const {shape, string} = PropTypes +const {arrayOf, number, shape, string} = PropTypes export const annotation = shape({ id: string.isRequired, @@ -9,3 +9,23 @@ export const annotation = shape({ text: string.isRequired, type: string.isRequired, }) + +export const colorsStringSchema = arrayOf( + shape({ + type: string.isRequired, + hex: string.isRequired, + id: string.isRequired, + name: string.isRequired, + value: string.isRequired, + }).isRequired +) + +export const colorsNumberSchema = arrayOf( + shape({ + type: string.isRequired, + hex: string.isRequired, + id: string.isRequired, + name: string.isRequired, + value: number.isRequired, + }).isRequired +) diff --git a/ui/src/status/fixtures.js b/ui/src/status/fixtures.js index d366801897..3e96f036f0 100644 --- a/ui/src/status/fixtures.js +++ b/ui/src/status/fixtures.js @@ -1,3 +1,5 @@ +import {DEFAULT_LINE_COLORS} from 'src/shared/constants/graphColorPalettes' + export const fixtureStatusPageCells = [ { i: 'alerts-bar-graph', @@ -8,6 +10,7 @@ export const fixtureStatusPageCells = [ h: 4, legend: {}, name: 'Alert Events per Day – Last 30 Days', + colors: DEFAULT_LINE_COLORS, queries: [ { query: From a6d11a0e12687809c4a9884f5c4fda8ff09ff765 Mon Sep 17 00:00:00 2001 From: Brandon Farmer Date: Mon, 2 Apr 2018 11:28:32 -0700 Subject: [PATCH 25/39] Fixes template variable editing not allowing saving - Dropdown and TemplateQueryBuilder components require that a function is passed to them, where as TableInput requires that a function builder is passed to them for starting editing --- ui/src/dashboards/components/template_variables/Row.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/src/dashboards/components/template_variables/Row.js b/ui/src/dashboards/components/template_variables/Row.js index 4242f0075c..3be354f73e 100644 --- a/ui/src/dashboards/components/template_variables/Row.js +++ b/ui/src/dashboards/components/template_variables/Row.js @@ -70,7 +70,7 @@ const TemplateVariableRow = ({ t.type === selectedType).text} className="dropdown-140" /> @@ -84,7 +84,7 @@ const TemplateVariableRow = ({ selectedMeasurement={selectedMeasurement} selectedTagKey={selectedTagKey} onSelectTagKey={onSelectTagKey} - onStartEdit={onStartEdit} + onStartEdit={onStartEdit('tempVar')} onErrorThrown={onErrorThrown} /> Date: Mon, 2 Apr 2018 14:35:30 -0700 Subject: [PATCH 26/39] Surround temp var query params with quotes --- ui/src/dashboards/utils/templateVariableQueryGenerator.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/src/dashboards/utils/templateVariableQueryGenerator.js b/ui/src/dashboards/utils/templateVariableQueryGenerator.js index 163b72102c..d15a43be7d 100644 --- a/ui/src/dashboards/utils/templateVariableQueryGenerator.js +++ b/ui/src/dashboards/utils/templateVariableQueryGenerator.js @@ -55,8 +55,8 @@ const generateTemplateVariableQuery = ({ export const makeQueryForTemplate = ({influxql, db, measurement, tagKey}) => influxql - .replace(':database:', db) - .replace(':measurement:', measurement) - .replace(':tagKey:', tagKey) + .replace(':database:', `"${db}"`) + .replace(':measurement:', `"${measurement}"`) + .replace(':tagKey:', `"${tagKey}"`) export default generateTemplateVariableQuery From 42aa891a4ca8bbf1002edcf62a8715dead2260ba Mon Sep 17 00:00:00 2001 From: Andrew Watkins Date: Mon, 2 Apr 2018 15:19:23 -0700 Subject: [PATCH 27/39] Update styles to fix text overflow --- ui/src/style/pages/admin.scss | 55 +++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/ui/src/style/pages/admin.scss b/ui/src/style/pages/admin.scss index ab3e7d56ab..1731246c4f 100644 --- a/ui/src/style/pages/admin.scss +++ b/ui/src/style/pages/admin.scss @@ -16,9 +16,7 @@ .tab { font-weight: 500 !important; border-radius: $radius $radius 0 0 !important; - transition: - background-color 0.25s ease, - color 0.25s ease !important; + transition: background-color 0.25s ease, color 0.25s ease !important; border: 0 !important; text-align: left; height: 60px !important; @@ -41,16 +39,24 @@ } } .admin-tabs--content { - .panel {border-top-left-radius: 0;} - .panel-heading {height: 60px;} + .panel { + border-top-left-radius: 0; + } + .panel-heading { + height: 60px; + } .panel-title { font-size: 17px; font-weight: 400 !important; color: $g12-forge; padding: 6px 0; } - .panel-body {min-height: 300px;} - .panel-heading + .panel-body {padding-top: 0;} + .panel-body { + min-height: 300px; + } + .panel-heading + .panel-body { + padding-top: 0; + } } /* @@ -69,7 +75,9 @@ border-radius: $radius 0 0 $radius !important; padding: 0 0 0 16px !important; } - & + div {padding-left: 0;} + & + div { + padding-left: 0; + } } } @@ -82,8 +90,13 @@ font-weight: 600; color: $g14-chromium; transition: none !important; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; - .caret {opacity: 0;} + .caret { + opacity: 0; + } } .admin-table--multi-select-empty .dropdown-toggle { color: $g8-storm; @@ -92,7 +105,9 @@ color: $g20-white !important; background-color: $c-pool; - .caret {opacity: 1;} + .caret { + opacity: 1; + } &:hover { transition: background-color 0.25s ease; @@ -100,7 +115,9 @@ } } table > tbody > tr > td.admin-table--left-offset, -table > thead > tr > th.admin-table--left-offset {padding-left: 15px;} +table > thead > tr > th.admin-table--left-offset { + padding-left: 15px; +} table > tbody > tr.admin-table--edit-row, table > tbody > tr.admin-table--edit-row:hover, @@ -141,9 +158,15 @@ pre.admin-table--query { .db-manager { margin-bottom: 8px; - &:last-child {margin-bottom: 0;} - .db-manager-header--actions {visibility: hidden;} - &:hover .db-manager-header--actions {visibility: visible;} + &:last-child { + margin-bottom: 0; + } + .db-manager-header--actions { + visibility: hidden; + } + &:hover .db-manager-header--actions { + visibility: visible; + } } .db-manager-header { padding: 0 11px; @@ -182,7 +205,9 @@ pre.admin-table--query { padding: 9px 11px; border-radius: 0 0 $radius-small $radius-small; - .table-highlight > tbody > tr:hover {background-color: $g5-pepper;} + .table-highlight > tbody > tr:hover { + background-color: $g5-pepper; + } } /* From f3dbc69b2e33ec4435957dc39b84d9894021a653 Mon Sep 17 00:00:00 2001 From: Andrew Watkins Date: Mon, 2 Apr 2018 15:20:15 -0700 Subject: [PATCH 28/39] Convert and refactor UserRow to TypeScript --- .../components/UserPermissionsDropdown.tsx | 67 +++++++ ui/src/admin/components/UserRow.js | 169 ------------------ ui/src/admin/components/UserRow.tsx | 131 ++++++++++++++ ui/src/admin/components/UserRowEdit.tsx | 47 +++++ ui/src/types/influxAdmin.ts | 14 ++ 5 files changed, 259 insertions(+), 169 deletions(-) create mode 100644 ui/src/admin/components/UserPermissionsDropdown.tsx delete mode 100644 ui/src/admin/components/UserRow.js create mode 100644 ui/src/admin/components/UserRow.tsx create mode 100644 ui/src/admin/components/UserRowEdit.tsx create mode 100644 ui/src/types/influxAdmin.ts diff --git a/ui/src/admin/components/UserPermissionsDropdown.tsx b/ui/src/admin/components/UserPermissionsDropdown.tsx new file mode 100644 index 0000000000..4548beeefb --- /dev/null +++ b/ui/src/admin/components/UserPermissionsDropdown.tsx @@ -0,0 +1,67 @@ +import React, {PureComponent} from 'react' +import classnames from 'classnames' +import _ from 'lodash' + +import MultiSelectDropdown from 'src/shared/components/MultiSelectDropdown' +import {USERS_TABLE} from 'src/admin/constants/tableSizing' +import {User} from 'src/types/influxAdmin' + +interface Props { + user: User + allPermissions: string[] + onUpdatePermissions: (user: User, permissions: any[]) => void +} + +class UserPermissionsDropdown extends PureComponent { + constructor(props) { + super(props) + } + + public render() { + return ( + + ) + } + + private handleUpdatePermissions = (permissions): void => { + const {onUpdatePermissions, user} = this.props + const allowed = permissions.map(p => p.name) + onUpdatePermissions(user, [{scope: 'all', allowed}]) + } + + private get allPermissions() { + return this.props.allPermissions.map(p => ({name: p})) + } + + private get userPermissions() { + return _.get(this.props.user, ['permissions', '0', 'allowed'], []) + } + + private get selectedPermissions() { + return this.userPermissions.map(p => ({name: p})) + } + + private get permissionsLabel() { + const {user} = this.props + return user.permissions && user.permissions.length + ? '' + : 'Select Permissions' + } + + private get permissionsClass() { + return classnames(`dropdown-${USERS_TABLE.colPermissions}`, { + 'admin-table--multi-select-empty': !this.props.user.permissions.length, + }) + } +} + +export default UserPermissionsDropdown diff --git a/ui/src/admin/components/UserRow.js b/ui/src/admin/components/UserRow.js deleted file mode 100644 index fa6a744cc3..0000000000 --- a/ui/src/admin/components/UserRow.js +++ /dev/null @@ -1,169 +0,0 @@ -import React from 'react' -import PropTypes from 'prop-types' - -import _ from 'lodash' -import classnames from 'classnames' - -import UserEditName from 'src/admin/components/UserEditName' -import UserNewPassword from 'src/admin/components/UserNewPassword' -import MultiSelectDropdown from 'shared/components/MultiSelectDropdown' -import ConfirmOrCancel from 'shared/components/ConfirmOrCancel' -import ConfirmButton from 'shared/components/ConfirmButton' -import ChangePassRow from 'src/admin/components/ChangePassRow' -import {USERS_TABLE} from 'src/admin/constants/tableSizing' - -const UserRow = ({ - user: {name, roles = [], permissions, password}, - user, - allRoles, - allPermissions, - hasRoles, - isNew, - isEditing, - onEdit, - onSave, - onCancel, - onDelete, - onUpdatePermissions, - onUpdateRoles, - onUpdatePassword, -}) => { - function handleUpdatePermissions(perms) { - const allowed = perms.map(p => p.name) - onUpdatePermissions(user, [{scope: 'all', allowed}]) - } - - function handleUpdateRoles(roleNames) { - onUpdateRoles( - user, - allRoles.filter(r => roleNames.find(rn => rn.name === r.name)) - ) - } - - function handleUpdatePassword() { - onUpdatePassword(user, password) - } - - const perms = _.get(permissions, ['0', 'allowed'], []) - - const wrappedDelete = () => { - onDelete(user) - } - - if (isEditing) { - return ( - - - - {hasRoles ? -- : null} - -- - - - - - ) - } - - return ( - - {name} - - - - {hasRoles ? ( - - ({name: r.name}))} - label={roles.length ? '' : 'Select Roles'} - onApply={handleUpdateRoles} - buttonSize="btn-xs" - buttonColor="btn-primary" - customClass={classnames(`dropdown-${USERS_TABLE.colRoles}`, { - 'admin-table--multi-select-empty': !roles.length, - })} - resetStateOnReceiveProps={false} - /> - - ) : null} - - {allPermissions && allPermissions.length ? ( - ({name: p}))} - selectedItems={perms.map(p => ({name: p}))} - label={ - permissions && permissions.length ? '' : 'Select Permissions' - } - onApply={handleUpdatePermissions} - buttonSize="btn-xs" - buttonColor="btn-primary" - customClass={classnames(`dropdown-${USERS_TABLE.colPermissions}`, { - 'admin-table--multi-select-empty': !permissions.length, - })} - resetStateOnReceiveProps={false} - /> - ) : null} - - - - - - ) -} - -const {arrayOf, bool, func, shape, string} = PropTypes - -UserRow.propTypes = { - user: shape({ - name: string, - roles: arrayOf( - shape({ - name: string, - }) - ), - permissions: arrayOf( - shape({ - name: string, - }) - ), - password: string, - }).isRequired, - allRoles: arrayOf(shape()), - allPermissions: arrayOf(string), - hasRoles: bool, - isNew: bool, - isEditing: bool, - onCancel: func, - onEdit: func, - onSave: func, - onDelete: func.isRequired, - onUpdatePermissions: func, - onUpdateRoles: func, - onUpdatePassword: func, -} - -export default UserRow diff --git a/ui/src/admin/components/UserRow.tsx b/ui/src/admin/components/UserRow.tsx new file mode 100644 index 0000000000..75e6d05e27 --- /dev/null +++ b/ui/src/admin/components/UserRow.tsx @@ -0,0 +1,131 @@ +import React, {PureComponent} from 'react' + +import classnames from 'classnames' + +import UserPermissionsDropdown from 'src/admin/components/UserPermissionsDropdown' +import MultiSelectDropdown from 'src/shared/components/MultiSelectDropdown' +import ConfirmButton from 'src/shared/components/ConfirmButton' +import ChangePassRow from 'src/admin/components/ChangePassRow' +import {USERS_TABLE} from 'src/admin/constants/tableSizing' + +import UserRowEdit from 'src/admin/components/UserRowEdit' +import {User} from 'src/types/influxAdmin' + +interface UserRowProps { + user: User + allRoles: any[] + allPermissions: string[] + hasRoles: boolean + isNew: boolean + isEditing: boolean + onCancel: () => void + onEdit: () => void + onSave: () => void + onDelete: (user: User) => void + onUpdatePermissions: (user: User, permissions: any[]) => void + onUpdateRoles: (user: User, roles: any[]) => void + onUpdatePassword: (user: User, password: string) => void +} + +class UserRow extends PureComponent { + public render() { + const { + user: {name, roles = [], password}, + user, + allRoles, + allPermissions, + hasRoles, + isNew, + isEditing, + onEdit, + onSave, + onCancel, + onDelete, + onUpdatePermissions, + onUpdateRoles, + onUpdatePassword, + } = this.props + + function handleUpdateRoles(roleNames): void { + onUpdateRoles( + user, + allRoles.filter(r => roleNames.find(rn => rn.name === r.name)) + ) + } + + function handleUpdatePassword(): void { + onUpdatePassword(user, password) + } + + const wrappedDelete = () => { + onDelete(user) + } + + if (isEditing) { + return ( + + ) + } + + return ( + + {name} + + + + {hasRoles ? ( + + ({name: r.name}))} + label={roles.length ? '' : 'Select Roles'} + onApply={handleUpdateRoles} + buttonSize="btn-xs" + buttonColor="btn-primary" + customClass={classnames(`dropdown-${USERS_TABLE.colRoles}`, { + 'admin-table--multi-select-empty': !roles.length, + })} + resetStateOnReceiveProps={false} + /> + + ) : null} + + {allPermissions && + !!allPermissions.length && ( + + )} + + + + + + ) + } +} + +export default UserRow diff --git a/ui/src/admin/components/UserRowEdit.tsx b/ui/src/admin/components/UserRowEdit.tsx new file mode 100644 index 0000000000..60d8516038 --- /dev/null +++ b/ui/src/admin/components/UserRowEdit.tsx @@ -0,0 +1,47 @@ +import React, {SFC} from 'react' +import UserEditName from 'src/admin/components/UserEditName' +import UserNewPassword from 'src/admin/components/UserNewPassword' +import ConfirmOrCancel from 'src/shared/components/ConfirmOrCancel' +import {USERS_TABLE} from 'src/admin/constants/tableSizing' + +import {User} from 'src/types/influxAdmin' + +interface UserRowEditProps { + user: User + onEdit: () => void + onSave: () => void + onCancel: () => void + isNew: boolean + hasRoles: boolean +} + +const UserRowEdit: SFC = ({ + user, + onEdit, + onSave, + onCancel, + isNew, + hasRoles, +}) => ( + + + + {hasRoles ? -- : null} + -- + + + + +) + +export default UserRowEdit diff --git a/ui/src/types/influxAdmin.ts b/ui/src/types/influxAdmin.ts new file mode 100644 index 0000000000..c6802b9b70 --- /dev/null +++ b/ui/src/types/influxAdmin.ts @@ -0,0 +1,14 @@ +interface UserRole { + name: string +} + +interface UserPermission { + name: string +} + +export interface User { + name: string + roles: UserRole[] + permissions: UserPermission[] + password: string +} From a169c2cec8d8687e86864d780cb8e742d8bf0724 Mon Sep 17 00:00:00 2001 From: Andrew Watkins Date: Mon, 2 Apr 2018 16:09:47 -0700 Subject: [PATCH 29/39] Introduce UserRole dropdown --- .../components/UserPermissionsDropdown.tsx | 5 +- ui/src/admin/components/UserRoleDropdown.tsx | 58 +++++++++++++++++++ ui/src/admin/components/UserRow.tsx | 34 +++-------- 3 files changed, 68 insertions(+), 29 deletions(-) create mode 100644 ui/src/admin/components/UserRoleDropdown.tsx diff --git a/ui/src/admin/components/UserPermissionsDropdown.tsx b/ui/src/admin/components/UserPermissionsDropdown.tsx index 4548beeefb..6d5e69e29d 100644 --- a/ui/src/admin/components/UserPermissionsDropdown.tsx +++ b/ui/src/admin/components/UserPermissionsDropdown.tsx @@ -3,6 +3,7 @@ import classnames from 'classnames' import _ from 'lodash' import MultiSelectDropdown from 'src/shared/components/MultiSelectDropdown' + import {USERS_TABLE} from 'src/admin/constants/tableSizing' import {User} from 'src/types/influxAdmin' @@ -13,10 +14,6 @@ interface Props { } class UserPermissionsDropdown extends PureComponent { - constructor(props) { - super(props) - } - public render() { return ( void +} + +class UserRoleDropdown extends PureComponent { + public render() { + const {allRoles} = this.props + + return ( + + ) + } + + private handleUpdateRoles = (roleNames): void => { + const {user, allRoles, onUpdateRoles} = this.props + const roles = allRoles.filter(r => roleNames.find(rn => rn.name === r.name)) + + onUpdateRoles(user, roles) + } + + private get roles() { + const roles = _.get(this.props.user, 'roles', []) + return roles.map(r => ({name: r.name})) + } + + private get rolesClass() { + return classnames(`dropdown-${USERS_TABLE.colRoles}`, { + 'admin-table--multi-select-empty': !this.roles.length, + }) + } + + private get rolesLabel() { + return this.roles.length ? '' : 'Select Roles' + } +} + +export default UserRoleDropdown diff --git a/ui/src/admin/components/UserRow.tsx b/ui/src/admin/components/UserRow.tsx index 75e6d05e27..2de3f7ecde 100644 --- a/ui/src/admin/components/UserRow.tsx +++ b/ui/src/admin/components/UserRow.tsx @@ -1,11 +1,9 @@ import React, {PureComponent} from 'react' -import classnames from 'classnames' - import UserPermissionsDropdown from 'src/admin/components/UserPermissionsDropdown' -import MultiSelectDropdown from 'src/shared/components/MultiSelectDropdown' -import ConfirmButton from 'src/shared/components/ConfirmButton' +import UserRoleDropdown from 'src/admin/components/UserRoleDropdown' import ChangePassRow from 'src/admin/components/ChangePassRow' +import ConfirmButton from 'src/shared/components/ConfirmButton' import {USERS_TABLE} from 'src/admin/constants/tableSizing' import UserRowEdit from 'src/admin/components/UserRowEdit' @@ -30,7 +28,7 @@ interface UserRowProps { class UserRow extends PureComponent { public render() { const { - user: {name, roles = [], password}, + user: {name, password}, user, allRoles, allPermissions, @@ -46,13 +44,6 @@ class UserRow extends PureComponent { onUpdatePassword, } = this.props - function handleUpdateRoles(roleNames): void { - onUpdateRoles( - user, - allRoles.filter(r => roleNames.find(rn => rn.name === r.name)) - ) - } - function handleUpdatePassword(): void { onUpdatePassword(user, password) } @@ -85,22 +76,15 @@ class UserRow extends PureComponent { buttonSize="btn-xs" /> - {hasRoles ? ( + {hasRoles && ( - ({name: r.name}))} - label={roles.length ? '' : 'Select Roles'} - onApply={handleUpdateRoles} - buttonSize="btn-xs" - buttonColor="btn-primary" - customClass={classnames(`dropdown-${USERS_TABLE.colRoles}`, { - 'admin-table--multi-select-empty': !roles.length, - })} - resetStateOnReceiveProps={false} + - ) : null} + )} {allPermissions && !!allPermissions.length && ( From 9dc35668834be120dd84b5189375fe4f4f1d0127 Mon Sep 17 00:00:00 2001 From: Andrew Watkins Date: Mon, 2 Apr 2018 16:26:25 -0700 Subject: [PATCH 30/39] Update UserRoleDropdown getters --- ui/src/admin/components/UserRoleDropdown.tsx | 14 +++++++------- ui/src/types/influxAdmin.ts | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ui/src/admin/components/UserRoleDropdown.tsx b/ui/src/admin/components/UserRoleDropdown.tsx index f9a8af112c..e287934051 100644 --- a/ui/src/admin/components/UserRoleDropdown.tsx +++ b/ui/src/admin/components/UserRoleDropdown.tsx @@ -6,12 +6,12 @@ import _ from 'lodash' import MultiSelectDropdown from 'src/shared/components/MultiSelectDropdown' import {USERS_TABLE} from 'src/admin/constants/tableSizing' -import {User} from 'src/types/influxAdmin' +import {User, UserRole} from 'src/types/influxAdmin' interface Props { user: User allRoles: any[] - onUpdateRoles: (user: User, roles: any[]) => void + onUpdateRoles: (user: User, roles: UserRole[]) => void } class UserRoleDropdown extends PureComponent { @@ -39,18 +39,18 @@ class UserRoleDropdown extends PureComponent { onUpdateRoles(user, roles) } - private get roles() { - const roles = _.get(this.props.user, 'roles', []) - return roles.map(r => ({name: r.name})) + private get roles(): UserRole[] { + const roles = _.get(this.props.user, 'roles', []) as UserRole[] + return roles.map(({name}) => ({name})) } - private get rolesClass() { + private get rolesClass(): string { return classnames(`dropdown-${USERS_TABLE.colRoles}`, { 'admin-table--multi-select-empty': !this.roles.length, }) } - private get rolesLabel() { + private get rolesLabel(): string { return this.roles.length ? '' : 'Select Roles' } } diff --git a/ui/src/types/influxAdmin.ts b/ui/src/types/influxAdmin.ts index c6802b9b70..a9255be652 100644 --- a/ui/src/types/influxAdmin.ts +++ b/ui/src/types/influxAdmin.ts @@ -1,4 +1,4 @@ -interface UserRole { +export interface UserRole { name: string } From 458a8632fdc1a48d92ef69cfc46f2cf9411e419f Mon Sep 17 00:00:00 2001 From: Alex P Date: Mon, 2 Apr 2018 17:03:10 -0700 Subject: [PATCH 31/39] Redirect to URL of TICKscript after creation --- ui/src/kapacitor/containers/TickscriptPage.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui/src/kapacitor/containers/TickscriptPage.js b/ui/src/kapacitor/containers/TickscriptPage.js index 959f07db48..3b645e838c 100644 --- a/ui/src/kapacitor/containers/TickscriptPage.js +++ b/ui/src/kapacitor/containers/TickscriptPage.js @@ -173,6 +173,7 @@ class TickscriptPage extends Component { response = await updateTask(kapacitor, task, ruleID, router, sourceID) } else { response = await createTask(kapacitor, task, router, sourceID) + router.push(`/sources/${sourceID}/tickscript/${response.id}`) } if (response.code) { this.setState({unsavedChanges: true, consoleMessage: response.message}) @@ -227,6 +228,7 @@ class TickscriptPage extends Component { unsavedChanges, consoleMessage, } = this.state + return ( Date: Mon, 2 Apr 2018 17:03:52 -0700 Subject: [PATCH 32/39] Render task ID instead of name in TICKscript controls This ensures a newly created tickscript does not have a blank space here --- ui/src/kapacitor/components/TickscriptEditorControls.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/kapacitor/components/TickscriptEditorControls.js b/ui/src/kapacitor/components/TickscriptEditorControls.js index f57724c8e0..116757b1b5 100644 --- a/ui/src/kapacitor/components/TickscriptEditorControls.js +++ b/ui/src/kapacitor/components/TickscriptEditorControls.js @@ -19,7 +19,7 @@ const TickscriptEditorControls = ({ {isNewTickscript ? ( ) : ( - + )}
From e78e98eb135da915aadc2d92c762bccff968da77 Mon Sep 17 00:00:00 2001 From: Alex P Date: Mon, 2 Apr 2018 17:08:43 -0700 Subject: [PATCH 33/39] Updoot changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ffbf0efd8..e6c5185eee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,8 +10,10 @@ ### Bug Fixes ## v1.4.3.0 [unreleased] + 1. [#3080](https://github.com/influxdata/chronograf/pull/3080): Add tabular data visualization option with features 1. [#3103](https://github.com/influxdata/chronograf/pull/3103): Add ability to clone dashboards +1. [#3111](https://github.com/influxdata/chronograf/pull/3111): Fix saving of new TICKscripts ### UI Improvements From 5c38d99549cc85504ceb08d63e8f91ae6c650a4c Mon Sep 17 00:00:00 2001 From: Andrew Watkins Date: Mon, 2 Apr 2018 17:09:31 -0700 Subject: [PATCH 34/39] Fix server validation --- server/sources.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/sources.go b/server/sources.go index b6af66ce03..ddb7eac76b 100644 --- a/server/sources.go +++ b/server/sources.go @@ -635,7 +635,7 @@ type sourceUsersResponse struct { } func (r *sourceUserRequest) ValidUpdate() error { - if r.Password == "" && len(r.Permissions) == 0 && len(r.Roles) == 0 { + if r.Password == "" && r.Permissions == nil && r.Roles == nil { return fmt.Errorf("No fields to update") } return validPermissions(&r.Permissions) From 1efa7a257cb9cc9af3bd77fb967731ba6db1e843 Mon Sep 17 00:00:00 2001 From: nathan haugo Date: Mon, 2 Apr 2018 17:50:32 -0700 Subject: [PATCH 35/39] Update for 1.4.3.1 --- .bumpversion.cfg | 2 +- CHANGELOG.md | 9 ++++++--- README.md | 4 ++-- server/swagger.json | 2 +- ui/package.json | 2 +- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index b701ac3ce3..9356f66c84 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 1.4.3.0 +current_version = 1.4.3.1 files = README.md server/swagger.json parse = (?P\d+)\.(?P\d+)\.(?P\d+)\.(?P\d+) serialize = {major}.{minor}.{patch}.{release} diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ffbf0efd8..e2444aa84c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,9 +9,12 @@ ### Bug Fixes -## v1.4.3.0 [unreleased] -1. [#3080](https://github.com/influxdata/chronograf/pull/3080): Add tabular data visualization option with features -1. [#3103](https://github.com/influxdata/chronograf/pull/3103): Add ability to clone dashboards +## v1.4.3.1 [2018-04-02] +### Bug Fixes + +1. [#3107](https://github.com/influxdata/chronograf/pull/3107): Fixes template variable editing not allowing saving +1. [#3094](https://github.com/influxdata/chronograf/pull/3094): Save template variables on first edit +1. [#3101](https://github.com/influxdata/chronograf/pull/3101): Fix template variables not loading all values ### UI Improvements diff --git a/README.md b/README.md index a8c657d5c3..78ea39c33f 100644 --- a/README.md +++ b/README.md @@ -136,7 +136,7 @@ option. ## Versions The most recent version of Chronograf is -[v1.4.3.0](https://www.influxdata.com/downloads/). +[v1.4.3.1](https://www.influxdata.com/downloads/). Spotted a bug or have a feature request? Please open [an issue](https://github.com/influxdata/chronograf/issues/new)! @@ -178,7 +178,7 @@ By default, chronograf runs on port `8888`. To get started right away with Docker, you can pull down our latest release: ```sh -docker pull chronograf:1.4.3.0 +docker pull chronograf:1.4.3.1 ``` ### From Source diff --git a/server/swagger.json b/server/swagger.json index 508ee2be0e..e8208779b0 100644 --- a/server/swagger.json +++ b/server/swagger.json @@ -3,7 +3,7 @@ "info": { "title": "Chronograf", "description": "API endpoints for Chronograf", - "version": "1.4.3.0" + "version": "1.4.3.1" }, "schemes": ["http"], "basePath": "/chronograf/v1", diff --git a/ui/package.json b/ui/package.json index 8835c15619..19a8274f81 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,6 +1,6 @@ { "name": "chronograf-ui", - "version": "1.4.3-0", + "version": "1.4.3-1", "private": false, "license": "AGPL-3.0", "description": "", From 9cf6457fab7679b284824c7460aeb338a805c42c Mon Sep 17 00:00:00 2001 From: nathan haugo Date: Mon, 2 Apr 2018 17:57:24 -0700 Subject: [PATCH 36/39] Move 1.4.3.1 to proper position --- CHANGELOG.md | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2444aa84c..64f2e45ae3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,17 +7,6 @@ ### UI Improvements -### Bug Fixes - -## v1.4.3.1 [2018-04-02] -### Bug Fixes - -1. [#3107](https://github.com/influxdata/chronograf/pull/3107): Fixes template variable editing not allowing saving -1. [#3094](https://github.com/influxdata/chronograf/pull/3094): Save template variables on first edit -1. [#3101](https://github.com/influxdata/chronograf/pull/3101): Fix template variables not loading all values - -### UI Improvements - 1. [#3088](https://github.com/influxdata/chronograf/pull/3088): New dashboard cells appear at bottom of layout and assume the size of the most common cell 1. [#3096](https://github.com/influxdata/chronograf/pull/3096): Standardize delete confirmation interactions 1. [#3096](https://github.com/influxdata/chronograf/pull/3096): Standardize save & cancel interactions @@ -27,6 +16,13 @@ 1. [#2950](https://github.com/influxdata/chronograf/pull/2094): Always save template variables on first edit 1. [#3101](https://github.com/influxdata/chronograf/pull/3101): Fix template variables not loading +## v1.4.3.1 [2018-04-02] +### Bug Fixes + +1. [#3107](https://github.com/influxdata/chronograf/pull/3107): Fixes template variable editing not allowing saving +1. [#3094](https://github.com/influxdata/chronograf/pull/3094): Save template variables on first edit +1. [#3101](https://github.com/influxdata/chronograf/pull/3101): Fix template variables not loading all values + ## v1.4.3.0 [2018-3-28] ### Features From da8ed064f7893c0cbf5f81d0fce1d0e5f9909691 Mon Sep 17 00:00:00 2001 From: nathan haugo Date: Mon, 2 Apr 2018 17:58:53 -0700 Subject: [PATCH 37/39] Remove dupe changelog entries --- CHANGELOG.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64f2e45ae3..7bf2d29ea5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,9 +13,6 @@ ### Bug Fixes -1. [#2950](https://github.com/influxdata/chronograf/pull/2094): Always save template variables on first edit -1. [#3101](https://github.com/influxdata/chronograf/pull/3101): Fix template variables not loading - ## v1.4.3.1 [2018-04-02] ### Bug Fixes From c00a67f075b13e1437888c885f9a899407c8f951 Mon Sep 17 00:00:00 2001 From: Andrew Watkins Date: Tue, 3 Apr 2018 10:53:55 -0700 Subject: [PATCH 38/39] Refactor label logic into if statement --- ui/src/admin/components/UserPermissionsDropdown.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ui/src/admin/components/UserPermissionsDropdown.tsx b/ui/src/admin/components/UserPermissionsDropdown.tsx index 6d5e69e29d..d3345341ef 100644 --- a/ui/src/admin/components/UserPermissionsDropdown.tsx +++ b/ui/src/admin/components/UserPermissionsDropdown.tsx @@ -49,9 +49,11 @@ class UserPermissionsDropdown extends PureComponent { private get permissionsLabel() { const {user} = this.props - return user.permissions && user.permissions.length - ? '' - : 'Select Permissions' + if (user.permissions && user.permissions.length) { + return 'Select Permissions' + } + + return '' } private get permissionsClass() { From 63d8d8bfa5bd5641c3b2903b96d0cf6b7c33d7ab Mon Sep 17 00:00:00 2001 From: Andrew Watkins Date: Tue, 3 Apr 2018 10:56:22 -0700 Subject: [PATCH 39/39] Move functions out of render --- ui/src/admin/components/UserRow.tsx | 51 ++++++++++++++++------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/ui/src/admin/components/UserRow.tsx b/ui/src/admin/components/UserRow.tsx index 2de3f7ecde..a2e908c6c6 100644 --- a/ui/src/admin/components/UserRow.tsx +++ b/ui/src/admin/components/UserRow.tsx @@ -28,7 +28,6 @@ interface UserRowProps { class UserRow extends PureComponent { public render() { const { - user: {name, password}, user, allRoles, allPermissions, @@ -38,20 +37,10 @@ class UserRow extends PureComponent { onEdit, onSave, onCancel, - onDelete, onUpdatePermissions, onUpdateRoles, - onUpdatePassword, } = this.props - function handleUpdatePassword(): void { - onUpdatePassword(user, password) - } - - const wrappedDelete = () => { - onDelete(user) - } - if (isEditing) { return ( { return ( - {name} + {user.name} {hasRoles && ( @@ -86,14 +75,13 @@ class UserRow extends PureComponent { )} - {allPermissions && - !!allPermissions.length && ( - - )} + {this.hasPermissions && ( + + )} { size="btn-xs" type="btn-danger" text="Delete User" - confirmAction={wrappedDelete} + confirmAction={this.handleDelete} customClass="table--show-on-row-hover" /> ) } + + private handleDelete = (): void => { + const {user, onDelete} = this.props + + onDelete(user) + } + + private handleUpdatePassword = (): void => { + const {user, onUpdatePassword} = this.props + + onUpdatePassword(user, user.password) + } + + private get hasPermissions() { + const {allPermissions} = this.props + return allPermissions && !!allPermissions.length + } } export default UserRow