grafana/packages/grafana-ui/src/components/ThresholdsEditor/ThresholdsEditor.tsx

234 lines
6.6 KiB
TypeScript
Raw Normal View History

import React, { PureComponent, ChangeEvent } from 'react';
import { Threshold } from '../../types';
import { ColorPicker } from '..';
import { PanelOptionsGroup } from '..';
2019-01-14 20:50:06 +08:00
import { colors } from '../../utils';
import { getColorFromHexRgbOrName, ThemeContext } from '@grafana/ui';
2018-11-21 00:01:58 +08:00
export interface Props {
thresholds: Threshold[];
onChange: (thresholds: Threshold[]) => void;
}
2018-11-21 00:01:58 +08:00
interface State {
thresholds: Threshold[];
}
export class ThresholdsEditor extends PureComponent<Props, State> {
constructor(props: Props) {
2018-11-21 22:18:12 +08:00
super(props);
2019-01-17 15:19:40 +08:00
const addDefaultThreshold = this.props.thresholds.length === 0;
const thresholds: Threshold[] = addDefaultThreshold
? [{ index: 0, value: -Infinity, color: colors[0] }]
: props.thresholds;
2019-01-15 18:26:13 +08:00
this.state = { thresholds };
2019-01-17 15:19:40 +08:00
if (addDefaultThreshold) {
this.onChange();
}
2018-11-21 22:18:12 +08:00
}
2018-11-21 00:01:58 +08:00
onAddThreshold = (index: number) => {
2018-11-27 20:42:13 +08:00
const { thresholds } = this.state;
2019-01-14 20:50:06 +08:00
const maxValue = 100;
const minValue = 0;
if (index === 0) {
return;
}
2018-11-27 20:42:13 +08:00
2018-11-28 22:43:49 +08:00
const newThresholds = thresholds.map(threshold => {
2018-11-22 18:41:09 +08:00
if (threshold.index >= index) {
2019-01-14 20:50:06 +08:00
const index = threshold.index + 1;
threshold = { ...threshold, index };
2018-11-22 18:41:09 +08:00
}
return threshold;
});
2018-12-14 20:23:22 +08:00
// Setting value to a value between the previous thresholds
const beforeThreshold = newThresholds.filter(t => t.index === index - 1 && t.index !== 0)[0];
const afterThreshold = newThresholds.filter(t => t.index === index + 1 && t.index !== 0)[0];
const beforeThresholdValue = beforeThreshold !== undefined ? beforeThreshold.value : minValue;
const afterThresholdValue = afterThreshold !== undefined ? afterThreshold.value : maxValue;
2019-01-14 20:50:06 +08:00
const value = afterThresholdValue - (afterThresholdValue - beforeThresholdValue) / 2;
2018-12-17 21:15:04 +08:00
2019-01-14 20:50:06 +08:00
// Set a color
const color = colors.filter(c => !newThresholds.some(t => t.color === c))[0];
2018-11-22 18:41:09 +08:00
2018-11-29 20:44:35 +08:00
this.setState(
2018-11-29 22:04:49 +08:00
{
thresholds: this.sortThresholds([
...newThresholds,
{
color,
index,
value: value as number,
},
]),
2018-11-29 22:04:49 +08:00
},
2019-01-17 15:19:40 +08:00
() => this.onChange()
2018-11-29 20:44:35 +08:00
);
2018-11-21 22:18:12 +08:00
};
onRemoveThreshold = (threshold: Threshold) => {
if (threshold.index === 0) {
return;
}
2018-11-29 22:07:31 +08:00
this.setState(
2019-01-15 16:35:37 +08:00
prevState => {
const newThresholds = prevState.thresholds.map(t => {
if (t.index > threshold.index) {
const index = t.index - 1;
t = { ...t, index };
}
return t;
});
return {
thresholds: newThresholds.filter(t => t !== threshold),
};
},
2019-01-17 15:19:40 +08:00
() => this.onChange()
2018-11-29 22:07:31 +08:00
);
2018-11-21 22:18:12 +08:00
};
onChangeThresholdValue = (event: ChangeEvent<HTMLInputElement>, threshold: Threshold) => {
if (threshold.index === 0) {
return;
}
2018-11-27 20:42:13 +08:00
const { thresholds } = this.state;
const cleanValue = event.target.value.replace(/,/g, '.');
const parsedValue = parseFloat(cleanValue);
const value = isNaN(parsedValue) ? '' : parsedValue;
2018-11-27 20:42:13 +08:00
2018-11-29 21:22:43 +08:00
const newThresholds = thresholds.map(t => {
2019-01-18 14:10:00 +08:00
if (t === threshold && t.index !== 0) {
2019-01-16 02:45:46 +08:00
t = { ...t, value: value as number };
2018-11-27 22:06:39 +08:00
}
2018-11-29 21:22:43 +08:00
return t;
2018-11-27 22:06:39 +08:00
});
this.setState({ thresholds: newThresholds });
2018-11-27 22:06:39 +08:00
};
onChangeThresholdColor = (threshold: Threshold, color: string) => {
2018-11-27 22:06:39 +08:00
const { thresholds } = this.state;
2018-11-29 21:22:43 +08:00
const newThresholds = thresholds.map(t => {
if (t === threshold) {
t = { ...t, color: color };
2018-11-21 22:18:12 +08:00
}
2018-11-29 21:22:43 +08:00
return t;
2018-11-21 22:18:12 +08:00
});
2018-11-29 20:44:35 +08:00
this.setState(
{
thresholds: newThresholds,
},
2019-01-17 15:19:40 +08:00
() => this.onChange()
2018-11-29 20:44:35 +08:00
);
2018-11-21 22:18:12 +08:00
};
2018-11-22 18:41:09 +08:00
onBlur = () => {
this.setState(prevState => {
const sortThresholds = this.sortThresholds([...prevState.thresholds]);
let index = 0;
sortThresholds.forEach(t => {
t.index = index++;
});
return { thresholds: sortThresholds };
});
2018-11-21 22:18:12 +08:00
2019-01-17 15:19:40 +08:00
this.onChange();
2018-11-29 20:44:35 +08:00
};
2019-01-17 15:19:40 +08:00
onChange = () => {
this.props.onChange(this.state.thresholds);
2018-11-22 18:41:09 +08:00
};
2018-11-21 22:18:12 +08:00
sortThresholds = (thresholds: Threshold[]) => {
2018-11-22 18:41:09 +08:00
return thresholds.sort((t1, t2) => {
return t1.value - t2.value;
2018-11-21 22:18:12 +08:00
});
};
2019-01-14 23:40:44 +08:00
renderInput = (threshold: Threshold) => {
2018-11-23 23:12:53 +08:00
return (
2019-01-14 23:40:44 +08:00
<div className="thresholds-row-input-inner">
2019-01-15 16:35:37 +08:00
<span className="thresholds-row-input-inner-arrow" />
2019-01-14 23:40:44 +08:00
<div className="thresholds-row-input-inner-color">
{threshold.color && (
<div className="thresholds-row-input-inner-color-colorpicker">
<ColorPicker color={threshold.color} onChange={color => this.onChangeThresholdColor(threshold, color)} />
2018-12-14 23:27:42 +08:00
</div>
2019-01-14 23:40:44 +08:00
)}
2018-12-14 23:27:42 +08:00
</div>
2019-02-19 14:48:54 +08:00
{threshold.index === 0 && (
<div className="thresholds-row-input-inner-value">
<input type="text" value="Base" readOnly />
2019-01-14 23:40:44 +08:00
</div>
)}
2019-02-19 14:48:54 +08:00
{threshold.index > 0 && (
<>
<div className="thresholds-row-input-inner-value">
<input
type="number"
step="0.0001"
onChange={event => this.onChangeThresholdValue(event, threshold)}
value={threshold.value}
onBlur={this.onBlur}
readOnly={threshold.index === 0}
/>
</div>
<div className="thresholds-row-input-inner-remove" onClick={() => this.onRemoveThreshold(threshold)}>
<i className="fa fa-times" />
</div>
</>
)}
2018-12-13 23:46:10 +08:00
</div>
);
2019-01-14 23:40:44 +08:00
};
2018-11-22 18:41:09 +08:00
render() {
2019-01-14 23:40:44 +08:00
const { thresholds } = this.state;
2018-11-21 00:01:58 +08:00
return (
<ThemeContext.Consumer>
{theme => {
return (
<PanelOptionsGroup title="Thresholds">
<div className="thresholds">
{thresholds
.slice(0)
.reverse()
.map((threshold, index) => {
return (
<div className="thresholds-row" key={`${threshold.index}-${index}`}>
<div
className="thresholds-row-add-button"
onClick={() => this.onAddThreshold(threshold.index + 1)}
>
<i className="fa fa-plus" />
</div>
<div
className="thresholds-row-color-indicator"
style={{ backgroundColor: getColorFromHexRgbOrName(threshold.color, theme.type) }}
/>
<div className="thresholds-row-input">{this.renderInput(threshold)}</div>
</div>
);
})}
2019-01-14 23:40:44 +08:00
</div>
</PanelOptionsGroup>
);
}}
</ThemeContext.Consumer>
2018-11-21 00:01:58 +08:00
);
}
}