Commit ddf080da by Peter Holmberg

Using an id to identify mappings

parent 76f296e2
...@@ -41,7 +41,7 @@ export default class ToggleButtonGroup extends PureComponent<ToggleButtonGroupPr ...@@ -41,7 +41,7 @@ export default class ToggleButtonGroup extends PureComponent<ToggleButtonGroupPr
<div className="gf-form"> <div className="gf-form">
<div className={`toggle-button-group ${stackedButtons ? 'stacked' : ''}`}> <div className={`toggle-button-group ${stackedButtons ? 'stacked' : ''}`}>
{label && <label className={labelClassName}>{label}</label>} {label && <label className={labelClassName}>{label}</label>}
{this.props.render({ selectedValue, onChange: this.handleToggle.bind(this) })} {this.props.render({ selectedValue, onChange: this.handleToggle.bind(this), stackedButtons: stackedButtons })}
</div> </div>
</div> </div>
); );
...@@ -54,9 +54,17 @@ interface ToggleButtonProps { ...@@ -54,9 +54,17 @@ interface ToggleButtonProps {
value: any; value: any;
className?: string; className?: string;
children: ReactNode; children: ReactNode;
stackedButtons?: boolean;
} }
export const ToggleButton: SFC<ToggleButtonProps> = ({ children, selected, className = '', value, onChange }) => { export const ToggleButton: SFC<ToggleButtonProps> = ({
children,
selected,
className = '',
value,
onChange,
stackedButtons,
}) => {
const handleChange = event => { const handleChange = event => {
event.stopPropagation(); event.stopPropagation();
if (onChange) { if (onChange) {
...@@ -64,7 +72,7 @@ export const ToggleButton: SFC<ToggleButtonProps> = ({ children, selected, class ...@@ -64,7 +72,7 @@ export const ToggleButton: SFC<ToggleButtonProps> = ({ children, selected, class
} }
}; };
const btnClassName = `btn ${className} ${selected ? 'active' : ''}`; const btnClassName = `btn ${className} ${selected ? 'active' : ''} ${stackedButtons ? 'stacked' : ''}`;
return ( return (
<button className={btnClassName} onClick={handleChange}> <button className={btnClassName} onClick={handleChange}>
<span>{children}</span> <span>{children}</span>
......
...@@ -53,17 +53,17 @@ export default class MappingRow extends PureComponent<Props, State> { ...@@ -53,17 +53,17 @@ export default class MappingRow extends PureComponent<Props, State> {
this.setState({ mapping: updatedMapping }); this.setState({ mapping: updatedMapping });
}; };
updateMapping = () => { onMappingTypeChange = mappingType => {
const { mapping } = this.state; const { mapping } = this.state;
this.props.updateMapping(mapping); const updatedMapping = { ...mapping, type: mappingType };
this.setState({ mapping: updatedMapping });
}; };
onMappingTypeChange = mappingType => { updateMapping = () => {
const { mapping } = this.state; const { mapping } = this.state;
const updatedMapping = { ...mapping, type: mappingType }; this.props.updateMapping(mapping);
this.setState({ mapping: updatedMapping });
}; };
renderRow() { renderRow() {
...@@ -74,7 +74,7 @@ export default class MappingRow extends PureComponent<Props, State> { ...@@ -74,7 +74,7 @@ export default class MappingRow extends PureComponent<Props, State> {
return ( return (
<div className="gf-form"> <div className="gf-form">
<div className="gf-form-inline"> <div className="gf-form-inline mapping-row-input">
<Label width={4}>From</Label> <Label width={4}>From</Label>
<div> <div>
<input <input
...@@ -85,7 +85,7 @@ export default class MappingRow extends PureComponent<Props, State> { ...@@ -85,7 +85,7 @@ export default class MappingRow extends PureComponent<Props, State> {
/> />
</div> </div>
</div> </div>
<div className="gf-form-inline"> <div className="gf-form-inline mapping-row-input">
<Label width={4}>To</Label> <Label width={4}>To</Label>
<div> <div>
<input <input
...@@ -96,7 +96,7 @@ export default class MappingRow extends PureComponent<Props, State> { ...@@ -96,7 +96,7 @@ export default class MappingRow extends PureComponent<Props, State> {
/> />
</div> </div>
</div> </div>
<div className="gf-form-inline"> <div className="gf-form-inline mapping-row-input">
<Label width={4}>Text</Label> <Label width={4}>Text</Label>
<div> <div>
<input <input
...@@ -115,7 +115,7 @@ export default class MappingRow extends PureComponent<Props, State> { ...@@ -115,7 +115,7 @@ export default class MappingRow extends PureComponent<Props, State> {
return ( return (
<div className="gf-form"> <div className="gf-form">
<div className="gf-form-inline"> <div className="gf-form-inline mapping-row-input">
<Label width={4}>Value</Label> <Label width={4}>Value</Label>
<div> <div>
<input <input
...@@ -126,7 +126,7 @@ export default class MappingRow extends PureComponent<Props, State> { ...@@ -126,7 +126,7 @@ export default class MappingRow extends PureComponent<Props, State> {
/> />
</div> </div>
</div> </div>
<div className="gf-form-inline"> <div className="gf-form-inline mapping-row-input">
<Label width={4}>Text</Label> <Label width={4}>Text</Label>
<div> <div>
<input <input
...@@ -151,7 +151,7 @@ export default class MappingRow extends PureComponent<Props, State> { ...@@ -151,7 +151,7 @@ export default class MappingRow extends PureComponent<Props, State> {
onChange={mappingType => this.onMappingTypeChange(mappingType)} onChange={mappingType => this.onMappingTypeChange(mappingType)}
value={mapping.type} value={mapping.type}
stackedButtons={true} stackedButtons={true}
render={({ selectedValue, onChange }) => { render={({ selectedValue, onChange, stackedButtons }) => {
return [ return [
<ToggleButton <ToggleButton
className="btn-small" className="btn-small"
...@@ -159,6 +159,7 @@ export default class MappingRow extends PureComponent<Props, State> { ...@@ -159,6 +159,7 @@ export default class MappingRow extends PureComponent<Props, State> {
onChange={onChange} onChange={onChange}
selected={selectedValue === MappingType.ValueToText} selected={selectedValue === MappingType.ValueToText}
value={MappingType.ValueToText} value={MappingType.ValueToText}
stackedButtons={stackedButtons}
> >
Value Value
</ToggleButton>, </ToggleButton>,
...@@ -168,6 +169,7 @@ export default class MappingRow extends PureComponent<Props, State> { ...@@ -168,6 +169,7 @@ export default class MappingRow extends PureComponent<Props, State> {
onChange={onChange} onChange={onChange}
selected={selectedValue === MappingType.RangeToText} selected={selectedValue === MappingType.RangeToText}
value={MappingType.RangeToText} value={MappingType.RangeToText}
stackedButtons={stackedButtons}
> >
Range Range
</ToggleButton>, </ToggleButton>,
......
...@@ -2,27 +2,18 @@ import React, { PureComponent } from 'react'; ...@@ -2,27 +2,18 @@ import React, { PureComponent } from 'react';
import classNames from 'classnames/bind'; import classNames from 'classnames/bind';
import { ColorPicker } from 'app/core/components/colorpicker/ColorPicker'; import { ColorPicker } from 'app/core/components/colorpicker/ColorPicker';
import { OptionModuleProps } from './module'; import { OptionModuleProps } from './module';
import { Threshold } from 'app/types'; import { BasicGaugeColor, Threshold } from 'app/types';
interface State { interface State {
thresholds: Threshold[]; thresholds: Threshold[];
} }
enum BasicGaugeColor {
Green = 'rgba(50, 172, 45, 0.97)',
Orange = 'rgba(237, 129, 40, 0.89)',
Red = 'rgb(212, 74, 58)',
}
export default class Thresholds extends PureComponent<OptionModuleProps, State> { export default class Thresholds extends PureComponent<OptionModuleProps, State> {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
thresholds: this.props.options.thresholds || [ thresholds: props.options.thresholds,
{ index: 0, label: 'Min', value: 0, canRemove: false, color: BasicGaugeColor.Green },
{ index: 1, label: 'Max', value: 100, canRemove: false },
],
}; };
} }
......
import React from 'react';
import { shallow } from 'enzyme';
import { defaultProps, OptionModuleProps } from './module';
import { MappingType } from '../../../types';
import ValueMappings from './ValueMappings';
const setup = (propOverrides?: object) => {
const props: OptionModuleProps = {
onChange: jest.fn(),
options: {
...defaultProps.options,
mappings: [
{ id: 1, operator: '', type: MappingType.ValueToText, value: '20', text: 'Ok' },
{ id: 2, operator: '', type: MappingType.RangeToText, from: '21', to: '30', text: 'Meh' },
],
},
};
Object.assign(props, propOverrides);
const wrapper = shallow(<ValueMappings {...props} />);
return wrapper.instance() as ValueMappings;
};
describe('On remove mapping', () => {
it('Should remove mapping with id 0', () => {
const instance = setup();
instance.onRemoveMapping(1);
expect(instance.state.mappings).toEqual([
{ id: 2, operator: '', type: MappingType.RangeToText, from: '21', to: '30', text: 'Meh' },
]);
});
it('should remove mapping with id 1', () => {
const instance = setup();
instance.onRemoveMapping(2);
expect(instance.state.mappings).toEqual([
{ id: 1, operator: '', type: MappingType.ValueToText, value: '20', text: 'Ok' },
]);
});
});
describe('Next id to add', () => {
it('should be 4', () => {
const instance = setup();
instance.addMapping();
expect(instance.state.nextIdToAdd).toEqual(4);
});
});
...@@ -5,35 +5,60 @@ import { MappingType, RangeMap, ValueMap } from 'app/types'; ...@@ -5,35 +5,60 @@ import { MappingType, RangeMap, ValueMap } from 'app/types';
interface State { interface State {
mappings: Array<ValueMap | RangeMap>; mappings: Array<ValueMap | RangeMap>;
nextIdToAdd: number;
} }
export default class ValueMappings extends PureComponent<OptionModuleProps, State> { export default class ValueMappings extends PureComponent<OptionModuleProps, State> {
constructor(props) { constructor(props) {
super(props); super(props);
const mappings = props.options.mappings;
this.state = { this.state = {
mappings: props.mappings || [], mappings: mappings || [],
nextIdToAdd: mappings ? this.getMaxIdFromMappings(mappings) : 1,
}; };
} }
getMaxIdFromMappings(mappings) {
return Math.max.apply(null, mappings.map(mapping => mapping.id).map(m => m)) + 1;
}
addMapping = () => addMapping = () =>
this.setState(prevState => ({ this.setState(prevState => ({
mappings: [ mappings: [
...prevState.mappings, ...prevState.mappings,
{ op: '', value: '', text: '', type: MappingType.ValueToText, from: '', to: '' }, {
id: prevState.nextIdToAdd,
operator: '',
value: '',
text: '',
type: MappingType.ValueToText,
from: '',
to: '',
},
], ],
nextIdToAdd: prevState.nextIdToAdd + 1,
})); }));
onRemoveMapping = index => onRemoveMapping = id => {
this.setState(prevState => ({ this.setState(
mappings: prevState.mappings.filter((m, i) => i !== index), prevState => ({
})); mappings: prevState.mappings.filter(m => {
return m.id !== id;
}),
}),
() => {
this.props.onChange({ ...this.props.options, mappings: this.state.mappings });
}
);
};
updateGauge = mapping => { updateGauge = mapping => {
this.setState( this.setState(
prevState => ({ prevState => ({
mappings: prevState.mappings.map(m => { mappings: prevState.mappings.map(m => {
if (m === mapping) { if (m.id === mapping.id) {
return { ...mapping }; return { ...mapping };
} }
...@@ -54,16 +79,14 @@ export default class ValueMappings extends PureComponent<OptionModuleProps, Stat ...@@ -54,16 +79,14 @@ export default class ValueMappings extends PureComponent<OptionModuleProps, Stat
<h5 className="page-heading">Value mappings</h5> <h5 className="page-heading">Value mappings</h5>
<div> <div>
{mappings.length > 0 && {mappings.length > 0 &&
mappings.map((mapping, index) => { mappings.map((mapping, index) => (
return ( <MappingRow
<MappingRow key={`${mapping.text}-${index}`}
key={index} mapping={mapping}
mapping={mapping} updateMapping={this.updateGauge}
updateMapping={this.updateGauge} removeMapping={() => this.onRemoveMapping(mapping.id)}
removeMapping={() => this.onRemoveMapping(index)} />
/> ))}
);
})}
</div> </div>
<div className="add-mapping-row" onClick={this.addMapping}> <div className="add-mapping-row" onClick={this.addMapping}>
<div className="add-mapping-row-icon"> <div className="add-mapping-row-icon">
......
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import Gauge from 'app/viz/Gauge'; import Gauge from 'app/viz/Gauge';
import { NullValueMode, PanelOptionsProps, PanelProps, RangeMap, Threshold, ValueMap } from 'app/types';
import { getTimeSeriesVMs } from 'app/viz/state/timeSeries'; import { getTimeSeriesVMs } from 'app/viz/state/timeSeries';
import ValueOptions from './ValueOptions'; import ValueOptions from './ValueOptions';
import GaugeOptions from './GaugeOptions'; import GaugeOptions from './GaugeOptions';
import Thresholds from './Thresholds'; import Thresholds from './Thresholds';
import ValueMappings from './ValueMappings'; import ValueMappings from './ValueMappings';
import {
BasicGaugeColor,
NullValueMode,
PanelOptionsProps,
PanelProps,
RangeMap,
Threshold,
ValueMap,
} from 'app/types';
export interface OptionsProps { export interface OptionsProps {
decimals: number; decimals: number;
...@@ -16,8 +24,7 @@ export interface OptionsProps { ...@@ -16,8 +24,7 @@ export interface OptionsProps {
suffix: string; suffix: string;
unit: string; unit: string;
thresholds: Threshold[]; thresholds: Threshold[];
mappings: Array<ValueMap | RangeMap>; mappings: Array<RangeMap | ValueMap>;
mappingType: number;
} }
export interface OptionModuleProps { export interface OptionModuleProps {
...@@ -33,8 +40,14 @@ export const defaultProps = { ...@@ -33,8 +40,14 @@ export const defaultProps = {
showThresholdMarkers: true, showThresholdMarkers: true,
showThresholdLabels: false, showThresholdLabels: false,
suffix: '', suffix: '',
valueMaps: [], decimals: 0,
rangeMaps: [], stat: '',
unit: '',
mappings: [],
thresholds: [
{ index: 0, label: 'Min', value: 0, canRemove: false, color: BasicGaugeColor.Green },
{ index: 1, label: 'Max', value: 100, canRemove: false },
],
}, },
}; };
......
...@@ -21,7 +21,7 @@ import { ...@@ -21,7 +21,7 @@ import {
DataQueryOptions, DataQueryOptions,
IntervalValues, IntervalValues,
} from './series'; } from './series';
import { MappingType, PanelProps, PanelOptionsProps, RangeMap, Threshold, ValueMap } from './panel'; import { BasicGaugeColor, MappingType, PanelProps, PanelOptionsProps, RangeMap, Threshold, ValueMap } from './panel';
import { PluginDashboard, PluginMeta, Plugin, PanelPlugin, PluginsState } from './plugins'; import { PluginDashboard, PluginMeta, Plugin, PanelPlugin, PluginsState } from './plugins';
import { Organization, OrganizationState } from './organization'; import { Organization, OrganizationState } from './organization';
import { import {
...@@ -97,6 +97,7 @@ export { ...@@ -97,6 +97,7 @@ export {
RangeMap, RangeMap,
IntervalValues, IntervalValues,
MappingType, MappingType,
BasicGaugeColor,
}; };
export interface StoreState { export interface StoreState {
......
...@@ -42,8 +42,15 @@ export enum MappingType { ...@@ -42,8 +42,15 @@ export enum MappingType {
RangeToText = 2, RangeToText = 2,
} }
export enum BasicGaugeColor {
Green = 'rgba(50, 172, 45, 0.97)',
Orange = 'rgba(237, 129, 40, 0.89)',
Red = 'rgb(212, 74, 58)',
}
interface BaseMap { interface BaseMap {
op: string; id: number;
operator: string;
text: string; text: string;
type: MappingType; type: MappingType;
} }
......
...@@ -37,5 +37,9 @@ ...@@ -37,5 +37,9 @@
border-radius: 0 $border-radius $border-radius 0; border-radius: 0 $border-radius $border-radius 0;
margin-left: 0; margin-left: 0;
} }
&.stacked {
border-radius: $border-radius;
}
} }
} }
...@@ -8,11 +8,17 @@ ...@@ -8,11 +8,17 @@
margin-right: 5px; margin-right: 5px;
} }
.mapping-row-input {
margin-right: 5px;
}
.add-mapping-row { .add-mapping-row {
display: flex; display: flex;
overflow: hidden; overflow: hidden;
height: 37px; height: 37px;
cursor: pointer; cursor: pointer;
border-radius: $border-radius;
width: 200px;
} }
.add-mapping-row-icon { .add-mapping-row-icon {
...@@ -27,4 +33,6 @@ ...@@ -27,4 +33,6 @@
align-items: center; align-items: center;
display: flex; display: flex;
padding: 5px 8px; padding: 5px 8px;
background-color: $input-label-bg;
width: calc(100% - 36px);
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment