Merge pull request #1352 from influxdata/line-display-options
Add display options ui for line graph typespull/10616/head
commit
b9ad495e58
|
@ -1,6 +1,6 @@
|
|||
import {DEFAULT_TABLE_OPTIONS} from 'src/dashboards/constants'
|
||||
import {stringifyColorValues} from 'src/shared/constants/colorOperations'
|
||||
import {ViewType, Axis} from 'src/types/v2/dashboards'
|
||||
import {ViewType, Axis, Axes} from 'src/types/v2/dashboards'
|
||||
import {Color} from 'src/types/colors'
|
||||
|
||||
export const initializeOptions = (type: ViewType) => {
|
||||
|
@ -29,6 +29,16 @@ 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,
|
||||
}
|
||||
|
||||
export const TOOLTIP_Y_VALUE_FORMAT =
|
||||
'<p><strong>K/M/B</strong> = Thousand / Million / Billion<br/><strong>K/M/G</strong> = Kilo / Mega / Giga </p>'
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
// Types
|
||||
import {TimeMachineState} from 'src/shared/reducers/v2/timeMachines'
|
||||
import {TimeRange, ViewType} from 'src/types/v2'
|
||||
import {Axes, DecimalPlaces} from 'src/types/v2/dashboards'
|
||||
import {Color} from 'src/types/colors'
|
||||
|
||||
export type Action =
|
||||
| SetActiveTimeMachineAction
|
||||
|
@ -8,6 +11,17 @@ export type Action =
|
|||
| SetTypeAction
|
||||
| SetDraftScriptAction
|
||||
| SubmitScriptAction
|
||||
| SetDecimalPlaces
|
||||
| SetAxes
|
||||
| SetStaticLegend
|
||||
| SetColors
|
||||
| SetYAxisLabel
|
||||
| SetYAxisMinBound
|
||||
| SetYAxisMaxBound
|
||||
| SetYAxisPrefix
|
||||
| SetYAxisSuffix
|
||||
| SetYAxisBase
|
||||
| SetYAxisScale
|
||||
|
||||
interface SetActiveTimeMachineAction {
|
||||
type: 'SET_ACTIVE_TIME_MACHINE'
|
||||
|
@ -72,3 +86,114 @@ interface SubmitScriptAction {
|
|||
export const submitScript = (): SubmitScriptAction => ({
|
||||
type: 'SUBMIT_SCRIPT',
|
||||
})
|
||||
interface SetAxes {
|
||||
type: 'SET_AXES'
|
||||
payload: {axes: Axes}
|
||||
}
|
||||
|
||||
export const setAxes = (axes: Axes): SetAxes => ({
|
||||
type: 'SET_AXES',
|
||||
payload: {axes},
|
||||
})
|
||||
|
||||
interface SetYAxisLabel {
|
||||
type: 'SET_Y_AXIS_LABEL'
|
||||
payload: {label: string}
|
||||
}
|
||||
|
||||
export const setYAxisLabel = (label: string): SetYAxisLabel => ({
|
||||
type: 'SET_Y_AXIS_LABEL',
|
||||
payload: {label},
|
||||
})
|
||||
|
||||
interface SetYAxisMinBound {
|
||||
type: 'SET_Y_AXIS_MIN_BOUND'
|
||||
payload: {min: string}
|
||||
}
|
||||
|
||||
export const setYAxisMinBound = (min: string): SetYAxisMinBound => ({
|
||||
type: 'SET_Y_AXIS_MIN_BOUND',
|
||||
payload: {min},
|
||||
})
|
||||
|
||||
interface SetYAxisMaxBound {
|
||||
type: 'SET_Y_AXIS_MAX_BOUND'
|
||||
payload: {max: string}
|
||||
}
|
||||
|
||||
export const setYAxisMaxBound = (max: string): SetYAxisMaxBound => ({
|
||||
type: 'SET_Y_AXIS_MAX_BOUND',
|
||||
payload: {max},
|
||||
})
|
||||
|
||||
interface SetYAxisPrefix {
|
||||
type: 'SET_Y_AXIS_PREFIX'
|
||||
payload: {prefix: string}
|
||||
}
|
||||
|
||||
export const setYAxisPrefix = (prefix: string): SetYAxisPrefix => ({
|
||||
type: 'SET_Y_AXIS_PREFIX',
|
||||
payload: {prefix},
|
||||
})
|
||||
|
||||
interface SetYAxisSuffix {
|
||||
type: 'SET_Y_AXIS_SUFFIX'
|
||||
payload: {suffix: string}
|
||||
}
|
||||
|
||||
export const setYAxisSuffix = (suffix: string): SetYAxisSuffix => ({
|
||||
type: 'SET_Y_AXIS_SUFFIX',
|
||||
payload: {suffix},
|
||||
})
|
||||
|
||||
interface SetYAxisBase {
|
||||
type: 'SET_Y_AXIS_BASE'
|
||||
payload: {base: string}
|
||||
}
|
||||
|
||||
export const setYAxisBase = (base: string): SetYAxisBase => ({
|
||||
type: 'SET_Y_AXIS_BASE',
|
||||
payload: {base},
|
||||
})
|
||||
|
||||
interface SetYAxisScale {
|
||||
type: 'SET_Y_AXIS_SCALE'
|
||||
payload: {scale: string}
|
||||
}
|
||||
|
||||
export const setYAxisScale = (scale: string): SetYAxisScale => ({
|
||||
type: 'SET_Y_AXIS_SCALE',
|
||||
payload: {scale},
|
||||
})
|
||||
|
||||
interface SetStaticLegend {
|
||||
type: 'SET_STATIC_LEGEND'
|
||||
payload: {staticLegend: boolean}
|
||||
}
|
||||
|
||||
export const setStaticLegend = (staticLegend: boolean): SetStaticLegend => ({
|
||||
type: 'SET_STATIC_LEGEND',
|
||||
payload: {staticLegend},
|
||||
})
|
||||
|
||||
interface SetColors {
|
||||
type: 'SET_COLORS'
|
||||
payload: {colors: Color[]}
|
||||
}
|
||||
|
||||
export const setColors = (colors: Color[]): SetColors => ({
|
||||
type: 'SET_COLORS',
|
||||
payload: {colors},
|
||||
})
|
||||
|
||||
interface SetDecimalPlaces {
|
||||
type: 'SET_DECIMAL_PLACES'
|
||||
payload: {decimalPlaces: DecimalPlaces}
|
||||
}
|
||||
|
||||
export const setDecimalPlaces = (
|
||||
decimalPlaces: DecimalPlaces
|
||||
): SetDecimalPlaces => ({
|
||||
type: 'SET_DECIMAL_PLACES',
|
||||
payload: {decimalPlaces},
|
||||
})
|
||||
|
|
|
@ -38,7 +38,6 @@ export default class ColorScaleDropdown extends Component<Props, State> {
|
|||
|
||||
public render() {
|
||||
const {expanded} = this.state
|
||||
const {selected} = this.props
|
||||
|
||||
return (
|
||||
<ClickOutside onClickOutside={this.handleClickOutside}>
|
||||
|
@ -46,9 +45,9 @@ export default class ColorScaleDropdown extends Component<Props, State> {
|
|||
<div className={this.buttonClassName} onClick={this.handleToggleMenu}>
|
||||
<div
|
||||
className="color-dropdown--swatches"
|
||||
style={this.generateGradientStyle(selected)}
|
||||
style={this.generateGradientStyle(this.selected)}
|
||||
/>
|
||||
<div className="color-dropdown--name">{selected[0].name}</div>
|
||||
<div className="color-dropdown--name">{this.selected[0].name}</div>
|
||||
<span className="caret" />
|
||||
</div>
|
||||
{expanded && this.renderMenu}
|
||||
|
@ -57,9 +56,17 @@ export default class ColorScaleDropdown extends Component<Props, State> {
|
|||
)
|
||||
}
|
||||
|
||||
private get renderMenu(): JSX.Element {
|
||||
private get selected(): Color[] {
|
||||
const {selected} = this.props
|
||||
|
||||
if (selected.length) {
|
||||
return selected
|
||||
}
|
||||
|
||||
return LINE_COLOR_SCALES[0].colors
|
||||
}
|
||||
|
||||
private get renderMenu(): JSX.Element {
|
||||
return (
|
||||
<div className="color-dropdown--menu">
|
||||
<FancyScrollbar
|
||||
|
@ -70,7 +77,7 @@ export default class ColorScaleDropdown extends Component<Props, State> {
|
|||
{LINE_COLOR_SCALES.map(colorScale => (
|
||||
<div
|
||||
className={
|
||||
colorScale.name === selected[0].name
|
||||
colorScale.name === this.selected[0].name
|
||||
? 'color-dropdown--item active'
|
||||
: 'color-dropdown--item'
|
||||
}
|
||||
|
|
|
@ -1,34 +1,20 @@
|
|||
// Libraries
|
||||
import React, {SFC} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
|
||||
// Components
|
||||
import ViewTypeSelector from 'src/shared/components/ViewTypeSelector'
|
||||
import TimeMachineQueryEditor from 'src/shared/components/TimeMachineQueryEditor'
|
||||
|
||||
// Actions
|
||||
import {setType} from 'src/shared/actions/v2/timeMachines'
|
||||
import TimeMachineQueryEditor from 'src/shared/components/TimeMachineQueryEditor'
|
||||
import ViewOptions from 'src/shared/components/view_options/ViewOptions'
|
||||
|
||||
// Types
|
||||
import {AppState, View, NewView} from 'src/types/v2'
|
||||
import {TimeMachineTab} from 'src/types/v2/timeMachine'
|
||||
|
||||
interface StateProps {
|
||||
view: View | NewView
|
||||
}
|
||||
|
||||
interface DispatchProps {
|
||||
onUpdateType: typeof setType
|
||||
}
|
||||
|
||||
interface OwnProps {
|
||||
interface Props {
|
||||
activeTab: TimeMachineTab
|
||||
}
|
||||
|
||||
type Props = StateProps & DispatchProps & OwnProps
|
||||
|
||||
const TimeMachineBottom: SFC<Props> = props => {
|
||||
const {view, onUpdateType, activeTab} = props
|
||||
const {activeTab} = props
|
||||
|
||||
if (activeTab === TimeMachineTab.Queries) {
|
||||
return <TimeMachineQueryEditor />
|
||||
|
@ -37,10 +23,7 @@ const TimeMachineBottom: SFC<Props> = props => {
|
|||
if (activeTab === TimeMachineTab.Visualization) {
|
||||
return (
|
||||
<div className="time-machine-customization">
|
||||
<ViewTypeSelector
|
||||
type={view.properties.type}
|
||||
onUpdateType={onUpdateType}
|
||||
/>
|
||||
<ViewOptions />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -48,18 +31,4 @@ const TimeMachineBottom: SFC<Props> = props => {
|
|||
return null
|
||||
}
|
||||
|
||||
const mstp = (state: AppState) => {
|
||||
const {activeTimeMachineID, timeMachines} = state.timeMachines
|
||||
const timeMachine = timeMachines[activeTimeMachineID]
|
||||
|
||||
return {view: timeMachine.view}
|
||||
}
|
||||
|
||||
const mdtp = {
|
||||
onUpdateType: setType,
|
||||
}
|
||||
|
||||
export default connect<StateProps, DispatchProps, OwnProps>(
|
||||
mstp,
|
||||
mdtp
|
||||
)(TimeMachineBottom)
|
||||
export default TimeMachineBottom
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
|
||||
// Components
|
||||
import Form from 'src/clockface/components/form_layout/Form'
|
||||
import YAxisTitle from 'src/shared/components/view_options/options/YAxisTitle'
|
||||
import YAxisBounds from 'src/shared/components/view_options/options/YAxisBounds'
|
||||
import YAxisAffixes from 'src/shared/components/view_options/options/YAxisAffixes'
|
||||
import YAxisBase from 'src/shared/components/view_options/options/YAxisBase'
|
||||
import YAxisScale from 'src/shared/components/view_options/options/YAxisScale'
|
||||
import DecimalPlacesOption from 'src/shared/components/view_options/options/DecimalPlaces'
|
||||
import ColorSelector from 'src/shared/components/view_options/options/ColorSelector'
|
||||
|
||||
// Actions
|
||||
import {
|
||||
setStaticLegend,
|
||||
setColors,
|
||||
setDecimalPlaces,
|
||||
setYAxisLabel,
|
||||
setYAxisMinBound,
|
||||
setYAxisMaxBound,
|
||||
setYAxisPrefix,
|
||||
setYAxisSuffix,
|
||||
setYAxisBase,
|
||||
setYAxisScale,
|
||||
} from 'src/shared/actions/v2/timeMachines'
|
||||
|
||||
// Types
|
||||
import {ViewType} from 'src/types/v2'
|
||||
import {Axes, DecimalPlaces} from 'src/types/v2/dashboards'
|
||||
import {Color} from 'src/types/colors'
|
||||
|
||||
interface OwnProps {
|
||||
type: ViewType
|
||||
axes: Axes
|
||||
colors: Color[]
|
||||
decimalPlaces?: DecimalPlaces
|
||||
}
|
||||
|
||||
interface DispatchProps {
|
||||
onUpdateYAxisLabel: (label: string) => void
|
||||
onUpdateYAxisMinBound: (min: string) => void
|
||||
onUpdateYAxisMaxBound: (max: string) => void
|
||||
onUpdateYAxisPrefix: (prefix: string) => void
|
||||
onUpdateYAxisSuffix: (suffix: string) => void
|
||||
onUpdateYAxisBase: (base: string) => void
|
||||
onUpdateYAxisScale: (scale: string) => void
|
||||
onToggleStaticLegend: (isStaticLegend: boolean) => void
|
||||
onUpdateColors: (colors: Color[]) => void
|
||||
onUpdateDecimalPlaces: (decimalPlaces: DecimalPlaces) => void
|
||||
}
|
||||
|
||||
type Props = OwnProps & DispatchProps
|
||||
|
||||
class LineOptions extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {
|
||||
axes: {
|
||||
y: {label, bounds, scale, prefix, suffix, base},
|
||||
},
|
||||
colors,
|
||||
onUpdateColors,
|
||||
onUpdateYAxisLabel,
|
||||
onUpdateYAxisMinBound,
|
||||
onUpdateYAxisMaxBound,
|
||||
onUpdateYAxisPrefix,
|
||||
onUpdateYAxisSuffix,
|
||||
onUpdateYAxisBase,
|
||||
onUpdateYAxisScale,
|
||||
} = this.props
|
||||
|
||||
const [min, max] = bounds
|
||||
|
||||
return (
|
||||
<Form>
|
||||
<YAxisTitle label={label} onUpdateYAxisLabel={onUpdateYAxisLabel} />
|
||||
<ColorSelector colors={colors} onUpdateColors={onUpdateColors} />
|
||||
<YAxisBounds
|
||||
min={min}
|
||||
max={max}
|
||||
scale={scale}
|
||||
onUpdateYAxisMaxBound={onUpdateYAxisMaxBound}
|
||||
onUpdateYAxisMinBound={onUpdateYAxisMinBound}
|
||||
/>
|
||||
<YAxisAffixes
|
||||
prefix={prefix}
|
||||
suffix={suffix}
|
||||
onUpdateYAxisPrefix={onUpdateYAxisPrefix}
|
||||
onUpdateYAxisSuffix={onUpdateYAxisSuffix}
|
||||
/>
|
||||
<YAxisBase base={base} onUpdateYAxisBase={onUpdateYAxisBase} />
|
||||
<YAxisScale scale={scale} onUpdateYAxisScale={onUpdateYAxisScale} />
|
||||
{this.decimalPlaces}
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
|
||||
private get decimalPlaces(): JSX.Element {
|
||||
const {onUpdateDecimalPlaces, decimalPlaces, type} = this.props
|
||||
|
||||
if (type !== ViewType.LinePlusSingleStat || !decimalPlaces) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<DecimalPlacesOption
|
||||
digits={decimalPlaces.digits}
|
||||
isEnforced={decimalPlaces.isEnforced}
|
||||
onDecimalPlacesChange={onUpdateDecimalPlaces}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const mdtp: DispatchProps = {
|
||||
onUpdateYAxisLabel: setYAxisLabel,
|
||||
onUpdateYAxisMinBound: setYAxisMinBound,
|
||||
onUpdateYAxisMaxBound: setYAxisMaxBound,
|
||||
onUpdateYAxisPrefix: setYAxisPrefix,
|
||||
onUpdateYAxisSuffix: setYAxisSuffix,
|
||||
onUpdateYAxisBase: setYAxisBase,
|
||||
onUpdateYAxisScale: setYAxisScale,
|
||||
onToggleStaticLegend: setStaticLegend,
|
||||
onUpdateColors: setColors,
|
||||
onUpdateDecimalPlaces: setDecimalPlaces,
|
||||
}
|
||||
|
||||
export default connect<{}, DispatchProps, OwnProps>(
|
||||
null,
|
||||
mdtp
|
||||
)(LineOptions)
|
|
@ -0,0 +1,29 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
|
||||
// Components
|
||||
import LineOptions from 'src/shared/components/view_options/LineOptions'
|
||||
// Types
|
||||
import {ViewType, View, NewView} from 'src/types/v2'
|
||||
|
||||
interface Props {
|
||||
view: View | NewView
|
||||
}
|
||||
|
||||
class OptionsSwitcher extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {view} = this.props
|
||||
switch (view.properties.type) {
|
||||
case ViewType.Line:
|
||||
case ViewType.Stacked:
|
||||
case ViewType.StepPlot:
|
||||
case ViewType.Bar:
|
||||
case ViewType.LinePlusSingleStat:
|
||||
return <LineOptions {...view.properties} />
|
||||
default:
|
||||
return <div />
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default OptionsSwitcher
|
|
@ -0,0 +1,78 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
|
||||
// Actions
|
||||
import {setType} from 'src/shared/actions/v2/timeMachines'
|
||||
|
||||
// Components
|
||||
import ViewTypeSelector from 'src/shared/components/ViewTypeSelector'
|
||||
import Threesizer from 'src/shared/components/threesizer/Threesizer'
|
||||
import OptionsSwitcher from 'src/shared/components/view_options/OptionsSwitcher'
|
||||
|
||||
// Constants
|
||||
import {HANDLE_VERTICAL} from 'src/shared/constants'
|
||||
// Types
|
||||
import {View, NewView, AppState} from 'src/types/v2'
|
||||
|
||||
interface DispatchProps {
|
||||
onUpdateType: typeof setType
|
||||
}
|
||||
|
||||
interface StateProps {
|
||||
view: View | NewView
|
||||
}
|
||||
|
||||
type Props = DispatchProps & StateProps
|
||||
|
||||
class ViewOptions extends PureComponent<Props> {
|
||||
public render() {
|
||||
return (
|
||||
<Threesizer orientation={HANDLE_VERTICAL} divisions={this.divisions} />
|
||||
)
|
||||
}
|
||||
|
||||
private get divisions() {
|
||||
const {view, onUpdateType} = this.props
|
||||
return [
|
||||
{
|
||||
name: 'Visualization Type',
|
||||
headerButtons: [],
|
||||
menuOptions: [],
|
||||
render: () => (
|
||||
<ViewTypeSelector
|
||||
type={view.properties.type}
|
||||
onUpdateType={onUpdateType}
|
||||
/>
|
||||
),
|
||||
headerOrientation: HANDLE_VERTICAL,
|
||||
},
|
||||
{
|
||||
name: 'Customize',
|
||||
headerButtons: [],
|
||||
menuOptions: [],
|
||||
render: () => <OptionsSwitcher view={view} />,
|
||||
headerOrientation: HANDLE_VERTICAL,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
const mstp = (state: AppState): StateProps => {
|
||||
const {
|
||||
timeMachines: {activeTimeMachineID, timeMachines},
|
||||
} = state
|
||||
const timeMachine = timeMachines[activeTimeMachineID]
|
||||
|
||||
return {
|
||||
view: timeMachine.view,
|
||||
}
|
||||
}
|
||||
|
||||
const mdtp: DispatchProps = {
|
||||
onUpdateType: setType,
|
||||
}
|
||||
export default connect<StateProps, DispatchProps, {}>(
|
||||
mstp,
|
||||
mdtp
|
||||
)(ViewOptions)
|
|
@ -0,0 +1,41 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
|
||||
// Components
|
||||
import FormElement from 'src/clockface/components/form_layout/FormElement'
|
||||
import ColorScaleDropdown from 'src/shared/components/ColorScaleDropdown'
|
||||
|
||||
// Types
|
||||
import {Color} from 'src/types/colors'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
interface Props {
|
||||
colors: Color[]
|
||||
onUpdateColors: (colors: Color[]) => void
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
class LineGraphColorSelector extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {colors} = this.props
|
||||
|
||||
return (
|
||||
<FormElement label="Line Colors">
|
||||
<ColorScaleDropdown
|
||||
onChoose={this.handleSelectColors}
|
||||
stretchToFit={true}
|
||||
selected={colors}
|
||||
/>
|
||||
</FormElement>
|
||||
)
|
||||
}
|
||||
|
||||
public handleSelectColors = (colorScale): void => {
|
||||
const {onUpdateColors} = this.props
|
||||
const {colors} = colorScale
|
||||
|
||||
onUpdateColors(colors)
|
||||
}
|
||||
}
|
||||
|
||||
export default LineGraphColorSelector
|
|
@ -13,7 +13,7 @@ const fixedValueString = 'fixed'
|
|||
const defaultPlaceholder = 'unlimited'
|
||||
|
||||
@ErrorHandling
|
||||
class GraphOptionsDecimalPlaces extends PureComponent<Props> {
|
||||
class DecimalPlacesOption extends PureComponent<Props> {
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
}
|
||||
|
@ -75,4 +75,4 @@ class GraphOptionsDecimalPlaces extends PureComponent<Props> {
|
|||
}
|
||||
}
|
||||
|
||||
export default GraphOptionsDecimalPlaces
|
||||
export default DecimalPlacesOption
|
|
@ -0,0 +1,48 @@
|
|||
// Libraries
|
||||
import React, {PureComponent, ChangeEvent} from 'react'
|
||||
|
||||
// Components
|
||||
import FormElement from 'src/clockface/components/form_layout/FormElement'
|
||||
import {Input} from 'src/clockface'
|
||||
|
||||
interface Props {
|
||||
prefix: string
|
||||
suffix: string
|
||||
onUpdateYAxisPrefix: (prefix: string) => void
|
||||
onUpdateYAxisSuffix: (suffix: string) => void
|
||||
}
|
||||
|
||||
class YAxisAffixes extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {prefix, suffix} = this.props
|
||||
|
||||
return (
|
||||
<>
|
||||
<FormElement label="Y-Value's Prefix">
|
||||
<Input value={prefix} onChange={this.handleUpdateYAxisPrefix} />
|
||||
</FormElement>
|
||||
<FormElement label="Y-Value's Suffix">
|
||||
<Input value={suffix} onChange={this.handleUpdateYAxisSuffix} />
|
||||
</FormElement>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
private handleUpdateYAxisPrefix = (
|
||||
e: ChangeEvent<HTMLInputElement>
|
||||
): void => {
|
||||
const {onUpdateYAxisPrefix} = this.props
|
||||
const prefix = e.target.value
|
||||
onUpdateYAxisPrefix(prefix)
|
||||
}
|
||||
|
||||
private handleUpdateYAxisSuffix = (
|
||||
e: ChangeEvent<HTMLInputElement>
|
||||
): void => {
|
||||
const {onUpdateYAxisSuffix} = this.props
|
||||
const suffix = e.target.value
|
||||
onUpdateYAxisSuffix(suffix)
|
||||
}
|
||||
}
|
||||
|
||||
export default YAxisAffixes
|
|
@ -0,0 +1,58 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
|
||||
// Components
|
||||
import FormElement from 'src/clockface/components/form_layout/FormElement'
|
||||
import {Radio, ButtonShape} from 'src/clockface'
|
||||
|
||||
// Constants
|
||||
import {AXES_SCALE_OPTIONS} from 'src/dashboards/constants/cellEditor'
|
||||
|
||||
interface Props {
|
||||
base: string
|
||||
onUpdateYAxisBase: (base: string) => void
|
||||
}
|
||||
|
||||
const {BASE_2, BASE_10} = AXES_SCALE_OPTIONS
|
||||
|
||||
class YAxisBase extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {base, onUpdateYAxisBase} = this.props
|
||||
|
||||
return (
|
||||
<FormElement label="Y-Value's Format">
|
||||
<Radio shape={ButtonShape.StretchToFit}>
|
||||
<Radio.Button
|
||||
id="y-values-format-tab--raw"
|
||||
value=""
|
||||
active={base === ''}
|
||||
titleText="Don't format values"
|
||||
onClick={onUpdateYAxisBase}
|
||||
>
|
||||
Raw
|
||||
</Radio.Button>
|
||||
<Radio.Button
|
||||
id="y-values-format-tab--kmb"
|
||||
value={BASE_10}
|
||||
active={base === BASE_10}
|
||||
titleText="Thousand / Million / Billion"
|
||||
onClick={onUpdateYAxisBase}
|
||||
>
|
||||
K/M/B
|
||||
</Radio.Button>
|
||||
<Radio.Button
|
||||
id="y-values-format-tab--kmg"
|
||||
value={BASE_2}
|
||||
active={base === BASE_2}
|
||||
titleText="Kilo / Mega / Giga"
|
||||
onClick={onUpdateYAxisBase}
|
||||
>
|
||||
K/M/G
|
||||
</Radio.Button>
|
||||
</Radio>
|
||||
</FormElement>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default YAxisBase
|
|
@ -0,0 +1,39 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
|
||||
// Constants
|
||||
import {AXES_SCALE_OPTIONS} from 'src/dashboards/constants/cellEditor'
|
||||
|
||||
// Components
|
||||
import FormElement from 'src/clockface/components/form_layout/FormElement'
|
||||
import OptIn from 'src/shared/components/OptIn'
|
||||
|
||||
interface Props {
|
||||
label: string
|
||||
bound: string
|
||||
scale: string
|
||||
onUpdateYAxisBound: (bound: string) => void
|
||||
}
|
||||
|
||||
const {LOG} = AXES_SCALE_OPTIONS
|
||||
const getInputMin = scale => (scale === LOG ? '0' : null)
|
||||
|
||||
class YAxisBound extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {label, bound, scale, onUpdateYAxisBound} = this.props
|
||||
|
||||
return (
|
||||
<FormElement label={label}>
|
||||
<OptIn
|
||||
customPlaceholder={'min'}
|
||||
customValue={bound}
|
||||
onSetValue={onUpdateYAxisBound}
|
||||
type="number"
|
||||
min={getInputMin(scale)}
|
||||
/>
|
||||
</FormElement>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default YAxisBound
|
|
@ -0,0 +1,45 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
|
||||
// Components
|
||||
import YAxisBound from 'src/shared/components/view_options/options/YAxisBound'
|
||||
|
||||
interface Props {
|
||||
min: string
|
||||
max: string
|
||||
scale: string
|
||||
onUpdateYAxisMinBound: (min: string) => void
|
||||
onUpdateYAxisMaxBound: (max: string) => void
|
||||
}
|
||||
|
||||
class YAxisBounds extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {
|
||||
min,
|
||||
max,
|
||||
scale,
|
||||
onUpdateYAxisMinBound,
|
||||
onUpdateYAxisMaxBound,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<>
|
||||
<YAxisBound
|
||||
label="Min"
|
||||
bound={min}
|
||||
scale={scale}
|
||||
onUpdateYAxisBound={onUpdateYAxisMinBound}
|
||||
/>
|
||||
|
||||
<YAxisBound
|
||||
label="Max"
|
||||
bound={max}
|
||||
scale={scale}
|
||||
onUpdateYAxisBound={onUpdateYAxisMaxBound}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default YAxisBounds
|
|
@ -0,0 +1,49 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
|
||||
// Components
|
||||
import FormElement from 'src/clockface/components/form_layout/FormElement'
|
||||
import {Radio, ButtonShape} from 'src/clockface'
|
||||
|
||||
// Constants
|
||||
import {AXES_SCALE_OPTIONS} from 'src/dashboards/constants/cellEditor'
|
||||
|
||||
interface Props {
|
||||
scale: string
|
||||
onUpdateYAxisScale: (scale: string) => void
|
||||
}
|
||||
|
||||
const {LINEAR, LOG} = AXES_SCALE_OPTIONS
|
||||
|
||||
class YAxisBase extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {scale, onUpdateYAxisScale} = this.props
|
||||
|
||||
return (
|
||||
<FormElement label="Scale">
|
||||
<Radio shape={ButtonShape.StretchToFit}>
|
||||
<Radio.Button
|
||||
id="y-scale-tab--linear"
|
||||
value={LINEAR}
|
||||
active={scale === LINEAR || scale === ''}
|
||||
titleText="Set Y-Axis to Linear Scale"
|
||||
onClick={onUpdateYAxisScale}
|
||||
>
|
||||
Linear
|
||||
</Radio.Button>
|
||||
<Radio.Button
|
||||
id="y-scale-tab--logarithmic"
|
||||
value={LOG}
|
||||
active={scale === LOG}
|
||||
titleText="Set Y-Axis to Logarithmic Scale"
|
||||
onClick={onUpdateYAxisScale}
|
||||
>
|
||||
Logarithmic
|
||||
</Radio.Button>
|
||||
</Radio>
|
||||
</FormElement>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default YAxisBase
|
|
@ -0,0 +1,33 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
|
||||
// Components
|
||||
import FormElement from 'src/clockface/components/form_layout/FormElement'
|
||||
import OptIn from 'src/shared/components/OptIn'
|
||||
|
||||
interface Props {
|
||||
label: string
|
||||
onUpdateYAxisLabel: (label: string) => void
|
||||
}
|
||||
class YAxisTitle extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {label, onUpdateYAxisLabel} = this.props
|
||||
|
||||
return (
|
||||
<FormElement label="Title">
|
||||
<OptIn
|
||||
type="text"
|
||||
customValue={label}
|
||||
onSetValue={onUpdateYAxisLabel}
|
||||
customPlaceholder={this.defaultYLabel || 'y-axis title'}
|
||||
/>
|
||||
</FormElement>
|
||||
)
|
||||
}
|
||||
|
||||
private get defaultYLabel() {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
export default YAxisTitle
|
|
@ -1,3 +1,6 @@
|
|||
// Libraries
|
||||
import _ from 'lodash'
|
||||
|
||||
// Utils
|
||||
import {convertView, createView, replaceQuery} from 'src/shared/utils/view'
|
||||
|
||||
|
@ -111,6 +114,168 @@ const timeMachineReducer = (
|
|||
}
|
||||
break
|
||||
}
|
||||
case 'SET_AXES': {
|
||||
const {axes} = action.payload
|
||||
const {
|
||||
view,
|
||||
view: {properties},
|
||||
} = activeTimeMachine
|
||||
|
||||
newActiveTimeMachine = {
|
||||
...activeTimeMachine,
|
||||
view: {...view, properties: {...properties, axes}},
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'SET_Y_AXIS_LABEL': {
|
||||
const {label} = action.payload
|
||||
const {
|
||||
view,
|
||||
view: {properties},
|
||||
} = activeTimeMachine
|
||||
|
||||
const axes = _.get(properties, 'axes')
|
||||
const yAxis = {..._.get(axes, 'y'), label}
|
||||
|
||||
newActiveTimeMachine = {
|
||||
...activeTimeMachine,
|
||||
view: {...view, properties: {...properties, axes: {...axes, y: yAxis}}},
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'SET_Y_AXIS_MIN_BOUND': {
|
||||
const {min} = action.payload
|
||||
const {
|
||||
view,
|
||||
view: {properties},
|
||||
} = activeTimeMachine
|
||||
|
||||
const axes = _.get(properties, 'axes')
|
||||
const yAxis = _.get(axes, 'y')
|
||||
yAxis.bounds[0] = min
|
||||
|
||||
newActiveTimeMachine = {
|
||||
...activeTimeMachine,
|
||||
view: {...view, properties: {...properties, axes: {...axes, y: yAxis}}},
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'SET_Y_AXIS_MAX_BOUND': {
|
||||
const {max} = action.payload
|
||||
const {
|
||||
view,
|
||||
view: {properties},
|
||||
} = activeTimeMachine
|
||||
|
||||
const axes = _.get(properties, 'axes')
|
||||
const yAxis = _.get(axes, 'y')
|
||||
yAxis.bounds[1] = max
|
||||
|
||||
newActiveTimeMachine = {
|
||||
...activeTimeMachine,
|
||||
view: {...view, properties: {...properties, axes: {...axes, y: yAxis}}},
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'SET_Y_AXIS_PREFIX': {
|
||||
const {prefix} = action.payload
|
||||
const {
|
||||
view,
|
||||
view: {properties},
|
||||
} = activeTimeMachine
|
||||
|
||||
const axes = _.get(properties, 'axes')
|
||||
const yAxis = {..._.get(axes, 'y'), prefix}
|
||||
|
||||
newActiveTimeMachine = {
|
||||
...activeTimeMachine,
|
||||
view: {...view, properties: {...properties, axes: {...axes, y: yAxis}}},
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'SET_Y_AXIS_SUFFIX': {
|
||||
const {suffix} = action.payload
|
||||
const {
|
||||
view,
|
||||
view: {properties},
|
||||
} = activeTimeMachine
|
||||
|
||||
const axes = _.get(properties, 'axes')
|
||||
const yAxis = {..._.get(axes, 'y'), suffix}
|
||||
|
||||
newActiveTimeMachine = {
|
||||
...activeTimeMachine,
|
||||
view: {...view, properties: {...properties, axes: {...axes, y: yAxis}}},
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'SET_Y_AXIS_BASE': {
|
||||
const {base} = action.payload
|
||||
const {
|
||||
view,
|
||||
view: {properties},
|
||||
} = activeTimeMachine
|
||||
|
||||
const axes = _.get(properties, 'axes')
|
||||
const yAxis = {..._.get(axes, 'y'), base}
|
||||
|
||||
newActiveTimeMachine = {
|
||||
...activeTimeMachine,
|
||||
view: {...view, properties: {...properties, axes: {...axes, y: yAxis}}},
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'SET_Y_AXIS_SCALE': {
|
||||
const {scale} = action.payload
|
||||
const {
|
||||
view,
|
||||
view: {properties},
|
||||
} = activeTimeMachine
|
||||
|
||||
const axes = _.get(properties, 'axes')
|
||||
const yAxis = {..._.get(axes, 'y'), scale}
|
||||
|
||||
newActiveTimeMachine = {
|
||||
...activeTimeMachine,
|
||||
view: {...view, properties: {...properties, axes: {...axes, y: yAxis}}},
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'SET_COLORS': {
|
||||
const {colors} = action.payload
|
||||
const {
|
||||
view,
|
||||
view: {properties},
|
||||
} = activeTimeMachine
|
||||
|
||||
newActiveTimeMachine = {
|
||||
...activeTimeMachine,
|
||||
view: {...view, properties: {...properties, colors}},
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'SET_DECIMAL_PLACES': {
|
||||
const {decimalPlaces} = action.payload
|
||||
|
||||
newActiveTimeMachine = {...activeTimeMachine, decimalPlaces}
|
||||
break
|
||||
}
|
||||
|
||||
case 'SET_STATIC_LEGEND': {
|
||||
const {staticLegend} = action.payload
|
||||
|
||||
newActiveTimeMachine = {...activeTimeMachine, staticLegend}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (newActiveTimeMachine) {
|
||||
|
|
Loading…
Reference in New Issue