Add Visualization Options to DE (#4353)

* Update Children components of DisplayOptions to use props instead of individually connecting to redux and CEO visualization actions updated in prep for DE Vis

* Update DataExplorer to have visualization options

* Update timeSeriesToDygraph to not treat data explorer differently from ceo

* Remove featureflag from vis options in DE

* Update failing tests and rename cellNote to Note

* Update columns for table graph if in ceo or de, but not in dashboard

* Update Changelog

* Remove unnecessary getters from DisplayOptions
pull/4352/head
Iris Scholten 2018-09-05 11:49:10 -07:00 committed by GitHub
parent 43afa38b0a
commit bba49e9061
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 1197 additions and 565 deletions

View File

@ -11,6 +11,7 @@
1. [#4287](https://github.com/influxdata/chronograf/pull/4287): Add time selector dropdown to CEO
1. [#4311](https://github.com/influxdata/chronograf/pull/4311): Add Flux query editor to the Cell Editor Overlay
1. [#4319](https://github.com/influxdata/chronograf/pull/4319): Add Flux query editor to the Data Explorer and use same UI as CEO
1. [#4353](https://github.com/influxdata/chronograf/pull/4353): Add visualization options to the Data Explorer
### UI Improvements

View File

@ -10,7 +10,7 @@ import {
TableOptions,
CellQuery,
NewDefaultCell,
CellNoteVisibility,
NoteVisibility,
} from 'src/types/dashboards'
import {TimeRange} from 'src/types'
import {CEOInitialState} from 'src/dashboards/reducers/cellEditorOverlay'
@ -172,7 +172,7 @@ export interface UpdateCellNoteAction {
export interface UpdateCellNoteVisibilityAction {
type: ActionType.UpdateCellNoteVisibility
payload: {
noteVisibility: CellNoteVisibility
noteVisibility: NoteVisibility
}
}
@ -198,111 +198,9 @@ export const clearCEO = (): ClearCEOAction => ({
type: ActionType.ClearCEO,
})
export const changeCellType = (cellType: CellType): ChangeCellTypeAction => ({
type: ActionType.ChangeCellType,
payload: {
cellType,
},
})
export const updateCellNote = (note: string): UpdateCellNoteAction => ({
type: ActionType.UpdateCellNote,
payload: {
note,
},
})
export const UpdateCellNoteVisibility = (
noteVisibility: CellNoteVisibility
): UpdateCellNoteVisibilityAction => ({
type: ActionType.UpdateCellNoteVisibility,
payload: {
noteVisibility,
},
})
export const renameCell = (cellName: string): RenameCellAction => ({
type: ActionType.RenameCell,
payload: {
cellName,
},
})
export const updateThresholdsListColors = (
thresholdsListColors: ColorNumber[]
): UpdateThresholdsListColorsAction => ({
type: ActionType.UpdateThresholdsListColors,
payload: {
thresholdsListColors,
},
})
export const updateThresholdsListType = (
thresholdsListType: ThresholdType
): UpdateThresholdsListTypeAction => ({
type: ActionType.UpdateThresholdsListType,
payload: {
thresholdsListType,
},
})
export const updateGaugeColors = (
gaugeColors: ColorNumber[]
): UpdateGaugeColorsAction => ({
type: ActionType.UpdateGaugeColors,
payload: {
gaugeColors,
},
})
export const updateAxes = (axes: Axes): UpdateAxesAction => ({
type: ActionType.UpdateAxes,
payload: {
axes,
},
})
export const updateTableOptions = (
tableOptions: TableOptions
): UpdateTableOptionsAction => ({
type: ActionType.UpdateTableOptions,
payload: {
tableOptions,
},
})
export const updateLineColors = (
lineColors: ColorString[]
): UpdateLineColorsAction => ({
type: ActionType.UpdateLineColors,
payload: {
lineColors,
},
})
export const changeTimeFormat = (
timeFormat: string
): ChangeTimeFormatAction => ({
type: ActionType.ChangeTimeFormat,
payload: {
timeFormat,
},
})
export const changeDecimalPlaces = (
decimalPlaces: DecimalPlaces
): ChangeDecimalPlacesAction => ({
type: ActionType.ChangeDecimalPlaces,
payload: {
decimalPlaces,
},
})
export const updateFieldOptions = (
fieldOptions: FieldOption[]
): UpdateFieldOptionsAction => ({
type: ActionType.UpdateFieldOptions,
payload: {
fieldOptions,
},
})

View File

@ -1,6 +1,5 @@
// Libraries
import React, {PureComponent} from 'react'
import {connect} from 'react-redux'
// Components
import OptIn from 'src/shared/components/OptIn'
@ -14,12 +13,6 @@ import GraphOptionsDecimalPlaces from 'src/dashboards/components/GraphOptionsDec
import {AXES_SCALE_OPTIONS} from 'src/dashboards/constants/cellEditor'
import {GRAPH_TYPES} from 'src/dashboards/graphics/graph'
// Actions
import {
updateAxes,
changeDecimalPlaces,
} from 'src/dashboards/actions/cellEditorOverlay'
// Decorators
import {ErrorHandling} from 'src/shared/decorators/errors'
@ -35,10 +28,10 @@ interface Props {
axes: Axes
staticLegend: boolean
defaultYLabel: string
onUpdateDecimalPlaces: () => void
decimalPlaces: DecimalPlaces
handleUpdateAxes: (axes: Axes) => void
onUpdateAxes: (axes: Axes) => void
onToggleStaticLegend: (isStaticLegend: boolean) => void
onUpdateDecimalPlaces: (decimalPlaces: DecimalPlaces) => void
}
@ErrorHandling
@ -260,7 +253,7 @@ class AxesOptions extends PureComponent<Props> {
}
private handleSetPrefixSuffix = e => {
const {handleUpdateAxes, axes} = this.props
const {onUpdateAxes, axes} = this.props
const {prefix, suffix} = e.target.form
const newAxes = {
@ -272,11 +265,11 @@ class AxesOptions extends PureComponent<Props> {
},
}
handleUpdateAxes(newAxes)
onUpdateAxes(newAxes)
}
private handleSetYAxisBoundMin = (min: string): void => {
const {handleUpdateAxes, axes} = this.props
const {onUpdateAxes, axes} = this.props
const {
y: {
bounds: [, max],
@ -286,11 +279,11 @@ class AxesOptions extends PureComponent<Props> {
const bounds: [string, string] = [min, max]
const newAxes = {...axes, y: {...axes.y, bounds}}
handleUpdateAxes(newAxes)
onUpdateAxes(newAxes)
}
private handleSetYAxisBoundMax = (max: string): void => {
const {handleUpdateAxes, axes} = this.props
const {onUpdateAxes, axes} = this.props
const {
y: {
bounds: [min],
@ -300,43 +293,29 @@ class AxesOptions extends PureComponent<Props> {
const bounds: [string, string] = [min, max]
const newAxes = {...axes, y: {...axes.y, bounds}}
handleUpdateAxes(newAxes)
onUpdateAxes(newAxes)
}
private handleSetLabel = label => {
const {handleUpdateAxes, axes} = this.props
const {onUpdateAxes, axes} = this.props
const newAxes = {...axes, y: {...axes.y, label}}
handleUpdateAxes(newAxes)
onUpdateAxes(newAxes)
}
private handleSetScale = (scale: string): void => {
const {handleUpdateAxes, axes} = this.props
const {onUpdateAxes, axes} = this.props
const newAxes = {...axes, y: {...axes.y, scale}}
handleUpdateAxes(newAxes)
onUpdateAxes(newAxes)
}
private handleSetBase = (base: string): void => {
const {handleUpdateAxes, axes} = this.props
const {onUpdateAxes, axes} = this.props
const newAxes = {...axes, y: {...axes.y, base}}
handleUpdateAxes(newAxes)
onUpdateAxes(newAxes)
}
}
const mstp = ({
cellEditorOverlay: {
cell: {axes, type},
},
}) => ({
axes,
type,
})
const mdtp = {
handleUpdateAxes: updateAxes,
onUpdateDecimalPlaces: changeDecimalPlaces,
}
export default connect(mstp, mdtp)(AxesOptions)
export default AxesOptions

View File

@ -4,7 +4,9 @@ import _ from 'lodash'
// Components
import {ErrorHandling} from 'src/shared/decorators/errors'
import TimeMachine from 'src/shared/components/TimeMachine/TimeMachine'
import TimeMachine, {
VisualizationOptions,
} from 'src/shared/components/TimeMachine/TimeMachine'
import CEOHeader from 'src/dashboards/components/CEOHeader'
// Utils
@ -33,7 +35,7 @@ import * as QueriesModels from 'src/types/queries'
import * as SourcesModels from 'src/types/sources'
import {Service, NotificationAction} from 'src/types'
import {Template} from 'src/types/tempVars'
import {NewDefaultCell} from 'src/types/dashboards'
import {NewDefaultCell, ThresholdType} from 'src/types/dashboards'
import {UpdateScript} from 'src/flux/actions'
import {Links} from 'src/types/flux'
@ -42,20 +44,6 @@ const staticLegend: DashboardsModels.Legend = {
orientation: 'bottom',
}
interface VisualizationOptions {
type: DashboardsModels.CellType
axes: DashboardsModels.Axes | null
tableOptions: DashboardsModels.TableOptions
fieldOptions: DashboardsModels.FieldOption[]
timeFormat: string
decimalPlaces: DashboardsModels.DecimalPlaces
note: string
noteVisibility: DashboardsModels.CellNoteVisibility
thresholdsListColors: ColorsModels.ColorNumber[]
gaugeColors: ColorsModels.ColorNumber[]
lineColors: ColorsModels.ColorString[]
}
interface Props {
fluxLinks: Links
script: string
@ -70,7 +58,7 @@ interface Props {
queryStatus: QueriesModels.QueryStatus
templates: Template[]
timeRange: QueriesModels.TimeRange
thresholdsListType: string
thresholdsListType: ThresholdType
thresholdsListColors: ColorsModels.ColorNumber[]
gaugeColors: ColorsModels.ColorNumber[]
lineColors: ColorsModels.ColorString[]
@ -198,7 +186,13 @@ class CellEditorOverlay extends Component<Props, State> {
}
private get visualizationOptions(): VisualizationOptions {
const {cell, thresholdsListColors, gaugeColors, lineColors} = this.props
const {
cell,
lineColors,
gaugeColors,
thresholdsListType,
thresholdsListColors,
} = this.props
const {
type,
@ -223,6 +217,7 @@ class CellEditorOverlay extends Component<Props, State> {
thresholdsListColors,
gaugeColors,
lineColors,
thresholdsListType,
}
}

View File

@ -13,22 +13,60 @@ import NoteOptions from 'src/dashboards/components/NoteOptions'
import CellNoteEditor from 'src/shared/components/TimeMachine/CellNoteEditor'
import Threesizer from 'src/shared/components/threesizer/Threesizer'
// Actions
import {
updateDecimalPlaces,
updateGaugeColors,
updateAxes,
updateTableOptions,
updateFieldOptions,
updateTimeFormat,
updateVisType,
updateNote,
updateNoteVisibility,
updateThresholdsListColors,
updateThresholdsListType,
} from 'src/shared/actions/visualizations'
// Constants
import {HANDLE_VERTICAL} from 'src/shared/constants'
import {QueryUpdateState} from 'src/shared/actions/queries'
import {DEFAULT_AXES} from 'src/dashboards/constants/cellEditor'
// Types
import {CellType} from 'src/types/dashboards'
import {
CellType,
FieldOption,
ThresholdType,
DecimalPlaces,
NewDefaultCell,
NoteVisibility,
TableOptions as TableOptionsInterface,
} from 'src/types/dashboards'
import {buildDefaultYLabel} from 'src/shared/presenters'
import {ErrorHandling} from 'src/shared/decorators/errors'
import {Axes, Cell, QueryConfig} from 'src/types'
import {ColorNumber} from 'src/types/colors'
import {VisualizationOptions} from 'src/shared/components/TimeMachine/TimeMachine'
interface Props {
cell: Cell
Axes: Axes
interface Props extends VisualizationOptions {
cell: Cell | NewDefaultCell
queryConfigs: QueryConfig[]
staticLegend: boolean
stateToUpdate: QueryUpdateState
onResetFocus: () => void
onToggleStaticLegend: (isStaticLegend: boolean) => void
onUpdateDecimalPlaces: typeof updateDecimalPlaces
onUpdateGaugeColors: typeof updateGaugeColors
onUpdateAxes: typeof updateAxes
onUpdateTableOptions: typeof updateTableOptions
onUpdateFieldOptions: typeof updateFieldOptions
onUpdateTimeFormat: typeof updateTimeFormat
onUpdateVisType: typeof updateVisType
onUpdateNote: typeof updateNote
onUpdateNoteVisibility: typeof updateNoteVisibility
onUpdateThresholdsListColors: typeof updateThresholdsListColors
onUpdateThresholdsListType: typeof updateThresholdsListType
}
interface State {
@ -63,14 +101,18 @@ class DisplayOptions extends Component<Props, State> {
}
private get threesizerDivisions() {
const {cell} = this.props
const {type, note, noteVisibility} = this.props
return [
{
name: 'Visualization Type',
headerButtons: [],
menuOptions: [],
render: () => <GraphTypeSelector />,
render: () => (
<GraphTypeSelector
type={type}
onUpdateVisType={this.handleUpdateVisType}
/>
),
headerOrientation: HANDLE_VERTICAL,
},
{
@ -84,7 +126,14 @@ class DisplayOptions extends Component<Props, State> {
name: 'Add a Note',
headerButtons: [],
menuOptions: [],
render: () => <CellNoteEditor note={cell.note} />,
render: () => (
<CellNoteEditor
note={note || ''}
noteVisibility={noteVisibility}
onUpdateNote={this.handleUpdateNote}
onUpdateNoteVisibility={this.handleUpdateNoteVisibility}
/>
),
headerOrientation: HANDLE_VERTICAL,
},
]
@ -92,41 +141,94 @@ class DisplayOptions extends Component<Props, State> {
private renderOptions = (): JSX.Element => {
const {
cell,
type,
decimalPlaces,
gaugeColors,
staticLegend,
onToggleStaticLegend,
onResetFocus,
queryConfigs,
thresholdsListType,
thresholdsListColors,
timeFormat,
tableOptions,
fieldOptions,
} = this.props
const {defaultYLabel} = this.state
switch (cell.type) {
switch (type) {
case CellType.Gauge:
return <GaugeOptions onResetFocus={onResetFocus} />
return (
<GaugeOptions
onResetFocus={onResetFocus}
axes={this.axes}
decimalPlaces={decimalPlaces}
gaugeColors={gaugeColors}
onUpdateAxes={this.handleUpdateAxes}
onUpdateDecimalPlaces={this.handleUpdateDecimalPlaces}
onUpdateGaugeColors={this.handleUpdateGaugeColors}
/>
)
case CellType.Note:
return <NoteOptions />
case CellType.SingleStat:
return <SingleStatOptions onResetFocus={onResetFocus} />
return (
<SingleStatOptions
onResetFocus={onResetFocus}
axes={this.axes}
decimalPlaces={decimalPlaces}
onUpdateAxes={this.handleUpdateAxes}
thresholdsListType={thresholdsListType}
thresholdsListColors={thresholdsListColors}
onUpdateDecimalPlaces={this.handleUpdateDecimalPlaces}
onUpdateThresholdsListType={this.handleUpdateThresholdsListType}
onUpdateThresholdsListColors={this.handleUpdateThresholdsListColors}
/>
)
case CellType.Table:
return (
<TableOptions
onResetFocus={onResetFocus}
queryConfigs={queryConfigs}
timeFormat={timeFormat}
tableOptions={tableOptions}
fieldOptions={fieldOptions}
decimalPlaces={decimalPlaces}
thresholdsListType={thresholdsListType}
thresholdsListColors={thresholdsListColors}
onUpdateDecimalPlaces={this.handleUpdateDecimalPlaces}
onUpdateFieldOptions={this.handleUpdateFieldOptions}
onUpdateTableOptions={this.handleUpdateTableOptions}
onUpdateTimeFormat={this.handleUpdateTimeFormat}
onUpdateThresholdsListColors={this.handleUpdateThresholdsListColors}
onUpdateThresholdsListType={this.handleUpdateThresholdsListType}
/>
)
default:
return (
<AxesOptions
axes={this.axes}
type={type}
staticLegend={staticLegend}
defaultYLabel={defaultYLabel}
decimalPlaces={cell.decimalPlaces}
decimalPlaces={decimalPlaces}
onUpdateAxes={this.handleUpdateAxes}
onToggleStaticLegend={onToggleStaticLegend}
onUpdateDecimalPlaces={this.handleUpdateDecimalPlaces}
/>
)
}
}
private get stateToUpdate(): QueryUpdateState {
return this.props.stateToUpdate
}
private get axes(): Axes {
return this.props.axes || DEFAULT_AXES
}
private get defaultYLabel(): string {
const {queryConfigs} = this.props
if (queryConfigs.length) {
@ -135,11 +237,88 @@ class DisplayOptions extends Component<Props, State> {
return ''
}
private handleUpdateAxes = (axes: Axes): void => {
const {onUpdateAxes} = this.props
onUpdateAxes(axes, this.stateToUpdate)
}
private handleUpdateDecimalPlaces = (decimalPlaces: DecimalPlaces): void => {
const {onUpdateDecimalPlaces} = this.props
onUpdateDecimalPlaces(decimalPlaces, this.stateToUpdate)
}
private handleUpdateGaugeColors = (gaugeColors: ColorNumber[]): void => {
const {onUpdateGaugeColors} = this.props
onUpdateGaugeColors(gaugeColors, this.stateToUpdate)
}
private handleUpdateTimeFormat = (timeFormat: string): void => {
const {onUpdateTimeFormat} = this.props
onUpdateTimeFormat(timeFormat, this.stateToUpdate)
}
private handleUpdateTableOptions = (
tableOptions: TableOptionsInterface
): void => {
const {onUpdateTableOptions} = this.props
onUpdateTableOptions(tableOptions, this.stateToUpdate)
}
private handleUpdateFieldOptions = (fieldOptions: FieldOption[]): void => {
const {onUpdateFieldOptions} = this.props
onUpdateFieldOptions(fieldOptions, this.stateToUpdate)
}
private handleUpdateVisType = (type: CellType): void => {
const {onUpdateVisType} = this.props
onUpdateVisType(type, this.stateToUpdate)
}
private handleUpdateNote = (note: string): void => {
const {onUpdateNote} = this.props
onUpdateNote(note, this.stateToUpdate)
}
private handleUpdateNoteVisibility = (visibility: NoteVisibility): void => {
const {onUpdateNoteVisibility} = this.props
onUpdateNoteVisibility(visibility, this.stateToUpdate)
}
private handleUpdateThresholdsListColors = (colors: ColorNumber[]): void => {
const {onUpdateThresholdsListColors} = this.props
onUpdateThresholdsListColors(colors, this.stateToUpdate)
}
private handleUpdateThresholdsListType = (type: ThresholdType): void => {
const {onUpdateThresholdsListType} = this.props
onUpdateThresholdsListType(type, this.stateToUpdate)
}
}
const mstp = ({cellEditorOverlay}) => ({
cell: cellEditorOverlay.cell,
axes: cellEditorOverlay.cell.axes,
})
const mdtp = {
onUpdateGaugeColors: updateGaugeColors,
onUpdateAxes: updateAxes,
onUpdateDecimalPlaces: updateDecimalPlaces,
onUpdateTableOptions: updateTableOptions,
onUpdateFieldOptions: updateFieldOptions,
onUpdateTimeFormat: updateTimeFormat,
onUpdateVisType: updateVisType,
onUpdateNote: updateNote,
onUpdateNoteVisibility: updateNoteVisibility,
onUpdateThresholdsListColors: updateThresholdsListColors,
onUpdateThresholdsListType: updateThresholdsListType,
}
export default connect(mstp, null)(DisplayOptions)
export default connect(null, mdtp)(DisplayOptions)

View File

@ -1,13 +1,14 @@
// Libraries
import React, {PureComponent} from 'react'
import {connect} from 'react-redux'
import _ from 'lodash'
import uuid from 'uuid'
// Components
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
import Threshold from 'src/dashboards/components/Threshold'
import GraphOptionsDecimalPlaces from 'src/dashboards/components/GraphOptionsDecimalPlaces'
// Constants
import {
COLOR_TYPE_THRESHOLD,
THRESHOLD_COLORS,
@ -15,11 +16,7 @@ import {
MIN_THRESHOLDS,
} from 'src/shared/constants/thresholds'
import {
changeDecimalPlaces,
updateGaugeColors,
updateAxes,
} from 'src/dashboards/actions/cellEditorOverlay'
// Types
import {ErrorHandling} from 'src/shared/decorators/errors'
import {Axes} from 'src/types'
import {DecimalPlaces} from 'src/types/dashboards'
@ -30,9 +27,9 @@ interface Props {
gaugeColors: ColorNumber[]
decimalPlaces: DecimalPlaces
onResetFocus: () => void
handleUpdateAxes: (a: Axes) => void
onUpdateAxes: (a: Axes) => void
onUpdateDecimalPlaces: (d: DecimalPlaces) => void
handleUpdateGaugeColors: (d: ColorNumber[]) => void
onUpdateGaugeColors: (g: ColorNumber[]) => void
}
@ErrorHandling
@ -116,7 +113,7 @@ class GaugeOptions extends PureComponent<Props> {
}
private handleAddThreshold = () => {
const {gaugeColors, handleUpdateGaugeColors, onResetFocus} = this.props
const {gaugeColors, onUpdateGaugeColors, onResetFocus} = this.props
const sortedColors = _.sortBy(gaugeColors, color => color.value)
if (sortedColors.length <= MAX_THRESHOLDS) {
@ -145,25 +142,25 @@ class GaugeOptions extends PureComponent<Props> {
color => color.value
)
handleUpdateGaugeColors(updatedColors)
onUpdateGaugeColors(updatedColors)
} else {
onResetFocus()
}
}
private handleDeleteThreshold = threshold => {
const {handleUpdateGaugeColors, onResetFocus} = this.props
const {onUpdateGaugeColors, onResetFocus} = this.props
const gaugeColors = this.props.gaugeColors.filter(
color => color.id !== threshold.id
)
const sortedColors = _.sortBy(gaugeColors, color => color.value)
handleUpdateGaugeColors(sortedColors)
onUpdateGaugeColors(sortedColors)
onResetFocus()
}
private handleChooseColor = threshold => {
const {handleUpdateGaugeColors} = this.props
const {onUpdateGaugeColors} = this.props
const gaugeColors = this.props.gaugeColors.map(
color =>
color.id === threshold.id
@ -171,16 +168,16 @@ class GaugeOptions extends PureComponent<Props> {
: color
)
handleUpdateGaugeColors(gaugeColors)
onUpdateGaugeColors(gaugeColors)
}
private handleUpdateColorValue = (threshold, value) => {
const {handleUpdateGaugeColors} = this.props
const {onUpdateGaugeColors} = this.props
const gaugeColors = this.props.gaugeColors.map(
color => (color.id === threshold.id ? {...color, value} : color)
)
handleUpdateGaugeColors(gaugeColors)
onUpdateGaugeColors(gaugeColors)
}
private handleValidateColorValue = (threshold, targetValue) => {
@ -225,17 +222,17 @@ class GaugeOptions extends PureComponent<Props> {
}
private handleUpdatePrefix = e => {
const {handleUpdateAxes, axes} = this.props
const {onUpdateAxes, axes} = this.props
const newAxes = {...axes, y: {...axes.y, prefix: e.target.value}}
handleUpdateAxes(newAxes)
onUpdateAxes(newAxes)
}
private handleUpdateSuffix = e => {
const {handleUpdateAxes, axes} = this.props
const {onUpdateAxes, axes} = this.props
const newAxes = {...axes, y: {...axes.y, suffix: e.target.value}}
handleUpdateAxes(newAxes)
onUpdateAxes(newAxes)
}
get sortedGaugeColors() {
@ -246,21 +243,4 @@ class GaugeOptions extends PureComponent<Props> {
}
}
const mapStateToProps = ({
cellEditorOverlay: {
gaugeColors,
cell: {axes, decimalPlaces},
},
}) => ({
decimalPlaces,
gaugeColors,
axes,
})
const mapDispatchToProps = {
handleUpdateGaugeColors: updateGaugeColors,
handleUpdateAxes: updateAxes,
onUpdateDecimalPlaces: changeDecimalPlaces,
}
export default connect(mapStateToProps, mapDispatchToProps)(GaugeOptions)
export default GaugeOptions

View File

@ -1,23 +1,22 @@
// Libraries
import React, {Component} from 'react'
import {connect} from 'react-redux'
import classnames from 'classnames'
// Components
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
// Actions
import {changeCellType} from 'src/dashboards/actions/cellEditorOverlay'
// Constants
import {GRAPH_TYPES} from 'src/dashboards/graphics/graph'
// Decorators
import {ErrorHandling} from 'src/shared/decorators/errors'
// Types
import {CellType} from 'src/types/dashboards'
interface Props {
type: string
handleChangeCellType: (newType: string) => void
onUpdateVisType: (newType: CellType) => void
}
@ErrorHandling
@ -48,21 +47,9 @@ class GraphTypeSelector extends Component<Props> {
)
}
private onChangeCellType = (newType: string) => (): void => {
this.props.handleChangeCellType(newType)
private onChangeCellType = (newType: CellType) => (): void => {
this.props.onUpdateVisType(newType)
}
}
const mapStateToProps = ({
cellEditorOverlay: {
cell: {type},
},
}) => ({
type,
})
const mapDispatchToProps = {
handleChangeCellType: changeCellType,
}
export default connect(mapStateToProps, mapDispatchToProps)(GraphTypeSelector)
export default GraphTypeSelector

View File

@ -1,24 +1,27 @@
// Libraries
import React, {PureComponent} from 'react'
import {connect} from 'react-redux'
// Components
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
import ThresholdsList from 'src/shared/components/ThresholdsList'
import ThresholdsListTypeToggle from 'src/shared/components/ThresholdsListTypeToggle'
import GraphOptionsDecimalPlaces from 'src/dashboards/components/GraphOptionsDecimalPlaces'
import {
updateAxes,
changeDecimalPlaces,
} from 'src/dashboards/actions/cellEditorOverlay'
// Types
import {ErrorHandling} from 'src/shared/decorators/errors'
import {Axes} from 'src/types'
import {DecimalPlaces} from 'src/types/dashboards'
import {DecimalPlaces, ThresholdType} from 'src/types/dashboards'
import {ColorNumber} from 'src/types/colors'
interface Props {
axes: Axes
decimalPlaces: DecimalPlaces
thresholdsListType: ThresholdType
thresholdsListColors: ColorNumber[]
onResetFocus: () => void
onUpdateAxes: (axes: Axes) => void
onUpdateThresholdsListColors: (c: ColorNumber[]) => void
onUpdateThresholdsListType: (newType: ThresholdType) => void
onUpdateDecimalPlaces: (decimalPlaces: DecimalPlaces) => void
}
@ -31,13 +34,22 @@ class SingleStatOptions extends PureComponent<Props> {
},
onResetFocus,
decimalPlaces,
onUpdateThresholdsListColors,
thresholdsListType,
thresholdsListColors,
onUpdateThresholdsListType,
} = this.props
return (
<FancyScrollbar className="display-options" autoHide={false}>
<div className="display-options--wrapper">
<h5 className="display-options--header">Single Stat Controls</h5>
<ThresholdsList onResetFocus={onResetFocus} />
<ThresholdsList
onResetFocus={onResetFocus}
thresholdsListType={thresholdsListType}
thresholdsListColors={thresholdsListColors}
onUpdateThresholdsListColors={onUpdateThresholdsListColors}
/>
<div className="graph-options-group form-group-wrapper">
<div className="form-group col-xs-6">
<label>Prefix</label>
@ -64,7 +76,11 @@ class SingleStatOptions extends PureComponent<Props> {
isEnforced={decimalPlaces.isEnforced}
onDecimalPlacesChange={this.handleDecimalPlacesChange}
/>
<ThresholdsListTypeToggle containerClass="form-group col-xs-6" />
<ThresholdsListTypeToggle
containerClass="form-group col-xs-6"
thresholdsListType={thresholdsListType}
onUpdateThresholdsListType={onUpdateThresholdsListType}
/>
</div>
</div>
</FancyScrollbar>
@ -91,14 +107,4 @@ class SingleStatOptions extends PureComponent<Props> {
}
}
const mstp = ({cellEditorOverlay}) => ({
axes: cellEditorOverlay.cell.axes,
decimalPlaces: cellEditorOverlay.cell.decimalPlaces,
})
const mdtp = {
onUpdateAxes: updateAxes,
onUpdateDecimalPlaces: changeDecimalPlaces,
}
export default connect(mstp, mdtp)(SingleStatOptions)
export default SingleStatOptions

View File

@ -1,7 +1,8 @@
// Libraries
import React, {Component} from 'react'
import {connect} from 'react-redux'
import {bindActionCreators} from 'redux'
import _ from 'lodash'
// Components
import GraphOptionsCustomizeFields from 'src/dashboards/components/GraphOptionsCustomizeFields'
import GraphOptionsFixFirstColumn from 'src/dashboards/components/GraphOptionsFixFirstColumn'
import GraphOptionsSortBy from 'src/dashboards/components/GraphOptionsSortBy'
@ -9,23 +10,19 @@ import GraphOptionsTimeAxis from 'src/dashboards/components/GraphOptionsTimeAxis
import GraphOptionsTimeFormat from 'src/dashboards/components/GraphOptionsTimeFormat'
import GraphOptionsDecimalPlaces from 'src/dashboards/components/GraphOptionsDecimalPlaces'
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
import _ from 'lodash'
import ThresholdsList from 'src/shared/components/ThresholdsList'
import ThresholdsListTypeToggle from 'src/shared/components/ThresholdsListTypeToggle'
import {
updateTableOptions,
updateFieldOptions,
changeTimeFormat,
changeDecimalPlaces,
} from 'src/dashboards/actions/cellEditorOverlay'
// Constants
import {DEFAULT_TIME_FIELD} from 'src/dashboards/constants'
// Decorators
import {ErrorHandling} from 'src/shared/decorators/errors'
import {DecimalPlaces} from 'src/types/dashboards'
// Types
import {DecimalPlaces, ThresholdType} from 'src/types/dashboards'
import {QueryConfig} from 'src/types/queries'
import {ColorNumber} from 'src/types/colors'
interface DropdownOption {
text: string
@ -46,15 +43,19 @@ interface TableOptionsInterface {
interface Props {
queryConfigs: QueryConfig[]
handleUpdateTableOptions: (options: TableOptionsInterface) => void
handleUpdateFieldOptions: (fieldOptions: RenamableField[]) => void
handleChangeTimeFormat: (timeFormat: string) => void
handleChangeDecimalPlaces: (decimalPlaces: number) => void
onUpdateTableOptions: (options: TableOptionsInterface) => void
onUpdateFieldOptions: (fieldOptions: RenamableField[]) => void
onUpdateTimeFormat: (timeFormat: string) => void
onUpdateDecimalPlaces: (decimalPlaces: DecimalPlaces) => void
tableOptions: TableOptionsInterface
fieldOptions: RenamableField[]
timeFormat: string
decimalPlaces: DecimalPlaces
thresholdsListType: ThresholdType
thresholdsListColors: ColorNumber[]
onResetFocus: () => void
onUpdateThresholdsListColors: (c: ColorNumber[]) => void
onUpdateThresholdsListType: (newType: ThresholdType) => void
}
@ErrorHandling
@ -72,6 +73,10 @@ export class TableOptions extends Component<Props, {}> {
onResetFocus,
tableOptions,
decimalPlaces,
onUpdateThresholdsListColors,
thresholdsListType,
thresholdsListColors,
onUpdateThresholdsListType,
} = this.props
const tableSortByOptions = fieldOptions.map(field => ({
@ -112,9 +117,19 @@ export class TableOptions extends Component<Props, {}> {
onFieldUpdate={this.handleFieldUpdate}
moveField={this.moveField}
/>
<ThresholdsList showListHeading={true} onResetFocus={onResetFocus} />
<ThresholdsList
showListHeading={true}
onResetFocus={onResetFocus}
thresholdsListType={thresholdsListType}
thresholdsListColors={thresholdsListColors}
onUpdateThresholdsListColors={onUpdateThresholdsListColors}
/>
<div className="form-group-wrapper graph-options-group">
<ThresholdsListTypeToggle containerClass="form-group col-xs-6" />
<ThresholdsListTypeToggle
containerClass="form-group col-xs-6"
thresholdsListType={thresholdsListType}
onUpdateThresholdsListType={onUpdateThresholdsListType}
/>
</div>
</div>
</FancyScrollbar>
@ -122,7 +137,7 @@ export class TableOptions extends Component<Props, {}> {
}
private moveField(dragIndex, hoverIndex) {
const {handleUpdateFieldOptions, fieldOptions} = this.props
const {onUpdateFieldOptions, fieldOptions} = this.props
const draggedField = fieldOptions[dragIndex]
@ -137,40 +152,40 @@ export class TableOptions extends Component<Props, {}> {
_.slice(fieldOptionsRemoved, hoverIndex)
)
handleUpdateFieldOptions(fieldOptionsAdded)
onUpdateFieldOptions(fieldOptionsAdded)
}
private handleChooseSortBy = (option: DropdownOption) => {
const {tableOptions, handleUpdateTableOptions, fieldOptions} = this.props
const {tableOptions, onUpdateTableOptions, fieldOptions} = this.props
const sortBy = fieldOptions.find(f => f.internalName === option.key)
handleUpdateTableOptions({...tableOptions, sortBy})
onUpdateTableOptions({...tableOptions, sortBy})
}
private handleTimeFormatChange = timeFormat => {
const {handleChangeTimeFormat} = this.props
handleChangeTimeFormat(timeFormat)
const {onUpdateTimeFormat} = this.props
onUpdateTimeFormat(timeFormat)
}
private handleDecimalPlacesChange = decimalPlaces => {
const {handleChangeDecimalPlaces} = this.props
handleChangeDecimalPlaces(decimalPlaces)
const {onUpdateDecimalPlaces} = this.props
onUpdateDecimalPlaces(decimalPlaces)
}
private handleToggleVerticalTimeAxis = (verticalTimeAxis: boolean): void => {
const {tableOptions, handleUpdateTableOptions} = this.props
handleUpdateTableOptions({...tableOptions, verticalTimeAxis})
const {tableOptions, onUpdateTableOptions} = this.props
onUpdateTableOptions({...tableOptions, verticalTimeAxis})
}
private handleToggleFixFirstColumn = () => {
const {handleUpdateTableOptions, tableOptions} = this.props
const {onUpdateTableOptions, tableOptions} = this.props
const fixFirstColumn = !tableOptions.fixFirstColumn
handleUpdateTableOptions({...tableOptions, fixFirstColumn})
onUpdateTableOptions({...tableOptions, fixFirstColumn})
}
private handleFieldUpdate = field => {
const {
handleUpdateTableOptions,
handleUpdateFieldOptions,
onUpdateTableOptions,
onUpdateFieldOptions,
tableOptions,
fieldOptions,
} = this.props
@ -182,32 +197,14 @@ export class TableOptions extends Component<Props, {}> {
if (sortBy.internalName === field.internalName) {
const updatedSortBy = {...sortBy, displayName: field.displayName}
handleUpdateTableOptions({
onUpdateTableOptions({
...tableOptions,
sortBy: updatedSortBy,
})
}
handleUpdateFieldOptions(updatedFieldOptions)
onUpdateFieldOptions(updatedFieldOptions)
}
}
const mapStateToProps = ({
cellEditorOverlay: {
cell: {tableOptions, timeFormat, fieldOptions, decimalPlaces},
},
}) => ({
tableOptions,
timeFormat,
fieldOptions,
decimalPlaces,
})
const mapDispatchToProps = dispatch => ({
handleUpdateTableOptions: bindActionCreators(updateTableOptions, dispatch),
handleUpdateFieldOptions: bindActionCreators(updateFieldOptions, dispatch),
handleChangeTimeFormat: bindActionCreators(changeTimeFormat, dispatch),
handleChangeDecimalPlaces: bindActionCreators(changeDecimalPlaces, dispatch),
})
export default connect(mapStateToProps, mapDispatchToProps)(TableOptions)
export default TableOptions

View File

@ -6,6 +6,7 @@ import buildQueries from 'src/utils/buildQueriesForGraphs'
import {AutoRefresher} from 'src/utils/AutoRefresher'
import {getCellTypeColors} from 'src/dashboards/constants/cellEditor'
import {QueryUpdateState} from 'src/shared/actions/queries'
import {TimeRange, QueryConfig, Axes, Template, Source, Status} from 'src/types'
import {
@ -13,7 +14,7 @@ import {
DecimalPlaces,
FieldOption,
CellType,
CellNoteVisibility,
NoteVisibility,
} from 'src/types/dashboards'
import {ColorString, ColorNumber} from 'src/types/colors'
@ -35,10 +36,10 @@ interface Props {
gaugeColors: ColorNumber[]
lineColors: ColorString[]
staticLegend: boolean
isInCEO: boolean
note: string
noteVisibility: CellNoteVisibility
noteVisibility: NoteVisibility
manualRefresh: number
editorLocation?: QueryUpdateState
}
const DashVisualization: SFC<Props> = ({
@ -46,7 +47,6 @@ const DashVisualization: SFC<Props> = ({
type,
note,
source,
isInCEO,
templates,
timeRange,
lineColors,
@ -59,6 +59,7 @@ const DashVisualization: SFC<Props> = ({
manualRefresh,
decimalPlaces,
autoRefresher,
editorLocation,
noteVisibility,
editQueryStatus,
resizerTopHeight,
@ -89,11 +90,11 @@ const DashVisualization: SFC<Props> = ({
timeFormat={timeFormat}
decimalPlaces={decimalPlaces}
fieldOptions={fieldOptions}
isInCEO={isInCEO}
cellNote={note}
cellNoteVisibility={noteVisibility}
timeRange={timeRange}
manualRefresh={manualRefresh}
editorLocation={editorLocation}
/>
</div>
</div>

View File

@ -1,6 +1,6 @@
import {DEFAULT_TABLE_OPTIONS} from 'src/dashboards/constants'
import {stringifyColorValues} from 'src/shared/constants/colorOperations'
import {CellType, Axis} from 'src/types/dashboards'
import {CellType, Axis, Axes} from 'src/types/dashboards'
import {ColorString, ColorNumber} from 'src/types/colors'
export const initializeOptions = (cellType: CellType) => {
@ -29,6 +29,17 @@ export const DEFAULT_AXIS: DefaultAxis = {
label: '',
}
export const FULL_DEFAULT_AXIS: Axis = {
...DEFAULT_AXIS,
bounds: ['', ''],
}
export const DEFAULT_AXES: Axes = {
x: FULL_DEFAULT_AXIS,
y: FULL_DEFAULT_AXIS,
y2: FULL_DEFAULT_AXIS,
}
interface Color {
cellType: CellType
thresholdsListColors: ColorNumber[]

View File

@ -9,7 +9,7 @@ import {
DecimalPlaces,
SourceItemValue,
NewDefaultCell,
CellNoteVisibility,
NoteVisibility,
} from 'src/types/dashboards'
export const UNTITLED_GRAPH: string = 'Untitled Graph'
@ -54,6 +54,8 @@ export const FORMAT_OPTIONS: Array<{text: string}> = [
{text: TIME_FORMAT_CUSTOM},
]
export const DEFAULT_FIELD_OPTIONS = [DEFAULT_TIME_FIELD]
export const NEW_DEFAULT_DASHBOARD_CELL: NewDefaultCell = {
x: 0,
y: 0,
@ -65,10 +67,10 @@ export const NEW_DEFAULT_DASHBOARD_CELL: NewDefaultCell = {
tableOptions: DEFAULT_TABLE_OPTIONS,
timeFormat: DEFAULT_TIME_FORMAT,
decimalPlaces: DEFAULT_DECIMAL_PLACES,
fieldOptions: [DEFAULT_TIME_FIELD],
fieldOptions: DEFAULT_FIELD_OPTIONS,
inView: true,
note: '',
noteVisibility: CellNoteVisibility.Default,
noteVisibility: NoteVisibility.Default,
}
interface EmptyDefaultDashboardCell {

View File

@ -120,7 +120,7 @@ interface Props extends ManualRefreshProps, WithRouterProps {
queryDrafts: DashboardsModels.CellQuery[]
editorTimeRange: QueriesModels.TimeRange
updateQueryDrafts: (queryDrafts: DashboardsModels.CellQuery[]) => void
thresholdsListType: string
thresholdsListType: DashboardsModels.ThresholdType
thresholdsListColors: ColorsModels.ColorNumber[]
gaugeColors: ColorsModels.ColorNumber[]
lineColors: ColorsModels.ColorString[]

View File

@ -1,16 +1,17 @@
// Types
import {TimeRange, CellQuery, Status, QueryStatus} from 'src/types'
export interface DEInitialState {
queryDrafts: CellQuery[]
timeRange: TimeRange
queryStatus: QueryStatus
script: string
sourceLink: string
}
import {ColorNumber, ColorString} from 'src/types/colors'
import {TimeRange, CellQuery, Status, CellType, Axes} from 'src/types'
import {
DecimalPlaces,
FieldOption,
ThresholdType,
TableOptions,
NoteVisibility,
} from 'src/types/dashboards'
import {DEState} from 'src/types/dataExplorer'
export interface State {
dataExplorer: DEInitialState
dataExplorer: DEState
}
export enum ActionType {
@ -20,6 +21,19 @@ export enum ActionType {
UpdateQueryStatus = 'DE_UPDATE_QUERY_STATUS',
UpdateScript = 'DE_UPDATE_SCRIPT',
UpdateSourceLink = 'DE_UPDATE_SOURCE_LINK',
ChangeVisualizationType = 'DE_CHANGE_Visualization_TYPE',
UpdateThresholdsListColors = 'DE_UPDATE_THRESHOLDS_LIST_COLORS',
UpdateThresholdsListType = 'DE_UPDATE_THRESHOLDS_LIST_TYPE',
UpdateGaugeColors = 'DE_UPDATE_GAUGE_COLORS',
UpdateAxes = 'DE_UPDATE_AXES',
UpdateTableOptions = 'DE_UPDATE_TABLE_OPTIONS',
UpdateLineColors = 'DE_UPDATE_LINE_COLORS',
ChangeTimeFormat = 'DE_CHANGE_TIME_FORMAT',
ChangeDecimalPlaces = 'DE_CHANGE_DECIMAL_PLACES',
UpdateFieldOptions = 'DE_UPDATE_FIELD_OPTIONS',
UpdateQueryDraft = 'DE_UPDATE_QUERY_DRAFT',
UpdateNote = 'DE_UPDATE_NOTE',
UpdateNoteVisibility = 'DE_UPDATE_NOTE_VISIBILITY',
}
export type Action =
@ -29,6 +43,18 @@ export type Action =
| UpdateQueryStatusAction
| UpdateScriptAction
| UpdateSourceLinkAction
| ChangeVisualizationTypeAction
| UpdateThresholdsListColorsAction
| UpdateThresholdsListTypeAction
| UpdateGaugeColorsAction
| UpdateAxesAction
| UpdateTableOptionsAction
| UpdateLineColorsAction
| ChangeTimeFormatAction
| ChangeDecimalPlacesAction
| UpdateFieldOptionsAction
| UpdateCellNoteAction
| UpdateCellNoteVisibilityAction
export interface UpdateSourceLinkAction {
type: ActionType.UpdateSourceLink
@ -74,6 +100,90 @@ export interface UpdateScriptAction {
}
}
export interface ChangeVisualizationTypeAction {
type: ActionType.ChangeVisualizationType
payload: {
cellType: CellType
}
}
export interface UpdateThresholdsListColorsAction {
type: ActionType.UpdateThresholdsListColors
payload: {
thresholdsListColors: ColorNumber[]
}
}
export interface UpdateThresholdsListTypeAction {
type: ActionType.UpdateThresholdsListType
payload: {
thresholdsListType: ThresholdType
}
}
export interface UpdateGaugeColorsAction {
type: ActionType.UpdateGaugeColors
payload: {
gaugeColors: ColorNumber[]
}
}
export interface UpdateAxesAction {
type: ActionType.UpdateAxes
payload: {
axes: Axes
}
}
export interface UpdateTableOptionsAction {
type: ActionType.UpdateTableOptions
payload: {
tableOptions: TableOptions
}
}
export interface UpdateLineColorsAction {
type: ActionType.UpdateLineColors
payload: {
lineColors: ColorString[]
}
}
export interface ChangeTimeFormatAction {
type: ActionType.ChangeTimeFormat
payload: {
timeFormat: string
}
}
export interface ChangeDecimalPlacesAction {
type: ActionType.ChangeDecimalPlaces
payload: {
decimalPlaces: DecimalPlaces
}
}
export interface UpdateFieldOptionsAction {
type: ActionType.UpdateFieldOptions
payload: {
fieldOptions: FieldOption[]
}
}
export interface UpdateCellNoteAction {
type: ActionType.UpdateNote
payload: {
note: string
}
}
export interface UpdateCellNoteVisibilityAction {
type: ActionType.UpdateNoteVisibility
payload: {
noteVisibility: NoteVisibility
}
}
export const loadDE = (
queries: CellQuery[],
timeRange: TimeRange

View File

@ -5,7 +5,6 @@ import React, {Component} from 'react'
import {Radio, ButtonShape} from 'src/reusable_ui'
import GraphTips from 'src/shared/components/GraphTips'
import Authorized, {EDITOR_ROLE} from 'src/auth/Authorized'
import FeatureFlag from 'src/shared/components/FeatureFlag'
// Constants
import {CEOTabs} from 'src/dashboards/constants'
@ -40,28 +39,26 @@ class DEHeader extends Component<Props> {
<div className="page-header--container">
<div className="page-header--left">Explore</div>
<div className="deceo--header-tabs">
<FeatureFlag>
<Radio shape={ButtonShape.StretchToFit}>
<Radio.Button
id="deceo-tab-queries"
titleText="Queries"
value={CEOTabs.Queries}
active={activeEditorTab === CEOTabs.Queries}
onClick={onSetActiveEditorTab}
>
Queries
</Radio.Button>
<Radio.Button
id="deceo-tab-vis"
titleText="Visualization"
value={CEOTabs.Vis}
active={activeEditorTab === CEOTabs.Vis}
onClick={onSetActiveEditorTab}
>
Visualization
</Radio.Button>
</Radio>
</FeatureFlag>
<Radio shape={ButtonShape.StretchToFit}>
<Radio.Button
id="deceo-tab-queries"
titleText="Queries"
value={CEOTabs.Queries}
active={activeEditorTab === CEOTabs.Queries}
onClick={onSetActiveEditorTab}
>
Queries
</Radio.Button>
<Radio.Button
id="deceo-tab-vis"
titleText="Visualization"
value={CEOTabs.Vis}
active={activeEditorTab === CEOTabs.Vis}
onClick={onSetActiveEditorTab}
>
Visualization
</Radio.Button>
</Radio>
</div>
<div className="page-header--right">

View File

@ -22,7 +22,9 @@ import OverlayTechnology from 'src/reusable_ui/components/overlays/OverlayTechno
import ManualRefresh from 'src/shared/components/ManualRefresh'
import SendToDashboardOverlay from 'src/data_explorer/components/SendToDashboardOverlay'
import Authorized, {EDITOR_ROLE} from 'src/auth/Authorized'
import TimeMachine from 'src/shared/components/TimeMachine/TimeMachine'
import TimeMachine, {
VisualizationOptions,
} from 'src/shared/components/TimeMachine/TimeMachine'
import DEHeader from 'src/data_explorer/components/DEHeader'
// Actions
@ -66,9 +68,19 @@ import {
Template,
TemplateType,
TemplateValueType,
CellType,
Axes,
} from 'src/types'
import {ErrorHandling} from 'src/shared/decorators/errors'
import {Links} from 'src/types/flux'
import {ColorNumber, ColorString} from 'src/types/colors'
import {
DecimalPlaces,
FieldOption,
ThresholdType,
TableOptions,
NoteVisibility,
} from 'src/types/dashboards'
interface Props {
source: Source
@ -103,6 +115,18 @@ interface Props {
fetchServicesAsync: typeof fetchAllFluxServicesAsync
notify: typeof notifyAction
sourceLink: string
thresholdsListType: ThresholdType
thresholdsListColors: ColorNumber[]
gaugeColors: ColorNumber[]
lineColors: ColorString[]
visType: CellType
axes: Axes
tableOptions: TableOptions
timeFormat: string
decimalPlaces: DecimalPlaces
fieldOptions: FieldOption[]
note: string
noteVisibility: NoteVisibility
}
interface State {
@ -262,6 +286,7 @@ export class DataExplorer extends PureComponent<Props, State> {
updateScript={updateScript}
fluxLinks={fluxLinks}
notify={notify}
visualizationOptions={this.visualizationOptions}
>
{(activeEditorTab, onSetActiveEditorTab) => (
<DEHeader
@ -407,6 +432,38 @@ export class DataExplorer extends PureComponent<Props, State> {
return ''
}
private get visualizationOptions(): VisualizationOptions {
const {
visType,
tableOptions,
fieldOptions,
timeFormat,
decimalPlaces,
note,
noteVisibility,
axes,
thresholdsListColors,
thresholdsListType,
gaugeColors,
lineColors,
} = this.props
return {
type: visType,
axes,
tableOptions,
fieldOptions,
timeFormat,
decimalPlaces,
note,
noteVisibility,
thresholdsListColors,
gaugeColors,
lineColors,
thresholdsListType,
}
}
private toggleSendToDashboard = () => {
this.setState({
isSendToDashboardVisible: !this.state.isSendToDashboardVisible,
@ -427,7 +484,25 @@ const mapStateToProps = state => {
app: {
persisted: {autoRefresh},
},
dataExplorer: {queryDrafts, timeRange, queryStatus, script, sourceLink},
dataExplorer: {
queryDrafts,
timeRange,
queryStatus,
script,
sourceLink,
visType,
thresholdsListType,
thresholdsListColors,
gaugeColors,
lineColors,
axes,
tableOptions,
timeFormat,
decimalPlaces,
fieldOptions,
note,
noteVisibility,
},
dashboardUI: {dashboards},
sources,
services,
@ -445,6 +520,18 @@ const mapStateToProps = state => {
queryStatus,
script,
sourceLink,
visType,
thresholdsListType,
thresholdsListColors,
gaugeColors,
lineColors,
axes,
tableOptions,
timeFormat,
decimalPlaces,
fieldOptions,
note,
noteVisibility,
}
}

View File

@ -11,22 +11,47 @@ import defaultQueryConfig from 'src/utils/defaultQueryConfig'
// constants
import {timeRanges} from 'src/shared/data/timeRanges'
import {editor} from 'src/flux/constants'
import {
DEFAULT_THRESHOLDS_LIST_COLORS,
DEFAULT_GAUGE_COLORS,
} from 'src/shared/constants/thresholds'
import {DEFAULT_LINE_COLORS} from 'src/shared/constants/graphColorPalettes'
import {DEFAULT_AXES} from 'src/dashboards/constants/cellEditor'
import {
DEFAULT_TABLE_OPTIONS,
DEFAULT_TIME_FORMAT,
DEFAULT_DECIMAL_PLACES,
DEFAULT_FIELD_OPTIONS,
} from 'src/dashboards/constants'
// types
import {DEInitialState} from 'src/data_explorer/actions/queries'
import {CellQuery} from 'src/types/dashboards'
import {CellType} from 'src/types'
import {DEState} from 'src/types/dataExplorer'
import {CellQuery, ThresholdType, NoteVisibility} from 'src/types/dashboards'
const {lower, upper} = timeRanges.find(tr => tr.lower === 'now() - 1h')
export const initialState: DEInitialState = {
export const initialState: DEState = {
queryDrafts: null,
timeRange: {lower, upper},
queryStatus: {queryID: null, status: null},
script: editor.DEFAULT_SCRIPT,
sourceLink: '',
visType: CellType.Line,
thresholdsListType: ThresholdType.Text,
thresholdsListColors: DEFAULT_THRESHOLDS_LIST_COLORS,
gaugeColors: DEFAULT_GAUGE_COLORS,
lineColors: DEFAULT_LINE_COLORS,
axes: DEFAULT_AXES,
tableOptions: DEFAULT_TABLE_OPTIONS,
timeFormat: DEFAULT_TIME_FORMAT,
decimalPlaces: DEFAULT_DECIMAL_PLACES,
fieldOptions: DEFAULT_FIELD_OPTIONS,
note: '',
noteVisibility: NoteVisibility.Default,
}
export default (state = initialState, action: Action): DEInitialState => {
export default (state = initialState, action: Action): DEState => {
switch (action.type) {
case ActionType.LoadDE: {
const {timeRange, queries} = action.payload
@ -72,6 +97,7 @@ export default (state = initialState, action: Action): DEInitialState => {
case ActionType.UpdateQueryStatus: {
const {queryID, status} = action.payload
const queryStatus = {queryID, status}
return {...state, queryStatus}
}
@ -86,6 +112,82 @@ export default (state = initialState, action: Action): DEInitialState => {
return {...state, sourceLink}
}
case ActionType.ChangeVisualizationType: {
const {cellType} = action.payload
return {...state, visType: cellType}
}
case ActionType.UpdateThresholdsListColors: {
const {thresholdsListColors} = action.payload
return {...state, thresholdsListColors}
}
case ActionType.UpdateThresholdsListType: {
const {thresholdsListType} = action.payload
const thresholdsListColors = state.thresholdsListColors.map(color => {
return {...color, type: thresholdsListType}
})
return {...state, thresholdsListColors, thresholdsListType}
}
case ActionType.UpdateGaugeColors: {
const {gaugeColors} = action.payload
return {...state, gaugeColors}
}
case ActionType.UpdateAxes: {
const {axes} = action.payload
return {...state, axes}
}
case ActionType.UpdateTableOptions: {
const {tableOptions} = action.payload
return {...state, tableOptions}
}
case ActionType.ChangeTimeFormat: {
const {timeFormat} = action.payload
return {...state, timeFormat}
}
case ActionType.ChangeDecimalPlaces: {
const {decimalPlaces} = action.payload
return {...state, decimalPlaces}
}
case ActionType.UpdateFieldOptions: {
const {fieldOptions} = action.payload
return {...state, fieldOptions}
}
case ActionType.UpdateLineColors: {
const {lineColors} = action.payload
return {...state, lineColors}
}
case ActionType.UpdateNote: {
const {note} = action.payload
return {...state, note}
}
case ActionType.UpdateNoteVisibility: {
const {noteVisibility} = action.payload
return {...state, noteVisibility}
}
}
return state

View File

@ -5,8 +5,22 @@ import {
notifyLoadLocalSettingsFailed,
} from 'src/shared/copy/notifications'
import {
DEFAULT_THRESHOLDS_LIST_COLORS,
DEFAULT_GAUGE_COLORS,
} from 'src/shared/constants/thresholds'
import {DEFAULT_LINE_COLORS} from 'src/shared/constants/graphColorPalettes'
import {DEFAULT_AXES} from 'src/dashboards/constants/cellEditor'
import {
DEFAULT_TABLE_OPTIONS,
DEFAULT_TIME_FORMAT,
DEFAULT_DECIMAL_PLACES,
DEFAULT_FIELD_OPTIONS,
} from 'src/dashboards/constants'
import {editor} from 'src/flux/constants'
import {CellType} from 'src/types'
import {ThresholdType, NoteVisibility} from 'src/types/dashboards'
import {LocalStorage} from 'src/types/localStorage'
const VERSION = process.env.npm_package_version
@ -86,6 +100,22 @@ export const saveToLocalStorage = ({
sourceLink: dataExplorer.sourceLink || '',
queryStatus: dataExplorer.queryStatus || {},
script: dataExplorer.script || editor.DEFAULT_SCRIPT,
visType: dataExplorer.visType || CellType.Line,
thresholdsListType:
dataExplorer.thresholdsListType || ThresholdType.Text,
thresholdsListColors:
dataExplorer.thresholdsListColors ||
DEFAULT_THRESHOLDS_LIST_COLORS,
gaugeColors: dataExplorer.gaugeColors || DEFAULT_GAUGE_COLORS,
lineColors: dataExplorer.lineColors || DEFAULT_LINE_COLORS,
axes: dataExplorer.axes || DEFAULT_AXES,
tableOptions: dataExplorer.tableOptions || DEFAULT_TABLE_OPTIONS,
timeFormat: dataExplorer.timeFormat || DEFAULT_TIME_FORMAT,
decimalPlaces:
dataExplorer.decimalPlaces || DEFAULT_DECIMAL_PLACES,
fieldOptions: dataExplorer.fieldOptions || DEFAULT_FIELD_OPTIONS,
noteVisibility:
dataExplorer.noteVisibility || NoteVisibility.Default,
},
script,
logs: {

View File

@ -0,0 +1,299 @@
// Constants
import {QueryUpdateState} from 'src/shared/actions/queries'
// Types
import {ActionType as CEOActionType} from 'src/dashboards/actions/cellEditorOverlay'
import {ActionType as DEActionType} from 'src/data_explorer/actions/queries'
import {ColorNumber, ColorString} from 'src/types/colors'
import {
DecimalPlaces,
FieldOption,
Axes,
CellType,
ThresholdType,
TableOptions,
NoteVisibility,
} from 'src/types/dashboards'
export interface ChangeVisualizationTypeAction {
type: CEOActionType.ChangeCellType | DEActionType.ChangeVisualizationType
payload: {
cellType: CellType
}
}
export interface UpdateThresholdsListColorsAction {
type:
| CEOActionType.UpdateThresholdsListColors
| DEActionType.UpdateThresholdsListColors
payload: {
thresholdsListColors: ColorNumber[]
}
}
export interface UpdateThresholdsListTypeAction {
type:
| CEOActionType.UpdateThresholdsListType
| DEActionType.UpdateThresholdsListType
payload: {
thresholdsListType: ThresholdType
}
}
export interface UpdateGaugeColorsAction {
type: CEOActionType.UpdateGaugeColors | DEActionType.UpdateGaugeColors
payload: {
gaugeColors: ColorNumber[]
}
}
export interface UpdateAxesAction {
type: CEOActionType.UpdateAxes | DEActionType.UpdateAxes
payload: {
axes: Axes
}
}
export interface UpdateTableOptionsAction {
type: CEOActionType.UpdateTableOptions | DEActionType.UpdateTableOptions
payload: {
tableOptions: TableOptions
}
}
export interface UpdateLineColorsAction {
type: CEOActionType.UpdateLineColors | DEActionType.UpdateLineColors
payload: {
lineColors: ColorString[]
}
}
export interface ChangeTimeFormatAction {
type: CEOActionType.ChangeTimeFormat | DEActionType.ChangeTimeFormat
payload: {
timeFormat: string
}
}
export interface ChangeDecimalPlacesAction {
type: CEOActionType.ChangeDecimalPlaces | DEActionType.ChangeDecimalPlaces
payload: {
decimalPlaces: DecimalPlaces
}
}
export interface UpdateFieldOptionsAction {
type: CEOActionType.UpdateFieldOptions | DEActionType.UpdateFieldOptions
payload: {
fieldOptions: FieldOption[]
}
}
export interface UpdateNoteAction {
type: CEOActionType.UpdateCellNote | DEActionType.UpdateNote
payload: {
note: string
}
}
export interface UpdateNoteVisibilityAction {
type:
| CEOActionType.UpdateCellNoteVisibility
| DEActionType.UpdateNoteVisibility
payload: {
noteVisibility: NoteVisibility
}
}
export const updateVisType = (
cellType: CellType,
stateToUpdate: QueryUpdateState
): ChangeVisualizationTypeAction => {
const type =
stateToUpdate === QueryUpdateState.CEO
? CEOActionType.ChangeCellType
: DEActionType.ChangeVisualizationType
return {
type,
payload: {
cellType,
},
} as ChangeVisualizationTypeAction
}
export const updateNote = (
note: string,
stateToUpdate: QueryUpdateState
): UpdateNoteAction => {
const type =
stateToUpdate === QueryUpdateState.CEO
? CEOActionType.UpdateCellNote
: DEActionType.UpdateNote
return {
type,
payload: {
note,
},
} as UpdateNoteAction
}
export const updateNoteVisibility = (
noteVisibility: NoteVisibility,
stateToUpdate: QueryUpdateState
): UpdateNoteVisibilityAction => {
const type =
stateToUpdate === QueryUpdateState.CEO
? CEOActionType.UpdateCellNoteVisibility
: DEActionType.UpdateNoteVisibility
return {
type,
payload: {
noteVisibility,
},
} as UpdateNoteVisibilityAction
}
export const updateThresholdsListColors = (
thresholdsListColors: ColorNumber[],
stateToUpdate: QueryUpdateState
): UpdateThresholdsListColorsAction => {
const type =
stateToUpdate === QueryUpdateState.CEO
? CEOActionType.UpdateThresholdsListColors
: DEActionType.UpdateThresholdsListColors
return {
type,
payload: {
thresholdsListColors,
},
} as UpdateThresholdsListColorsAction
}
export const updateThresholdsListType = (
thresholdsListType: ThresholdType,
stateToUpdate: QueryUpdateState
): UpdateThresholdsListTypeAction => {
const type =
stateToUpdate === QueryUpdateState.CEO
? CEOActionType.UpdateThresholdsListType
: DEActionType.UpdateThresholdsListType
return {
type,
payload: {
thresholdsListType,
},
} as UpdateThresholdsListTypeAction
}
export const updateGaugeColors = (
gaugeColors: ColorNumber[],
stateToUpdate: QueryUpdateState
): UpdateGaugeColorsAction => {
const type =
stateToUpdate === QueryUpdateState.CEO
? CEOActionType.UpdateGaugeColors
: DEActionType.UpdateGaugeColors
return {
type,
payload: {
gaugeColors,
},
} as UpdateGaugeColorsAction
}
export const updateAxes = (
axes: Axes,
stateToUpdate: QueryUpdateState
): UpdateAxesAction => {
const type =
stateToUpdate === QueryUpdateState.CEO
? CEOActionType.UpdateAxes
: DEActionType.UpdateAxes
return {
type,
payload: {
axes,
},
} as UpdateAxesAction
}
export const updateTableOptions = (
tableOptions: TableOptions,
stateToUpdate: QueryUpdateState
): UpdateTableOptionsAction => {
const type =
stateToUpdate === QueryUpdateState.CEO
? CEOActionType.UpdateTableOptions
: DEActionType.UpdateTableOptions
return {
type,
payload: {
tableOptions,
},
} as UpdateTableOptionsAction
}
export const updateLineColors = (
lineColors: ColorString[],
stateToUpdate: QueryUpdateState
): UpdateLineColorsAction => {
const type =
stateToUpdate === QueryUpdateState.CEO
? CEOActionType.UpdateLineColors
: DEActionType.UpdateLineColors
return {
type,
payload: {
lineColors,
},
} as UpdateLineColorsAction
}
export const updateTimeFormat = (
timeFormat: string,
stateToUpdate: QueryUpdateState
): ChangeTimeFormatAction => {
const type =
stateToUpdate === QueryUpdateState.CEO
? CEOActionType.ChangeTimeFormat
: DEActionType.ChangeTimeFormat
return {
type,
payload: {
timeFormat,
},
} as ChangeTimeFormatAction
}
export const updateDecimalPlaces = (
decimalPlaces: DecimalPlaces,
stateToUpdate: QueryUpdateState
): ChangeDecimalPlacesAction => {
const type =
stateToUpdate === QueryUpdateState.CEO
? CEOActionType.ChangeDecimalPlaces
: DEActionType.ChangeDecimalPlaces
return {
type,
payload: {
decimalPlaces,
},
} as ChangeDecimalPlacesAction
}
export const updateFieldOptions = (
fieldOptions: FieldOption[],
stateToUpdate: QueryUpdateState
): UpdateFieldOptionsAction => {
const type =
stateToUpdate === QueryUpdateState.CEO
? CEOActionType.UpdateFieldOptions
: DEActionType.UpdateFieldOptions
return {
type,
payload: {
fieldOptions,
},
} as UpdateFieldOptionsAction
}

View File

@ -14,7 +14,7 @@ import {timeSeriesToTableGraph} from 'src/utils/timeSeriesTransformers'
import {PREDEFINED_TEMP_VARS} from 'src/shared/constants'
import {Cell, CellQuery, Template} from 'src/types/'
import {CellNoteVisibility} from 'src/types/dashboards'
import {NoteVisibility} from 'src/types/dashboards'
import {TimeSeriesServerResponse} from 'src/types/series'
import {CellType} from 'src/types/dashboards'
@ -71,7 +71,7 @@ export default class LayoutCell extends Component<Props> {
return (
!!cell.note &&
cell.type !== CellType.Note &&
cell.noteVisibility === CellNoteVisibility.Default
cell.noteVisibility === NoteVisibility.Default
)
}

View File

@ -10,14 +10,14 @@ import FancyScrollbar from 'src/shared/components/FancyScrollbar'
import {humanizeNote} from 'src/dashboards/utils/notes'
// Types
import {CellType, CellNoteVisibility} from 'src/types/dashboards'
import {CellType, NoteVisibility} from 'src/types/dashboards'
interface Props {
note: string
cellX: number
cellY: number
cellType: CellType
visibility: CellNoteVisibility
visibility: NoteVisibility
}
class LayoutCellNote extends Component<Props> {
@ -28,7 +28,7 @@ class LayoutCellNote extends Component<Props> {
!note ||
note === '' ||
cellType === CellType.Note ||
visibility === CellNoteVisibility.ShowWhenNoData
visibility === NoteVisibility.ShowWhenNoData
) {
return null
}

View File

@ -4,7 +4,7 @@ import {bindActionCreators} from 'redux'
import ColorScaleDropdown from 'src/shared/components/ColorScaleDropdown'
import {updateLineColors} from 'src/dashboards/actions/cellEditorOverlay'
import {updateLineColors} from 'src/shared/actions/visualizations'
import {ColorNumber} from 'src/types/colors'
import {ErrorHandling} from 'src/shared/decorators/errors'

View File

@ -25,13 +25,14 @@ import {AutoRefresher} from 'src/utils/AutoRefresher'
import {setHoverTime} from 'src/dashboards/actions'
// Types
import {QueryUpdateState} from 'src/shared/actions/queries'
import {ColorString} from 'src/types/colors'
import {Source, Axes, TimeRange, Template, Query, CellType} from 'src/types'
import {
TableOptions,
FieldOption,
DecimalPlaces,
CellNoteVisibility,
NoteVisibility,
} from 'src/types/dashboards'
import {GrabDataForDownloadHandler} from 'src/types/layout'
@ -48,7 +49,6 @@ interface Props {
type: CellType
cellID: string
inView: boolean
isInCEO: boolean
timeFormat: string
cellHeight: number
staticLegend: boolean
@ -61,7 +61,8 @@ interface Props {
handleSetHoverTime: () => void
grabDataForDownload?: GrabDataForDownloadHandler
cellNote: string
cellNoteVisibility: CellNoteVisibility
cellNoteVisibility: NoteVisibility
editorLocation?: QueryUpdateState
}
class RefreshingGraph extends PureComponent<Props> {
@ -79,7 +80,7 @@ class RefreshingGraph extends PureComponent<Props> {
if (!this.timeSeries.current) {
return
}
if (this.props.isInCEO) {
if (this.props.editorLocation) {
this.timeSeries.current.forceUpdate()
}
}
@ -170,19 +171,19 @@ class RefreshingGraph extends PureComponent<Props> {
decimalPlaces,
manualRefresh,
handleSetHoverTime,
isInCEO,
editorLocation,
} = this.props
return (
<TableGraph
data={data}
colors={colors}
isInCEO={isInCEO}
key={manualRefresh}
tableOptions={tableOptions}
fieldOptions={fieldOptions}
timeFormat={timeFormat}
decimalPlaces={decimalPlaces}
editorLocation={editorLocation}
handleSetHoverTime={handleSetHoverTime}
/>
)

View File

@ -13,7 +13,8 @@ import {
computeFieldOptions,
transformTableData,
} from 'src/dashboards/utils/tableGraph'
import {updateFieldOptions} from 'src/dashboards/actions/cellEditorOverlay'
import {updateFieldOptions} from 'src/shared/actions/visualizations'
import {QueryUpdateState} from 'src/shared/actions/queries'
import {DEFAULT_TIME_FIELD} from 'src/dashboards/constants'
import {
ASCENDING,
@ -61,10 +62,10 @@ interface Props {
decimalPlaces: DecimalPlaces
fieldOptions: FieldOption[]
hoverTime: string
handleUpdateFieldOptions: (fieldOptions: FieldOption[]) => void
handleUpdateFieldOptions: typeof updateFieldOptions
handleSetHoverTime: (hovertime: string) => void
colors: ColorString
isInCEO: boolean
editorLocation?: QueryUpdateState
}
interface State {
@ -366,9 +367,9 @@ class TableGraph extends Component<Props, State> {
}
private handleUpdateFieldOptions = (fieldOptions: FieldOption[]): void => {
const {isInCEO, handleUpdateFieldOptions} = this.props
if (isInCEO) {
handleUpdateFieldOptions(fieldOptions)
const {handleUpdateFieldOptions, editorLocation} = this.props
if (editorLocation) {
handleUpdateFieldOptions(fieldOptions, editorLocation)
}
}

View File

@ -1,14 +1,16 @@
// Libraries
import React, {PureComponent} from 'react'
import {connect} from 'react-redux'
import {bindActionCreators} from 'redux'
import _ from 'lodash'
import uuid from 'uuid'
// Comonents
import Threshold from 'src/dashboards/components/Threshold'
import ColorDropdown from 'src/shared/components/ColorDropdown'
import {updateThresholdsListColors} from 'src/dashboards/actions/cellEditorOverlay'
// Decorators
import {ErrorHandling} from 'src/shared/decorators/errors'
// Types
import {ColorNumber} from 'src/types/colors'
import {
@ -18,14 +20,13 @@ import {
MAX_THRESHOLDS,
THRESHOLD_TYPE_BASE,
} from 'src/shared/constants/thresholds'
import {ErrorHandling} from 'src/shared/decorators/errors'
interface Props {
onResetFocus: () => void
showListHeading: boolean
showListHeading?: boolean
thresholdsListType: string
thresholdsListColors: ColorNumber[]
handleUpdateThresholdsListColors: (c: ColorNumber[]) => void
onUpdateThresholdsListColors: (c: ColorNumber[]) => void
}
@ErrorHandling
@ -93,7 +94,7 @@ class ThresholdsList extends PureComponent<Props> {
const {
thresholdsListColors,
thresholdsListType,
handleUpdateThresholdsListColors,
onUpdateThresholdsListColors,
onResetFocus,
} = this.props
@ -124,12 +125,12 @@ class ThresholdsList extends PureComponent<Props> {
color => color.value
)
handleUpdateThresholdsListColors(updatedColors)
onUpdateThresholdsListColors(updatedColors)
onResetFocus()
}
private handleChangeBaseColor = updatedColor => {
const {handleUpdateThresholdsListColors} = this.props
const {onUpdateThresholdsListColors} = this.props
const {hex, name} = updatedColor
const thresholdsListColors = this.props.thresholdsListColors.map(
@ -137,22 +138,22 @@ class ThresholdsList extends PureComponent<Props> {
color.id === THRESHOLD_TYPE_BASE ? {...color, hex, name} : color
)
handleUpdateThresholdsListColors(thresholdsListColors)
onUpdateThresholdsListColors(thresholdsListColors)
}
private handleChooseColor = updatedColor => {
const {handleUpdateThresholdsListColors} = this.props
const {onUpdateThresholdsListColors} = this.props
const thresholdsListColors = this.props.thresholdsListColors.map(
color => (color.id === updatedColor.id ? updatedColor : color)
)
handleUpdateThresholdsListColors(thresholdsListColors)
onUpdateThresholdsListColors(thresholdsListColors)
}
private handleDeleteThreshold = threshold => {
const {
handleUpdateThresholdsListColors,
onUpdateThresholdsListColors,
onResetFocus,
thresholdsListColors,
} = this.props
@ -164,18 +165,18 @@ class ThresholdsList extends PureComponent<Props> {
color => color.value
)
handleUpdateThresholdsListColors(sortedColors)
onUpdateThresholdsListColors(sortedColors)
onResetFocus()
}
private handleUpdateColorValue = (threshold, value) => {
const {handleUpdateThresholdsListColors} = this.props
const {onUpdateThresholdsListColors} = this.props
const thresholdsListColors = this.props.thresholdsListColors.map(
color => (color.id === threshold.id ? {...color, value} : color)
)
handleUpdateThresholdsListColors(thresholdsListColors)
onUpdateThresholdsListColors(thresholdsListColors)
}
private handleValidateColorValue = (__, targetValue) => {
@ -186,17 +187,4 @@ class ThresholdsList extends PureComponent<Props> {
}
}
const mapStateToProps = ({
cellEditorOverlay: {thresholdsListType, thresholdsListColors},
}) => ({
thresholdsListType,
thresholdsListColors,
})
const mapDispatchToProps = dispatch => ({
handleUpdateThresholdsListColors: bindActionCreators(
updateThresholdsListColors,
dispatch
),
})
export default connect(mapStateToProps, mapDispatchToProps)(ThresholdsList)
export default ThresholdsList

View File

@ -1,13 +1,9 @@
// Libraries
import React, {Component} from 'react'
import {connect} from 'react-redux'
// Components
import {Radio, ButtonShape} from 'src/reusable_ui'
// Actions
import {updateThresholdsListType} from 'src/dashboards/actions/cellEditorOverlay'
// Constants
import {
THRESHOLD_TYPE_TEXT,
@ -17,15 +13,14 @@ import {
// Decorators
import {ErrorHandling} from 'src/shared/decorators/errors'
interface PropsFromRedux {
thresholdsListType: string
}
interface PropsFromParent {
containerClass: string
handleUpdateThresholdsListType: (newType: string) => void
}
// Types
import {ThresholdType} from 'src/types/dashboards'
type Props = PropsFromRedux & PropsFromParent
interface Props {
containerClass: string
thresholdsListType: ThresholdType
onUpdateThresholdsListType: (newType: ThresholdType) => void
}
@ErrorHandling
class ThresholdsListTypeToggle extends Component<Props> {
@ -33,7 +28,7 @@ class ThresholdsListTypeToggle extends Component<Props> {
const {
containerClass,
thresholdsListType,
handleUpdateThresholdsListType,
onUpdateThresholdsListType,
} = this.props
return (
@ -44,7 +39,7 @@ class ThresholdsListTypeToggle extends Component<Props> {
id="threshold-list-type--background"
value={THRESHOLD_TYPE_BG}
active={thresholdsListType === THRESHOLD_TYPE_BG}
onClick={handleUpdateThresholdsListType}
onClick={onUpdateThresholdsListType}
titleText="Apply coloration to cell background"
>
Background
@ -53,7 +48,7 @@ class ThresholdsListTypeToggle extends Component<Props> {
id="threshold-list-type--text"
value={THRESHOLD_TYPE_TEXT}
active={thresholdsListType === THRESHOLD_TYPE_TEXT}
onClick={handleUpdateThresholdsListType}
onClick={onUpdateThresholdsListType}
titleText="Apply coloration to cell text"
>
Text
@ -64,16 +59,4 @@ class ThresholdsListTypeToggle extends Component<Props> {
}
}
const mapStateToProps = ({
cellEditorOverlay: {thresholdsListType},
}): PropsFromRedux => ({
thresholdsListType,
})
const mapDispatchToProps = {
handleUpdateThresholdsListType: updateThresholdsListType,
}
export default connect(mapStateToProps, mapDispatchToProps)(
ThresholdsListTypeToggle
)
export default ThresholdsListTypeToggle

View File

@ -1,6 +1,5 @@
// Libraries
import React, {Component} from 'react'
import {connect} from 'react-redux'
import classnames from 'classnames'
// Components
@ -8,14 +7,8 @@ import {Controlled as ReactCodeMirror} from 'react-codemirror2'
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
import {SlideToggle, ComponentSize} from 'src/reusable_ui'
// Actions
import {
updateCellNote,
UpdateCellNoteVisibility,
} from 'src/dashboards/actions/cellEditorOverlay'
// Types
import {CellNoteVisibility} from 'src/types/dashboards'
import {NoteVisibility} from 'src/types/dashboards'
// Utils
import {humanizeNote} from 'src/dashboards/utils/notes'
@ -25,9 +18,9 @@ import {ErrorHandling} from 'src/shared/decorators/errors'
interface Props {
note: string
noteVisibility: CellNoteVisibility
handleUpdateCellNote: (note: string) => void
handleUpdateCellNoteVisibility: (noteVisibility: CellNoteVisibility) => void
noteVisibility: NoteVisibility
onUpdateNote: (note: string) => void
onUpdateNoteVisibility: (noteVisibility: NoteVisibility) => void
}
interface State {
@ -41,7 +34,7 @@ class CellNoteEditor extends Component<Props, State> {
super(props)
this.state = {
noteDraft: props.note,
noteDraft: props.note || '',
editorIsFocused: false,
}
}
@ -70,7 +63,7 @@ class CellNoteEditor extends Component<Props, State> {
<SlideToggle
size={ComponentSize.ExtraSmall}
onChange={this.handleSlideToggle}
active={noteVisibility === CellNoteVisibility.ShowWhenNoData}
active={noteVisibility === NoteVisibility.ShowWhenNoData}
/>
<label>Display note in cell when query returns no results</label>
</div>
@ -92,12 +85,12 @@ class CellNoteEditor extends Component<Props, State> {
}
private handleSlideToggle = (): void => {
const {noteVisibility, handleUpdateCellNoteVisibility} = this.props
const {noteVisibility, onUpdateNoteVisibility} = this.props
if (noteVisibility === CellNoteVisibility.Default) {
handleUpdateCellNoteVisibility(CellNoteVisibility.ShowWhenNoData)
if (noteVisibility === NoteVisibility.Default) {
onUpdateNoteVisibility(NoteVisibility.ShowWhenNoData)
} else {
handleUpdateCellNoteVisibility(CellNoteVisibility.Default)
onUpdateNoteVisibility(NoteVisibility.Default)
}
}
@ -106,11 +99,11 @@ class CellNoteEditor extends Component<Props, State> {
}
private handleBlur = (): void => {
const {handleUpdateCellNote} = this.props
const {onUpdateNote} = this.props
const {noteDraft} = this.state
this.setState({editorIsFocused: false})
handleUpdateCellNote(noteDraft)
onUpdateNote(noteDraft)
}
private onTouchStart = (): void => {}
@ -126,18 +119,4 @@ class CellNoteEditor extends Component<Props, State> {
}
}
const mstp = ({
cellEditorOverlay: {
cell: {note, noteVisibility},
},
}) => ({
note,
noteVisibility,
})
const mdtp = {
handleUpdateCellNote: updateCellNote,
handleUpdateCellNoteVisibility: UpdateCellNoteVisibility,
}
export default connect(mstp, mdtp)(CellNoteEditor)
export default CellNoteEditor

View File

@ -74,12 +74,13 @@ import {
CellType,
FieldOption,
TableOptions,
ThresholdType,
DecimalPlaces,
CellNoteVisibility,
NoteVisibility,
} from 'src/types/dashboards'
import {ColorNumber, ColorString} from 'src/types/colors'
interface VisualizationOptions {
export interface VisualizationOptions {
type: CellType
axes: Axes | null
tableOptions: TableOptions
@ -87,8 +88,9 @@ interface VisualizationOptions {
timeFormat: string
decimalPlaces: DecimalPlaces
note: string
noteVisibility: CellNoteVisibility
noteVisibility: NoteVisibility
thresholdsListColors: ColorNumber[]
thresholdsListType: ThresholdType
gaugeColors: ColorNumber[]
lineColors: ColorString[]
}
@ -130,7 +132,7 @@ interface Props {
timeRange: TimeRange,
stateToUpdate: QueryUpdateState
) => void
visualizationOptions?: VisualizationOptions
visualizationOptions: VisualizationOptions
manualRefresh?: number
queryStatus: QueryStatus
}
@ -289,11 +291,10 @@ class TimeMachine extends PureComponent<Props, State> {
script,
timeRange,
templates,
isInCEO,
source,
isStaticLegend,
visualizationOptions,
manualRefresh,
visualizationOptions,
} = this.props
const {autoRefresher} = this.state
@ -311,8 +312,8 @@ class TimeMachine extends PureComponent<Props, State> {
queryConfigs={this.queriesWorkingDraft}
editQueryStatus={this.handleEditQueryStatus}
staticLegend={isStaticLegend}
isInCEO={isInCEO}
manualRefresh={manualRefresh}
editorLocation={this.stateToUpdate}
{...visualizationOptions}
/>
</div>
@ -324,7 +325,12 @@ class TimeMachine extends PureComponent<Props, State> {
}
private get editorTab() {
const {onResetFocus, isStaticLegend, onToggleStaticLegend} = this.props
const {
onResetFocus,
isStaticLegend,
onToggleStaticLegend,
visualizationOptions,
} = this.props
const {activeEditorTab} = this.state
if (activeEditorTab === CEOTabs.Queries) {
@ -340,6 +346,8 @@ class TimeMachine extends PureComponent<Props, State> {
onToggleStaticLegend={onToggleStaticLegend}
staticLegend={isStaticLegend}
onResetFocus={onResetFocus}
stateToUpdate={this.stateToUpdate}
{...visualizationOptions}
/>
)
}

View File

@ -20,7 +20,7 @@ import {GrabDataForDownloadHandler} from 'src/types/layout'
// Utils
import {GlobalAutoRefresher, AutoRefresher} from 'src/utils/AutoRefresher'
import {CellNoteVisibility} from 'src/types/dashboards'
import {NoteVisibility} from 'src/types/dashboards'
// Components
import MarkdownCell from 'src/shared/components/MarkdownCell'
@ -45,7 +45,7 @@ interface Props {
editQueryStatus?: () => void
grabDataForDownload?: GrabDataForDownloadHandler
cellNote?: string
cellNoteVisibility?: CellNoteVisibility
cellNoteVisibility?: NoteVisibility
}
interface State {
@ -239,7 +239,7 @@ class TimeSeries extends Component<Props, State> {
}
if (!hasValues) {
if (cellNoteVisibility === CellNoteVisibility.ShowWhenNoData) {
if (cellNoteVisibility === NoteVisibility.ShowWhenNoData) {
return <MarkdownCell text={cellNote} />
}

View File

@ -59,7 +59,7 @@ export interface DecimalPlaces {
digits: number
}
export enum CellNoteVisibility {
export enum NoteVisibility {
Default = 'default',
ShowWhenNoData = 'showWhenNoData',
}
@ -84,7 +84,7 @@ export interface Cell {
isWidget?: boolean
inView: boolean
note: string
noteVisibility: CellNoteVisibility
noteVisibility: NoteVisibility
}
export enum CellType {

View File

@ -1,5 +1,35 @@
import {ThresholdColor, GaugeColor, LineColor} from 'src/types/colors'
import {TimeRange, CellQuery, QueryStatus, CellType, Axes} from 'src/types'
import {
DecimalPlaces,
FieldOption,
ThresholdType,
TableOptions,
NoteVisibility,
} from 'src/types/dashboards'
// Write Data Modes
export enum WriteDataMode {
Manual = 'Manual Entry',
File = 'File Upload',
}
export interface DEState {
queryDrafts: CellQuery[]
timeRange: TimeRange
queryStatus: QueryStatus
script: string
sourceLink: string
thresholdsListType: ThresholdType
thresholdsListColors: ThresholdColor[]
gaugeColors: GaugeColor[]
lineColors: LineColor[]
visType: CellType
axes: Axes
tableOptions: TableOptions
timeFormat: string
decimalPlaces: DecimalPlaces
fieldOptions: FieldOption[]
note: string
noteVisibility: NoteVisibility
}

View File

@ -1,11 +1,12 @@
import {QueryConfig, TimeRange, CellQuery, QueryStatus} from 'src/types'
import {QueryConfig, TimeRange} from 'src/types'
import {DEState} from 'src/types/dataExplorer'
import {LogsState} from 'src/types/logs'
export interface LocalStorage {
VERSION: VERSION
app: App
dashTimeV1: DashTimeV1
dataExplorer: DataExplorer
dataExplorer: DEState
dataExplorerQueryConfigs: DataExplorerQueryConfigs
timeRange: TimeRange
script: string
@ -23,14 +24,6 @@ export interface DashTimeV1 {
ranges: DashboardTimeRange[]
}
export interface DataExplorer {
queryDrafts: CellQuery[]
timeRange: TimeRange
queryStatus: QueryStatus
script: string
sourceLink: string
}
export interface DataExplorerQueryConfigs {
[id: string]: QueryConfig
}

View File

@ -17,11 +17,9 @@ export interface TimeSeriesToDyGraphReturnType {
}
export const timeSeriesToDygraphWork = (
raw: TimeSeriesServerResponse[],
pathname: string = ''
raw: TimeSeriesServerResponse[]
): TimeSeriesToDyGraphReturnType => {
const isTable = false
const isInDataExplorer = pathname.includes('data-explorer')
const {sortedLabels, sortedTimeSeries} = groupByTimeSeriesTransform(
raw,
isTable
@ -40,11 +38,10 @@ export const timeSeriesToDygraphWork = (
const dygraphSeries = fastReduce<Label, DygraphSeries>(
sortedLabels,
(acc, {label, responseIndex}) => {
if (!isInDataExplorer) {
acc[label] = {
axis: responseIndex === 0 ? 'y' : 'y2',
}
acc[label] = {
axis: responseIndex === 0 ? 'y' : 'y2',
}
return acc
},
{}
@ -54,9 +51,9 @@ export const timeSeriesToDygraphWork = (
}
const timeSeriesToDygraph = async msg => {
const {raw, pathname} = await fetchData(msg)
const {raw} = await fetchData(msg)
return timeSeriesToDygraphWork(raw, pathname)
return timeSeriesToDygraphWork(raw)
}
export default timeSeriesToDygraph

View File

@ -11,10 +11,12 @@ import ThresholdsList from 'src/shared/components/ThresholdsList'
import ThresholdsListTypeToggle from 'src/shared/components/ThresholdsListTypeToggle'
const defaultProps = {
handleUpdateTableOptions: () => {},
handleUpdateFieldOptions: () => {},
handleChangeTimeFormat: () => {},
handleChangeDecimalPlaces: () => {},
onUpdateTableOptions: () => {},
onUpdateFieldOptions: () => {},
onUpdateTimeFormat: () => {},
onUpdateDecimalPlaces: () => {},
onUpdateThresholdsListColors: () => {},
onUpdateThresholdsListType: () => {},
onResetFocus: () => {},
queryConfigs: [],
tableOptions: {
@ -28,6 +30,8 @@ const defaultProps = {
isEnforced: true,
digits: 2,
},
thresholdsListType: null,
thresholdsListColors: [],
}
const setup = (override = {}) => {

View File

@ -5,15 +5,17 @@ import reducer, {initialState} from 'src/dashboards/reducers/cellEditorOverlay'
import {
loadCEO,
clearCEO,
changeCellType,
renameCell,
Action,
} from 'src/dashboards/actions/cellEditorOverlay'
import {
updateVisType,
updateThresholdsListColors,
updateThresholdsListType,
updateGaugeColors,
updateLineColors,
updateAxes,
Action,
} from 'src/dashboards/actions/cellEditorOverlay'
} from 'src/shared/actions/visualizations'
import {
updateEditorTimeRange,
updateQueryDrafts,
@ -77,7 +79,11 @@ describe('Dashboards.Reducers.cellEditorOverlay', () => {
})
it('should change the cell editor visualization type', () => {
const actual = reducer(initialState, changeCellType(defaultCell.type))
const action = updateVisType(
defaultCell.type,
QueryUpdateState.CEO
) as Action
const actual = reducer(initialState, action)
const expected = defaultCell.type
expect(actual.cell.type).toBe(expected)
@ -91,34 +97,41 @@ describe('Dashboards.Reducers.cellEditorOverlay', () => {
})
it('should update the cell single stat colors', () => {
const actual = reducer(
initialState,
updateThresholdsListColors(defaultThresholdsListColors)
)
const action = updateThresholdsListColors(
defaultThresholdsListColors,
QueryUpdateState.CEO
) as Action
const actual = reducer(initialState, action)
const expected = defaultThresholdsListColors
expect(actual.thresholdsListColors).toBe(expected)
})
it('should toggle the single stat type', () => {
const actual = reducer(
initialState,
updateThresholdsListType(defaultThresholdsListType)
)
const action = updateThresholdsListType(
defaultThresholdsListType,
QueryUpdateState.CEO
) as Action
const actual = reducer(initialState, action)
const expected = defaultThresholdsListType
expect(actual.thresholdsListType).toBe(expected)
})
it('should update the cell gauge colors', () => {
const actual = reducer(initialState, updateGaugeColors(defaultGaugeColors))
const action = updateGaugeColors(
defaultGaugeColors,
QueryUpdateState.CEO
) as Action
const actual = reducer(initialState, action)
const expected = defaultGaugeColors
expect(actual.gaugeColors).toBe(expected)
})
it('should update the cell axes', () => {
const actual = reducer(initialState, updateAxes(axes))
const action = updateAxes(axes, QueryUpdateState.CEO) as Action
const actual = reducer(initialState, action)
const expected = axes
const actualCell = actual.cell as Cell
@ -126,7 +139,11 @@ describe('Dashboards.Reducers.cellEditorOverlay', () => {
})
it('should update the cell line graph colors', () => {
const actual = reducer(initialState, updateLineColors(defaultLineColors))
const action = updateLineColors(
defaultLineColors,
QueryUpdateState.CEO
) as Action
const actual = reducer(initialState, action)
const expected = defaultLineColors
expect(actual.lineColors).toBe(expected)

View File

@ -1,5 +1,6 @@
import React from 'react'
import {DataExplorer} from 'src/data_explorer/containers/DataExplorer'
import {CellType} from 'src/types'
import {shallow} from 'enzyme'
import {source, query, timeRange} from 'test/resources'
@ -58,6 +59,18 @@ const setup = () => {
notify: jest.fn(),
sourceLink: '',
updateSourceLink: jest.fn(),
thresholdsListType: null,
thresholdsListColors: [],
gaugeColors: [],
lineColors: [],
visType: CellType.Line,
axes: null,
tableOptions: null,
timeFormat: '',
decimalPlaces: null,
fieldOptions: [],
note: '',
noteVisibility: null,
}
const wrapper = shallow(<DataExplorer {...props} />)

View File

@ -18,7 +18,7 @@ import {
FieldOption,
DecimalPlaces,
CellType,
CellNoteVisibility,
NoteVisibility,
} from 'src/types/dashboards'
import {LineColor, ColorNumber} from 'src/types/colors'
import {ServerLogConfig, ServerColumn} from 'src/types/logs'
@ -206,7 +206,7 @@ export const cell: Cell = {
},
inView: true,
note: 'I am a note!',
noteVisibility: CellNoteVisibility.Default,
noteVisibility: NoteVisibility.Default,
}
export const fullTimeRange = {

View File

@ -9,7 +9,7 @@ import {
TemplateType,
TemplateValueType,
} from 'src/types'
import {CellNoteVisibility} from 'src/types/dashboards'
import {NoteVisibility} from 'src/types/dashboards'
export const role = {
name: '',
@ -698,5 +698,5 @@ export const cell: Cell = {
legend: {},
inView: true,
note: 'I am the greatest cell!',
noteVisibility: CellNoteVisibility.Default,
noteVisibility: NoteVisibility.Default,
}

View File

@ -212,49 +212,6 @@ describe('timeSeriesToDygraph', () => {
expect(actual).toEqual(expected)
})
it('it does not use multiple axes if being used for the DataExplorer', () => {
const influxResponse = [
{
response: {
results: [
{
statement_id: 0,
series: [
{
name: 'm1',
columns: ['time', 'f1'],
values: [[1000, 1], [2000, 2]],
},
],
},
],
},
},
{
response: {
results: [
{
statement_id: 0,
series: [
{
name: 'm1',
columns: ['time', 'f2'],
values: [[2000, 3], [4000, 4]],
},
],
},
],
},
},
]
const actual = timeSeriesToDygraph(influxResponse, 'data-explorer')
const expected = {}
expect(actual.dygraphSeries).toEqual(expected)
})
it('parses a raw InfluxDB response into a dygraph friendly data format', () => {
const influxResponse = [
{