Commit ddf080da by Peter Holmberg

Using an id to identify mappings

parent 76f296e2
......@@ -41,7 +41,7 @@ export default class ToggleButtonGroup extends PureComponent<ToggleButtonGroupPr
<div className="gf-form">
<div className={`toggle-button-group ${stackedButtons ? 'stacked' : ''}`}>
{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>
);
......@@ -54,9 +54,17 @@ interface ToggleButtonProps {
value: any;
className?: string;
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 => {
event.stopPropagation();
if (onChange) {
......@@ -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 (
<button className={btnClassName} onClick={handleChange}>
<span>{children}</span>
......
......@@ -53,17 +53,17 @@ export default class MappingRow extends PureComponent<Props, State> {
this.setState({ mapping: updatedMapping });
};
updateMapping = () => {
onMappingTypeChange = mappingType => {
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 updatedMapping = { ...mapping, type: mappingType };
this.setState({ mapping: updatedMapping });
this.props.updateMapping(mapping);
};
renderRow() {
......@@ -74,7 +74,7 @@ export default class MappingRow extends PureComponent<Props, State> {
return (
<div className="gf-form">
<div className="gf-form-inline">
<div className="gf-form-inline mapping-row-input">
<Label width={4}>From</Label>
<div>
<input
......@@ -85,7 +85,7 @@ export default class MappingRow extends PureComponent<Props, State> {
/>
</div>
</div>
<div className="gf-form-inline">
<div className="gf-form-inline mapping-row-input">
<Label width={4}>To</Label>
<div>
<input
......@@ -96,7 +96,7 @@ export default class MappingRow extends PureComponent<Props, State> {
/>
</div>
</div>
<div className="gf-form-inline">
<div className="gf-form-inline mapping-row-input">
<Label width={4}>Text</Label>
<div>
<input
......@@ -115,7 +115,7 @@ export default class MappingRow extends PureComponent<Props, State> {
return (
<div className="gf-form">
<div className="gf-form-inline">
<div className="gf-form-inline mapping-row-input">
<Label width={4}>Value</Label>
<div>
<input
......@@ -126,7 +126,7 @@ export default class MappingRow extends PureComponent<Props, State> {
/>
</div>
</div>
<div className="gf-form-inline">
<div className="gf-form-inline mapping-row-input">
<Label width={4}>Text</Label>
<div>
<input
......@@ -151,7 +151,7 @@ export default class MappingRow extends PureComponent<Props, State> {
onChange={mappingType => this.onMappingTypeChange(mappingType)}
value={mapping.type}
stackedButtons={true}
render={({ selectedValue, onChange }) => {
render={({ selectedValue, onChange, stackedButtons }) => {
return [
<ToggleButton
className="btn-small"
......@@ -159,6 +159,7 @@ export default class MappingRow extends PureComponent<Props, State> {
onChange={onChange}
selected={selectedValue === MappingType.ValueToText}
value={MappingType.ValueToText}
stackedButtons={stackedButtons}
>
Value
</ToggleButton>,
......@@ -168,6 +169,7 @@ export default class MappingRow extends PureComponent<Props, State> {
onChange={onChange}
selected={selectedValue === MappingType.RangeToText}
value={MappingType.RangeToText}
stackedButtons={stackedButtons}
>
Range
</ToggleButton>,
......
......@@ -2,27 +2,18 @@ import React, { PureComponent } from 'react';
import classNames from 'classnames/bind';
import { ColorPicker } from 'app/core/components/colorpicker/ColorPicker';
import { OptionModuleProps } from './module';
import { Threshold } from 'app/types';
import { BasicGaugeColor, Threshold } from 'app/types';
interface State {
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> {
constructor(props) {
super(props);
this.state = {
thresholds: this.props.options.thresholds || [
{ index: 0, label: 'Min', value: 0, canRemove: false, color: BasicGaugeColor.Green },
{ index: 1, label: 'Max', value: 100, canRemove: false },
],
thresholds: props.options.thresholds,
};
}
......
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';
interface State {
mappings: Array<ValueMap | RangeMap>;
nextIdToAdd: number;
}
export default class ValueMappings extends PureComponent<OptionModuleProps, State> {
constructor(props) {
super(props);
const mappings = props.options.mappings;
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 = () =>
this.setState(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 =>
this.setState(prevState => ({
mappings: prevState.mappings.filter((m, i) => i !== index),
}));
onRemoveMapping = id => {
this.setState(
prevState => ({
mappings: prevState.mappings.filter(m => {
return m.id !== id;
}),
}),
() => {
this.props.onChange({ ...this.props.options, mappings: this.state.mappings });
}
);
};
updateGauge = mapping => {
this.setState(
prevState => ({
mappings: prevState.mappings.map(m => {
if (m === mapping) {
if (m.id === mapping.id) {
return { ...mapping };
}
......@@ -54,16 +79,14 @@ export default class ValueMappings extends PureComponent<OptionModuleProps, Stat
<h5 className="page-heading">Value mappings</h5>
<div>
{mappings.length > 0 &&
mappings.map((mapping, index) => {
return (
<MappingRow
key={index}
mapping={mapping}
updateMapping={this.updateGauge}
removeMapping={() => this.onRemoveMapping(index)}
/>
);
})}
mappings.map((mapping, index) => (
<MappingRow
key={`${mapping.text}-${index}`}
mapping={mapping}
updateMapping={this.updateGauge}
removeMapping={() => this.onRemoveMapping(mapping.id)}
/>
))}
</div>
<div className="add-mapping-row" onClick={this.addMapping}>
<div className="add-mapping-row-icon">
......
import React, { PureComponent } from 'react';
import Gauge from 'app/viz/Gauge';
import { NullValueMode, PanelOptionsProps, PanelProps, RangeMap, Threshold, ValueMap } from 'app/types';
import { getTimeSeriesVMs } from 'app/viz/state/timeSeries';
import ValueOptions from './ValueOptions';
import GaugeOptions from './GaugeOptions';
import Thresholds from './Thresholds';
import ValueMappings from './ValueMappings';
import {
BasicGaugeColor,
NullValueMode,
PanelOptionsProps,
PanelProps,
RangeMap,
Threshold,
ValueMap,
} from 'app/types';
export interface OptionsProps {
decimals: number;
......@@ -16,8 +24,7 @@ export interface OptionsProps {
suffix: string;
unit: string;
thresholds: Threshold[];
mappings: Array<ValueMap | RangeMap>;
mappingType: number;
mappings: Array<RangeMap | ValueMap>;
}
export interface OptionModuleProps {
......@@ -33,8 +40,14 @@ export const defaultProps = {
showThresholdMarkers: true,
showThresholdLabels: false,
suffix: '',
valueMaps: [],
rangeMaps: [],
decimals: 0,
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 {
DataQueryOptions,
IntervalValues,
} 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 { Organization, OrganizationState } from './organization';
import {
......@@ -97,6 +97,7 @@ export {
RangeMap,
IntervalValues,
MappingType,
BasicGaugeColor,
};
export interface StoreState {
......
......@@ -42,8 +42,15 @@ export enum MappingType {
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 {
op: string;
id: number;
operator: string;
text: string;
type: MappingType;
}
......
......@@ -37,5 +37,9 @@
border-radius: 0 $border-radius $border-radius 0;
margin-left: 0;
}
&.stacked {
border-radius: $border-radius;
}
}
}
......@@ -8,11 +8,17 @@
margin-right: 5px;
}
.mapping-row-input {
margin-right: 5px;
}
.add-mapping-row {
display: flex;
overflow: hidden;
height: 37px;
cursor: pointer;
border-radius: $border-radius;
width: 200px;
}
.add-mapping-row-icon {
......@@ -27,4 +33,6 @@
align-items: center;
display: flex;
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