diff options
author | Stas Vilchik <vilchiks@gmail.com> | 2016-09-22 09:34:27 +0200 |
---|---|---|
committer | Julien Lancelot <julien.lancelot@sonarsource.com> | 2016-09-22 14:10:33 +0200 |
commit | 1254f51378c109ab72392723926df8e4c5050f65 (patch) | |
tree | cc9bfd8565bc9c2ee92757bf09fcc3f839399900 | |
parent | 2bd140137075519bbe4018c9942fec05172d1215 (diff) | |
download | sonarqube-1254f51378c109ab72392723926df8e4c5050f65.tar.gz sonarqube-1254f51378c109ab72392723926df8e4c5050f65.zip |
SONAR-8136 Provide a special input to configure conditions based on ratings
3 files changed, 202 insertions, 20 deletions
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/Condition.js b/server/sonar-web/src/main/js/apps/quality-gates/components/Condition.js index 8169218183e..ffff916d31e 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/Condition.js +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/Condition.js @@ -20,6 +20,7 @@ import React, { Component } from 'react'; import Select from 'react-select'; +import ThresholdInput from './ThresholdInput'; import DeleteConditionView from '../views/gate-conditions-delete-view'; import Checkbox from '../../../components/controls/Checkbox'; import { createCondition, updateCondition } from '../../../api/quality-gates'; @@ -33,7 +34,9 @@ export default class Condition extends Component { this.state = { changed: false, period: props.condition.period, - op: props.condition.op + op: props.condition.op, + warning: props.condition.warning || '', + error: props.condition.error || '' }; } @@ -59,14 +62,22 @@ export default class Condition extends Component { this.setState({ changed: true, period }); } + handleWarningChange (value) { + this.setState({ changed: true, warning: value }); + } + + handleErrorChange (value) { + this.setState({ changed: true, error: value }); + } + handleSaveClick (e) { const { qualityGate, condition, onSaveCondition, onError, onResetError } = this.props; const period = this.state.period; const data = { metric: condition.metric, op: this.state.op, - warning: this.refs.warning.value, - error: this.refs.error.value + warning: this.state.warning, + error: this.state.error }; if (period) { @@ -92,8 +103,8 @@ export default class Condition extends Component { id: condition.id, metric: condition.metric, op: this.state.op, - warning: this.refs.warning.value, - error: this.refs.error.value + warning: this.state.warning, + error: this.state.error }; if (period) { @@ -194,28 +205,21 @@ export default class Condition extends Component { <td className="thin text-middle nowrap"> {edit ? ( - <input - ref="warning" + <ThresholdInput name="warning" - type="text" - className="input-tiny text-middle" - defaultValue={condition.warning} - data-type={metric.type} - placeholder={metric.placeholder} - onChange={this.handleChange}/> + value={this.state.warning} + metric={metric} + onChange={value => this.handleWarningChange(value)}/> ) : formatMeasure(condition.warning, metric.type)} </td> <td className="thin text-middle nowrap"> {edit ? ( - <input - ref="error" + <ThresholdInput name="error" - type="text" - className="input-tiny text-middle" - defaultValue={condition.error} - data-type={metric.type} - onChange={this.handleChange}/> + value={this.state.error} + metric={metric} + onChange={value => this.handleErrorChange(value)}/> ) : formatMeasure(condition.error, metric.type)} </td> diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/ThresholdInput.js b/server/sonar-web/src/main/js/apps/quality-gates/components/ThresholdInput.js new file mode 100644 index 00000000000..bbd08294bdb --- /dev/null +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/ThresholdInput.js @@ -0,0 +1,86 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import React from 'react'; +import Select from 'react-select'; + +export default class ThresholdInput extends React.Component { + static propTypes = { + name: React.PropTypes.string.isRequired, + value: React.PropTypes.any, + metric: React.PropTypes.object.isRequired, + onChange: React.PropTypes.func.isRequired + }; + + handleChange = e => { + this.props.onChange(e.target.value); + }; + + handleSelectChange = option => { + if (option) { + this.props.onChange(option.value); + } else { + this.props.onChange(''); + } + }; + + renderRatingInput () { + const { name, value } = this.props; + + const options = [ + { label: 'A', value: '1' }, + { label: 'B', value: '2' }, + { label: 'C', value: '3' }, + { label: 'D', value: '4' }, + { label: 'E', value: '5' } + ]; + + const realValue = value === '' ? null : value; + + return ( + <Select + className="input-tiny text-middle" + name={name} + value={realValue} + options={options} + searchable={false} + placeholder="" + onChange={this.handleSelectChange}/> + ); + } + + render () { + const { name, value, metric } = this.props; + + if (metric.type === 'RATING') { + return this.renderRatingInput(); + } + + return ( + <input + name={name} + type="text" + className="input-tiny text-middle" + value={value} + data-type={metric.type} + placeholder={metric.placeholder} + onChange={this.handleChange}/> + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/ThresholdInput-test.js b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/ThresholdInput-test.js new file mode 100644 index 00000000000..2fdfc7fd9f0 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/ThresholdInput-test.js @@ -0,0 +1,92 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import React from 'react'; +import { shallow } from 'enzyme'; +import Select from 'react-select'; +import ThresholdInput from '../ThresholdInput'; +import { change } from '../../../../../../../tests/utils'; + +describe('on strings', () => { + it('should render text input', () => { + const input = shallow( + <ThresholdInput + name="foo" + value="2" + metric={{ type: 'INTEGER' }} + onChange={jest.fn()}/> + ).find('input'); + expect(input.length).toEqual(1); + expect(input.prop('name')).toEqual('foo'); + expect(input.prop('value')).toEqual('2'); + }); + + it('should change', () => { + const onChange = jest.fn(); + const input = shallow( + <ThresholdInput + name="foo" + value="2" + metric={{ type: 'INTEGER' }} + onChange={onChange}/> + ).find('input'); + change(input, 'bar'); + expect(onChange).toBeCalledWith('bar'); + }); +}); + +describe('on ratings', () => { + it('should render Select', () => { + const select = shallow( + <ThresholdInput + name="foo" + value="2" + metric={{ type: 'RATING' }} + onChange={jest.fn()}/> + ).find(Select); + expect(select.length).toEqual(1); + expect(select.prop('value')).toEqual('2'); + }); + + it('should set', () => { + const onChange = jest.fn(); + const select = shallow( + <ThresholdInput + name="foo" + value="2" + metric={{ type: 'RATING' }} + onChange={onChange}/> + ).find(Select); + select.prop('onChange')({ label: 'D', value: '4' }); + expect(onChange).toBeCalledWith('4'); + }); + + it('should unset', () => { + const onChange = jest.fn(); + const select = shallow( + <ThresholdInput + name="foo" + value="2" + metric={{ type: 'RATING' }} + onChange={onChange}/> + ).find(Select); + select.prop('onChange')(null); + expect(onChange).toBeCalledWith(''); + }); +}); |