From 85d13d27ed108c0a70b09b4d4a570c25beaf1815 Mon Sep 17 00:00:00 2001 From: Alex P Date: Tue, 20 Feb 2018 22:27:42 -0800 Subject: [PATCH] Refactor single stat colors into redux state instead of CEO state --- .../dashboards/actions/cellEditorOverlay.js | 14 + .../components/CellEditorOverlay.js | 149 ++------- .../dashboards/components/DisplayOptions.js | 31 +- .../components/SingleStatOptions.js | 285 ++++++++++++------ ui/src/dashboards/components/Visualization.js | 64 ++-- ui/src/dashboards/containers/DashboardPage.js | 10 +- .../dashboards/reducers/cellEditorOverlay.js | 33 +- 7 files changed, 301 insertions(+), 285 deletions(-) diff --git a/ui/src/dashboards/actions/cellEditorOverlay.js b/ui/src/dashboards/actions/cellEditorOverlay.js index 3ec33de341..cafc82859a 100644 --- a/ui/src/dashboards/actions/cellEditorOverlay.js +++ b/ui/src/dashboards/actions/cellEditorOverlay.js @@ -22,3 +22,17 @@ export const renameCell = cellName => ({ cellName, }, }) + +export const updateSingleStatColors = singleStatColors => ({ + type: 'UPDATE_SINGLE_STAT_COLORS', + payload: { + singleStatColors, + }, +}) + +export const updateSingleStatType = singleStatType => ({ + type: 'UPDATE_SINGLE_STAT_TYPE', + payload: { + singleStatType, + }, +}) diff --git a/ui/src/dashboards/components/CellEditorOverlay.js b/ui/src/dashboards/components/CellEditorOverlay.js index 747bfa6ef2..d762f13e52 100644 --- a/ui/src/dashboards/components/CellEditorOverlay.js +++ b/ui/src/dashboards/components/CellEditorOverlay.js @@ -25,12 +25,8 @@ import {AUTO_GROUP_BY} from 'shared/constants' import { COLOR_TYPE_THRESHOLD, MAX_THRESHOLDS, - DEFAULT_VALUE_MIN, - DEFAULT_VALUE_MAX, GAUGE_COLORS, validateGaugeColors, - validateSingleStatColors, - getSingleStatType, stringifyColorValues, } from 'src/dashboards/constants/gaugeColors' @@ -51,16 +47,12 @@ class CellEditorOverlay extends Component { })) ) - const singleStatType = getSingleStatType(colors) - this.state = { queriesWorkingDraft, activeQueryIndex: 0, isDisplayOptionsTabActive: false, axes, - singleStatType, gaugeColors: validateGaugeColors(colors), - singleStatColors: validateSingleStatColors(colors, singleStatType), } } @@ -110,113 +102,39 @@ class CellEditorOverlay extends Component { } } - handleAddSingleStatThreshold = () => { - const {singleStatColors, singleStatType} = this.state - - const randomColor = _.random(0, GAUGE_COLORS.length - 1) - - const maxValue = DEFAULT_VALUE_MIN - const minValue = DEFAULT_VALUE_MAX - - let randomValue = _.round(_.random(minValue, maxValue, true), 2) - - if (singleStatColors.length > 0) { - const colorsValues = _.mapValues(singleStatColors, 'value') - do { - randomValue = _.round(_.random(minValue, maxValue, true), 2) - } while (_.includes(colorsValues, randomValue)) - } - - const newThreshold = { - type: singleStatType, - id: uuid.v4(), - value: randomValue, - hex: GAUGE_COLORS[randomColor].hex, - name: GAUGE_COLORS[randomColor].name, - } - - this.setState({singleStatColors: [...singleStatColors, newThreshold]}) - } - handleDeleteThreshold = threshold => () => { - const {type} = this.props.cell + const gaugeColors = this.state.gaugeColors.filter( + color => color.id !== threshold.id + ) - if (type === 'gauge') { - const gaugeColors = this.state.gaugeColors.filter( - color => color.id !== threshold.id - ) - - this.setState({gaugeColors}) - } - - if (type === 'single-stat') { - const singleStatColors = this.state.singleStatColors.filter( - color => color.id !== threshold.id - ) - - this.setState({singleStatColors}) - } + this.setState({gaugeColors}) } handleChooseColor = threshold => chosenColor => { - const {type} = this.props.cell + const gaugeColors = this.state.gaugeColors.map( + color => + color.id === threshold.id + ? {...color, hex: chosenColor.hex, name: chosenColor.name} + : color + ) - if (type === 'gauge') { - const gaugeColors = this.state.gaugeColors.map( - color => - color.id === threshold.id - ? {...color, hex: chosenColor.hex, name: chosenColor.name} - : color - ) - - this.setState({gaugeColors}) - } - - if (type === 'single-stat') { - const singleStatColors = this.state.singleStatColors.map( - color => - color.id === threshold.id - ? {...color, hex: chosenColor.hex, name: chosenColor.name} - : color - ) - - this.setState({singleStatColors}) - } + this.setState({gaugeColors}) } handleUpdateColorValue = (threshold, value) => { - const {type} = this.props.cell + const gaugeColors = this.state.gaugeColors.map( + color => (color.id === threshold.id ? {...color, value} : color) + ) - if (type === 'gauge') { - const gaugeColors = this.state.gaugeColors.map( - color => (color.id === threshold.id ? {...color, value} : color) - ) - - this.setState({gaugeColors}) - } - - if (type === 'single-stat') { - const singleStatColors = this.state.singleStatColors.map( - color => (color.id === threshold.id ? {...color, value} : color) - ) - - this.setState({singleStatColors}) - } + this.setState({gaugeColors}) } handleValidateColorValue = (threshold, targetValue) => { - const {gaugeColors, singleStatColors} = this.state - const {type} = this.props.cell + const {gaugeColors} = this.state const thresholdValue = threshold.value let allowedToUpdate = false - if (type === 'single-stat') { - // If type is single-stat then value only has to be unique - const sortedColors = _.sortBy(singleStatColors, color => color.value) - return !sortedColors.some(color => color.value === targetValue) - } - const sortedColors = _.sortBy(gaugeColors, color => color.value) const minValue = sortedColors[0].value @@ -252,18 +170,6 @@ class CellEditorOverlay extends Component { return allowedToUpdate } - handleToggleSingleStatType = type => () => { - const singleStatColors = this.state.singleStatColors.map(color => ({ - ...color, - type, - })) - - this.setState({ - singleStatType: type, - singleStatColors, - }) - } - handleSetSuffix = e => { const {axes} = this.state @@ -355,14 +261,9 @@ class CellEditorOverlay extends Component { } handleSaveCell = () => { - const { - queriesWorkingDraft, - axes, - gaugeColors, - singleStatColors, - } = this.state + const {queriesWorkingDraft, axes, gaugeColors} = this.state - const {cell} = this.props + const {cell, singleStatColors} = this.props const queries = queriesWorkingDraft.map(q => { const timeRange = q.range || {upper: null, lower: ':dashboardTime:'} @@ -520,7 +421,6 @@ class CellEditorOverlay extends Component { render() { const { - cell, onCancel, templates, timeRange, @@ -531,11 +431,9 @@ class CellEditorOverlay extends Component { const { axes, gaugeColors, - singleStatColors, activeQueryIndex, isDisplayOptionsTabActive, queriesWorkingDraft, - singleStatType, } = this.state const queryActions = { @@ -547,9 +445,6 @@ class CellEditorOverlay extends Component { (!!query.measurement && !!query.database && !!query.fields.length) || !!query.rawText - const visualizationColors = - cell.type === 'gauge' ? gaugeColors : singleStatColors - return (
) case 'single-stat': - return ( - - ) + return default: return ( ({ diff --git a/ui/src/dashboards/components/SingleStatOptions.js b/ui/src/dashboards/components/SingleStatOptions.js index c4af44736a..d32770d2b5 100644 --- a/ui/src/dashboards/components/SingleStatOptions.js +++ b/ui/src/dashboards/components/SingleStatOptions.js @@ -1,5 +1,9 @@ -import React, {PropTypes} from 'react' +import React, {Component, PropTypes} from 'react' +import {connect} from 'react-redux' +import {bindActionCreators} from 'redux' + import _ from 'lodash' +import uuid from 'node-uuid' import FancyScrollbar from 'shared/components/FancyScrollbar' import Threshold from 'src/dashboards/components/Threshold' @@ -7,106 +11,185 @@ import ColorDropdown from 'shared/components/ColorDropdown' import { GAUGE_COLORS, + DEFAULT_VALUE_MIN, + DEFAULT_VALUE_MAX, MAX_THRESHOLDS, SINGLE_STAT_BASE, SINGLE_STAT_TEXT, SINGLE_STAT_BG, } from 'src/dashboards/constants/gaugeColors' +import { + updateSingleStatType, + updateSingleStatColors, +} from 'src/dashboards/actions/cellEditorOverlay' + const formatColor = color => { const {hex, name} = color return {hex, name} } -const SingleStatOptions = ({ - suffix, - onSetSuffix, - colors, - onAddThreshold, - onDeleteThreshold, - onChooseColor, - onValidateColorValue, - onUpdateColorValue, - singleStatType, - onToggleSingleStatType, -}) => { - const disableAddThreshold = colors.length > MAX_THRESHOLDS - const sortedColors = _.sortBy(colors, color => color.value) +class SingleStatOptions extends Component { + handleToggleSingleStatType = newType => () => { + const {handleUpdateSingleStatType} = this.props - return ( - -
-
Single Stat Controls
-
- - {sortedColors.map( - color => - color.id === SINGLE_STAT_BASE - ?
-
Base Color
- { + const { + singleStatColors, + singleStatType, + handleUpdateSingleStatColors, + } = this.props + + const randomColor = _.random(0, GAUGE_COLORS.length - 1) + + const maxValue = DEFAULT_VALUE_MIN + const minValue = DEFAULT_VALUE_MAX + + let randomValue = _.round(_.random(minValue, maxValue, true), 2) + + if (singleStatColors.length > 0) { + const colorsValues = _.mapValues(singleStatColors, 'value') + do { + randomValue = _.round(_.random(minValue, maxValue, true), 2) + } while (_.includes(colorsValues, randomValue)) + } + + const newThreshold = { + type: singleStatType, + id: uuid.v4(), + value: randomValue, + hex: GAUGE_COLORS[randomColor].hex, + name: GAUGE_COLORS[randomColor].name, + } + + handleUpdateSingleStatColors([...singleStatColors, newThreshold]) + } + + handleDeleteThreshold = threshold => () => { + const {handleUpdateSingleStatColors} = this.props + + const singleStatColors = this.props.singleStatColors.filter( + color => color.id !== threshold.id + ) + + handleUpdateSingleStatColors(singleStatColors) + } + + handleChooseColor = threshold => chosenColor => { + const {handleUpdateSingleStatColors} = this.props + + const singleStatColors = this.props.singleStatColors.map( + color => + color.id === threshold.id + ? {...color, hex: chosenColor.hex, name: chosenColor.name} + : color + ) + + handleUpdateSingleStatColors(singleStatColors) + } + + handleUpdateColorValue = (threshold, value) => { + const {handleUpdateSingleStatColors} = this.props + + const singleStatColors = this.props.singleStatColors.map( + color => (color.id === threshold.id ? {...color, value} : color) + ) + + handleUpdateSingleStatColors(singleStatColors) + } + + handleValidateColorValue = (threshold, targetValue) => { + const {singleStatColors} = this.props + const sortedColors = _.sortBy(singleStatColors, color => color.value) + + return !sortedColors.some(color => color.value === targetValue) + } + + render() { + const {suffix, onSetSuffix, singleStatColors, singleStatType} = this.props + + const disableAddThreshold = singleStatColors.length > MAX_THRESHOLDS + + const sortedColors = _.sortBy(singleStatColors, color => color.value) + + return ( + +
+
Single Stat Controls
+
+ + {sortedColors.map( + color => + color.id === SINGLE_STAT_BASE + ?
+
Base Color
+ +
+ : -
- : - )} -
-
-
- -
    -
  • - Background -
  • -
  • - Text -
  • -
+ )}
-
- - +
+
+ +
    +
  • + Background +
  • +
  • + Text +
  • +
+
+
+ + +
-
-
- ) + + ) + } } const {arrayOf, func, number, shape, string} = PropTypes @@ -116,7 +199,8 @@ SingleStatOptions.defaultProps = { } SingleStatOptions.propTypes = { - colors: arrayOf( + singleStatType: string.isRequired, + singleStatColors: arrayOf( shape({ type: string.isRequired, hex: string.isRequired, @@ -125,15 +209,28 @@ SingleStatOptions.propTypes = { value: number.isRequired, }).isRequired ), - onAddThreshold: func.isRequired, - onDeleteThreshold: func.isRequired, - onChooseColor: func.isRequired, - onValidateColorValue: func.isRequired, - onUpdateColorValue: func.isRequired, - singleStatType: string.isRequired, - onToggleSingleStatType: func.isRequired, onSetSuffix: func.isRequired, suffix: string.isRequired, + handleUpdateSingleStatType: func.isRequired, + handleUpdateSingleStatColors: func.isRequired, } -export default SingleStatOptions +const mapStateToProps = ({ + cellEditorOverlay: {singleStatType, singleStatColors}, +}) => ({ + singleStatType, + singleStatColors, +}) + +const mapDispatchToProps = dispatch => ({ + handleUpdateSingleStatType: bindActionCreators( + updateSingleStatType, + dispatch + ), + handleUpdateSingleStatColors: bindActionCreators( + updateSingleStatColors, + dispatch + ), +}) + +export default connect(mapStateToProps, mapDispatchToProps)(SingleStatOptions) diff --git a/ui/src/dashboards/components/Visualization.js b/ui/src/dashboards/components/Visualization.js index 1b915f35f6..14f4cf124c 100644 --- a/ui/src/dashboards/components/Visualization.js +++ b/ui/src/dashboards/components/Visualization.js @@ -1,4 +1,6 @@ import React, {PropTypes} from 'react' +import {connect} from 'react-redux' + import RefreshingGraph from 'shared/components/RefreshingGraph' import buildQueries from 'utils/buildQueriesForGraphs' import VisualizationName from 'src/dashboards/components/VisualizationName' @@ -9,40 +11,41 @@ const DashVisualization = ( { axes, type, - colors, templates, timeRange, autoRefresh, queryConfigs, editQueryStatus, resizerTopHeight, + singleStatColors, }, {source: {links: {proxy}}} -) => -
- -
- +) => { + // const colors = type === 'gauge' ? gaugeColors : singleStatColors + + return ( +
+ +
+ +
-
+ ) +} const {arrayOf, func, number, shape, string} = PropTypes -DashVisualization.defaultProps = { - type: '', -} - DashVisualization.propTypes = { - type: string, + type: string.isRequired, autoRefresh: number.isRequired, templates: arrayOf(shape()), timeRange: shape({ @@ -57,15 +60,11 @@ DashVisualization.propTypes = { }), }), resizerTopHeight: number, - colors: arrayOf( + singleStatColors: arrayOf( shape({ type: string.isRequired, - hex: string.isRequired, - id: string.isRequired, - name: string.isRequired, - value: number.isRequired, - }) - ), + }).isRequired + ).isRequired, } DashVisualization.contextTypes = { @@ -76,4 +75,11 @@ DashVisualization.contextTypes = { }).isRequired, } -export default DashVisualization +const mapStateToProps = ({ + cellEditorOverlay: {singleStatColors, cell: {type}}, +}) => ({ + singleStatColors, + type, +}) + +export default connect(mapStateToProps, null)(DashVisualization) diff --git a/ui/src/dashboards/containers/DashboardPage.js b/ui/src/dashboards/containers/DashboardPage.js index a1a536de53..5cb023d01a 100644 --- a/ui/src/dashboards/containers/DashboardPage.js +++ b/ui/src/dashboards/containers/DashboardPage.js @@ -244,6 +244,8 @@ class DashboardPage extends Component { manualRefresh, onManualRefresh, cellQueryStatus, + singleStatType, + singleStatColors, dashboardActions, inPresentationMode, handleChooseAutoRefresh, @@ -348,6 +350,8 @@ class DashboardPage extends Component { onCancel={handleHideCellEditorOverlay} templates={templatesIncludingDashTime} editQueryStatus={dashboardActions.editCellQueryStatus} + singleStatType={singleStatType} + singleStatColors={singleStatColors} /> : null} { @@ -485,7 +491,7 @@ const mapStateToProps = (state, {params: {dashboardID}}) => { sources, dashTimeV1, auth: {me, isUsingAuth}, - cellEditorOverlay: {cell}, + cellEditorOverlay: {cell, singleStatType, singleStatColors}, } = state const meRole = _.get(me, 'role', null) @@ -511,6 +517,8 @@ const mapStateToProps = (state, {params: {dashboardID}}) => { meRole, isUsingAuth, selectedCell, + singleStatType, + singleStatColors, } } diff --git a/ui/src/dashboards/reducers/cellEditorOverlay.js b/ui/src/dashboards/reducers/cellEditorOverlay.js index 1c23565300..9e2762fabb 100644 --- a/ui/src/dashboards/reducers/cellEditorOverlay.js +++ b/ui/src/dashboards/reducers/cellEditorOverlay.js @@ -1,13 +1,25 @@ +import { + SINGLE_STAT_TEXT, + DEFAULT_SINGLESTAT_COLORS, + validateSingleStatColors, + getSingleStatType, +} from 'src/dashboards/constants/gaugeColors' + const initialState = { cell: null, + singleStatType: SINGLE_STAT_TEXT, + singleStatColors: DEFAULT_SINGLESTAT_COLORS, } export default function cellEditorOverlay(state = initialState, action) { switch (action.type) { case 'SHOW_CELL_EDITOR_OVERLAY': { - const {cell} = action.payload + const {cell, cell: {colors}} = action.payload - return {...state, cell} + const singleStatType = getSingleStatType(colors) + const singleStatColors = validateSingleStatColors(colors, singleStatType) + + return {...state, cell, singleStatType, singleStatColors} } case 'HIDE_CELL_EDITOR_OVERLAY': { @@ -29,6 +41,23 @@ export default function cellEditorOverlay(state = initialState, action) { return {...state, cell} } + + case 'UPDATE_SINGLE_STAT_COLORS': { + const {singleStatColors} = action.payload + + return {...state, singleStatColors} + } + + case 'UPDATE_SINGLE_STAT_TYPE': { + const {singleStatType} = action.payload + + const singleStatColors = state.singleStatColors.map(color => ({ + ...color, + type: singleStatType, + })) + + return {...state, singleStatType, singleStatColors} + } } return state