Commit caa47759 by Torkel Ödegaard Committed by GitHub

Merge pull request #15504 from grafana/thresholds-sort-order

Fixing array direction, adding simple render test
parents 3d994b16 93e8edfd
...@@ -84,9 +84,9 @@ describe('Get thresholds formatted', () => { ...@@ -84,9 +84,9 @@ describe('Get thresholds formatted', () => {
it('should get the correct formatted values when thresholds are added', () => { it('should get the correct formatted values when thresholds are added', () => {
const { instance } = setup({ const { instance } = setup({
thresholds: [ thresholds: [
{ index: 2, value: 75, color: '#6ED0E0' },
{ index: 1, value: 50, color: '#EAB839' },
{ index: 0, value: -Infinity, color: '#7EB26D' }, { index: 0, value: -Infinity, color: '#7EB26D' },
{ index: 1, value: 50, color: '#EAB839' },
{ index: 2, value: 75, color: '#6ED0E0' },
], ],
}); });
......
...@@ -98,16 +98,15 @@ export class Gauge extends PureComponent<Props> { ...@@ -98,16 +98,15 @@ export class Gauge extends PureComponent<Props> {
getFormattedThresholds() { getFormattedThresholds() {
const { maxValue, minValue, thresholds, theme } = this.props; const { maxValue, minValue, thresholds, theme } = this.props;
const thresholdsSortedByIndex = [...thresholds].sort((t1, t2) => t1.index - t2.index); const lastThreshold = thresholds[thresholds.length - 1];
const lastThreshold = thresholdsSortedByIndex[thresholdsSortedByIndex.length - 1];
return [ return [
...thresholdsSortedByIndex.map(threshold => { ...thresholds.map(threshold => {
if (threshold.index === 0) { if (threshold.index === 0) {
return { value: minValue, color: getColorFromHexRgbOrName(threshold.color, theme.type) }; return { value: minValue, color: getColorFromHexRgbOrName(threshold.color, theme.type) };
} }
const previousThreshold = thresholdsSortedByIndex[threshold.index - 1]; const previousThreshold = thresholds[threshold.index - 1];
return { value: threshold.value, color: getColorFromHexRgbOrName(previousThreshold.color, theme.type) }; return { value: threshold.value, color: getColorFromHexRgbOrName(previousThreshold.color, theme.type) };
}), }),
{ value: maxValue, color: getColorFromHexRgbOrName(lastThreshold.color, theme.type) }, { value: maxValue, color: getColorFromHexRgbOrName(lastThreshold.color, theme.type) },
......
import React, { ChangeEvent } from 'react'; import React, { ChangeEvent } from 'react';
import { shallow } from 'enzyme'; import { mount } from 'enzyme';
import { ThresholdsEditor, Props } from './ThresholdsEditor'; import { ThresholdsEditor, Props } from './ThresholdsEditor';
const setup = (propOverrides?: object) => { const setup = (propOverrides?: Partial<Props>) => {
const props: Props = { const props: Props = {
onChange: jest.fn(), onChange: jest.fn(),
thresholds: [], thresholds: [],
...@@ -11,12 +10,26 @@ const setup = (propOverrides?: object) => { ...@@ -11,12 +10,26 @@ const setup = (propOverrides?: object) => {
Object.assign(props, propOverrides); Object.assign(props, propOverrides);
return shallow(<ThresholdsEditor {...props} />).instance() as ThresholdsEditor; const wrapper = mount(<ThresholdsEditor {...props} />);
const instance = wrapper.instance() as ThresholdsEditor;
return {
instance,
wrapper,
};
}; };
describe('Render', () => {
it('should render with base threshold', () => {
const { wrapper } = setup();
expect(wrapper).toMatchSnapshot();
});
});
describe('Initialization', () => { describe('Initialization', () => {
it('should add a base threshold if missing', () => { it('should add a base threshold if missing', () => {
const instance = setup(); const { instance } = setup();
expect(instance.state.thresholds).toEqual([{ index: 0, value: -Infinity, color: '#7EB26D' }]); expect(instance.state.thresholds).toEqual([{ index: 0, value: -Infinity, color: '#7EB26D' }]);
}); });
...@@ -24,7 +37,7 @@ describe('Initialization', () => { ...@@ -24,7 +37,7 @@ describe('Initialization', () => {
describe('Add threshold', () => { describe('Add threshold', () => {
it('should not add threshold at index 0', () => { it('should not add threshold at index 0', () => {
const instance = setup(); const { instance } = setup();
instance.onAddThreshold(0); instance.onAddThreshold(0);
...@@ -32,32 +45,32 @@ describe('Add threshold', () => { ...@@ -32,32 +45,32 @@ describe('Add threshold', () => {
}); });
it('should add threshold', () => { it('should add threshold', () => {
const instance = setup(); const { instance } = setup();
instance.onAddThreshold(1); instance.onAddThreshold(1);
expect(instance.state.thresholds).toEqual([ expect(instance.state.thresholds).toEqual([
{ index: 1, value: 50, color: '#EAB839' },
{ index: 0, value: -Infinity, color: '#7EB26D' }, { index: 0, value: -Infinity, color: '#7EB26D' },
{ index: 1, value: 50, color: '#EAB839' },
]); ]);
}); });
it('should add another threshold above a first', () => { it('should add another threshold above a first', () => {
const instance = setup({ const { instance } = setup({
thresholds: [{ index: 0, value: -Infinity, color: '#7EB26D' }, { index: 1, value: 50, color: '#EAB839' }], thresholds: [{ index: 0, value: -Infinity, color: '#7EB26D' }, { index: 1, value: 50, color: '#EAB839' }],
}); });
instance.onAddThreshold(2); instance.onAddThreshold(2);
expect(instance.state.thresholds).toEqual([ expect(instance.state.thresholds).toEqual([
{ index: 2, value: 75, color: '#6ED0E0' },
{ index: 1, value: 50, color: '#EAB839' },
{ index: 0, value: -Infinity, color: '#7EB26D' }, { index: 0, value: -Infinity, color: '#7EB26D' },
{ index: 1, value: 50, color: '#EAB839' },
{ index: 2, value: 75, color: '#6ED0E0' },
]); ]);
}); });
it('should add another threshold between first and second index', () => { it('should add another threshold between first and second index', () => {
const instance = setup({ const { instance } = setup({
thresholds: [ thresholds: [
{ index: 0, value: -Infinity, color: '#7EB26D' }, { index: 0, value: -Infinity, color: '#7EB26D' },
{ index: 1, value: 50, color: '#EAB839' }, { index: 1, value: 50, color: '#EAB839' },
...@@ -68,10 +81,10 @@ describe('Add threshold', () => { ...@@ -68,10 +81,10 @@ describe('Add threshold', () => {
instance.onAddThreshold(2); instance.onAddThreshold(2);
expect(instance.state.thresholds).toEqual([ expect(instance.state.thresholds).toEqual([
{ index: 3, value: 75, color: '#6ED0E0' },
{ index: 2, value: 62.5, color: '#EF843C' },
{ index: 1, value: 50, color: '#EAB839' },
{ index: 0, value: -Infinity, color: '#7EB26D' }, { index: 0, value: -Infinity, color: '#7EB26D' },
{ index: 1, value: 50, color: '#EAB839' },
{ index: 2, value: 62.5, color: '#EF843C' },
{ index: 3, value: 75, color: '#6ED0E0' },
]); ]);
}); });
}); });
...@@ -83,7 +96,7 @@ describe('Remove threshold', () => { ...@@ -83,7 +96,7 @@ describe('Remove threshold', () => {
{ index: 1, value: 50, color: '#EAB839' }, { index: 1, value: 50, color: '#EAB839' },
{ index: 2, value: 75, color: '#6ED0E0' }, { index: 2, value: 75, color: '#6ED0E0' },
]; ];
const instance = setup({ thresholds }); const { instance } = setup({ thresholds });
instance.onRemoveThreshold(thresholds[0]); instance.onRemoveThreshold(thresholds[0]);
...@@ -96,9 +109,7 @@ describe('Remove threshold', () => { ...@@ -96,9 +109,7 @@ describe('Remove threshold', () => {
{ index: 1, value: 50, color: '#EAB839' }, { index: 1, value: 50, color: '#EAB839' },
{ index: 2, value: 75, color: '#6ED0E0' }, { index: 2, value: 75, color: '#6ED0E0' },
]; ];
const instance = setup({ const { instance } = setup({ thresholds });
thresholds,
});
instance.onRemoveThreshold(thresholds[1]); instance.onRemoveThreshold(thresholds[1]);
...@@ -116,7 +127,7 @@ describe('change threshold value', () => { ...@@ -116,7 +127,7 @@ describe('change threshold value', () => {
{ index: 1, value: 50, color: '#EAB839' }, { index: 1, value: 50, color: '#EAB839' },
{ index: 2, value: 75, color: '#6ED0E0' }, { index: 2, value: 75, color: '#6ED0E0' },
]; ];
const instance = setup({ thresholds }); const { instance } = setup({ thresholds });
const mockEvent = ({ target: { value: '12' } } as any) as ChangeEvent<HTMLInputElement>; const mockEvent = ({ target: { value: '12' } } as any) as ChangeEvent<HTMLInputElement>;
...@@ -126,7 +137,7 @@ describe('change threshold value', () => { ...@@ -126,7 +137,7 @@ describe('change threshold value', () => {
}); });
it('should update value', () => { it('should update value', () => {
const instance = setup(); const { instance } = setup();
const thresholds = [ const thresholds = [
{ index: 0, value: -Infinity, color: '#7EB26D' }, { index: 0, value: -Infinity, color: '#7EB26D' },
{ index: 1, value: 50, color: '#EAB839' }, { index: 1, value: 50, color: '#EAB839' },
...@@ -150,24 +161,24 @@ describe('change threshold value', () => { ...@@ -150,24 +161,24 @@ describe('change threshold value', () => {
}); });
describe('on blur threshold value', () => { describe('on blur threshold value', () => {
it('should resort rows and update indexes', () => { it.only('should resort rows and update indexes', () => {
const instance = setup(); const { instance } = setup();
const thresholds = [ const thresholds = [
{ index: 0, value: -Infinity, color: '#7EB26D' }, { index: 0, value: -Infinity, color: '#7EB26D' },
{ index: 1, value: 78, color: '#EAB839' }, { index: 1, value: 78, color: '#EAB839' },
{ index: 2, value: 75, color: '#6ED0E0' }, { index: 2, value: 75, color: '#6ED0E0' },
]; ];
instance.state = { instance.setState({
thresholds, thresholds,
}; });
instance.onBlur(); instance.onBlur();
expect(instance.state.thresholds).toEqual([ expect(instance.state.thresholds).toEqual([
{ index: 2, value: 78, color: '#EAB839' },
{ index: 1, value: 75, color: '#6ED0E0' },
{ index: 0, value: -Infinity, color: '#7EB26D' }, { index: 0, value: -Infinity, color: '#7EB26D' },
{ index: 1, value: 75, color: '#6ED0E0' },
{ index: 2, value: 78, color: '#EAB839' },
]); ]);
}); });
}); });
import React, { PureComponent, ChangeEvent } from 'react'; import React, { PureComponent, ChangeEvent } from 'react';
import { Threshold } from '../../types'; import { Threshold } from '../../types';
import { ColorPicker } from '../ColorPicker/ColorPicker'; import { ColorPicker } from '..';
import { PanelOptionsGroup } from '../PanelOptionsGroup/PanelOptionsGroup'; import { PanelOptionsGroup } from '..';
import { colors } from '../../utils'; import { colors } from '../../utils';
import { getColorFromHexRgbOrName, ThemeContext } from '@grafana/ui'; import { getColorFromHexRgbOrName, ThemeContext } from '@grafana/ui';
...@@ -54,16 +54,16 @@ export class ThresholdsEditor extends PureComponent<Props, State> { ...@@ -54,16 +54,16 @@ export class ThresholdsEditor extends PureComponent<Props, State> {
const value = afterThresholdValue - (afterThresholdValue - beforeThresholdValue) / 2; const value = afterThresholdValue - (afterThresholdValue - beforeThresholdValue) / 2;
// Set a color // Set a color
const color = colors.filter(c => newThresholds.some(t => t.color === c) === false)[0]; const color = colors.filter(c => !newThresholds.some(t => t.color === c))[0];
this.setState( this.setState(
{ {
thresholds: this.sortThresholds([ thresholds: this.sortThresholds([
...newThresholds, ...newThresholds,
{ {
color,
index, index,
value: value as number, value: value as number,
color,
}, },
]), ]),
}, },
...@@ -137,10 +137,11 @@ export class ThresholdsEditor extends PureComponent<Props, State> { ...@@ -137,10 +137,11 @@ export class ThresholdsEditor extends PureComponent<Props, State> {
onBlur = () => { onBlur = () => {
this.setState(prevState => { this.setState(prevState => {
const sortThresholds = this.sortThresholds([...prevState.thresholds]); const sortThresholds = this.sortThresholds([...prevState.thresholds]);
let index = sortThresholds.length - 1; let index = 0;
sortThresholds.forEach(t => { sortThresholds.forEach(t => {
t.index = index--; t.index = index++;
}); });
return { thresholds: sortThresholds }; return { thresholds: sortThresholds };
}); });
...@@ -153,12 +154,13 @@ export class ThresholdsEditor extends PureComponent<Props, State> { ...@@ -153,12 +154,13 @@ export class ThresholdsEditor extends PureComponent<Props, State> {
sortThresholds = (thresholds: Threshold[]) => { sortThresholds = (thresholds: Threshold[]) => {
return thresholds.sort((t1, t2) => { return thresholds.sort((t1, t2) => {
return t2.value - t1.value; return t1.value - t2.value;
}); });
}; };
renderInput = (threshold: Threshold) => { renderInput = (threshold: Threshold) => {
const value = threshold.index === 0 ? 'Base' : threshold.value; const value = threshold.index === 0 ? 'Base' : threshold.value;
return ( return (
<div className="thresholds-row-input-inner"> <div className="thresholds-row-input-inner">
<span className="thresholds-row-input-inner-arrow" /> <span className="thresholds-row-input-inner-arrow" />
...@@ -190,14 +192,16 @@ export class ThresholdsEditor extends PureComponent<Props, State> { ...@@ -190,14 +192,16 @@ export class ThresholdsEditor extends PureComponent<Props, State> {
render() { render() {
const { thresholds } = this.state; const { thresholds } = this.state;
return ( return (
<ThemeContext.Consumer> <ThemeContext.Consumer>
{theme => { {theme => {
return ( return (
<PanelOptionsGroup title="Thresholds"> <PanelOptionsGroup title="Thresholds">
<div className="thresholds"> <div className="thresholds">
{thresholds.map((threshold, index) => { {thresholds
.slice(0)
.reverse()
.map((threshold, index) => {
return ( return (
<div className="thresholds-row" key={`${threshold.index}-${index}`}> <div className="thresholds-row" key={`${threshold.index}-${index}`}>
<div <div
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Render should render with base threshold 1`] = `
<ContextConsumer>
<Component />
</ContextConsumer>
`;
...@@ -399,6 +399,12 @@ export class DashboardMigrator { ...@@ -399,6 +399,12 @@ export class DashboardMigrator {
prefix: panel.options.prefix, prefix: panel.options.prefix,
suffix: panel.options.suffix, suffix: panel.options.suffix,
}; };
// correct order
if (panel.options.thresholds) {
panel.options.thresholds.reverse();
}
// this options prop was due to a bug // this options prop was due to a bug
delete panel.options.options; delete panel.options.options;
delete panel.options.unit; delete panel.options.unit;
......
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