aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStas Vilchik <vilchiks@gmail.com>2016-09-22 09:34:27 +0200
committerJulien Lancelot <julien.lancelot@sonarsource.com>2016-09-22 14:10:33 +0200
commit1254f51378c109ab72392723926df8e4c5050f65 (patch)
treecc9bfd8565bc9c2ee92757bf09fcc3f839399900
parent2bd140137075519bbe4018c9942fec05172d1215 (diff)
downloadsonarqube-1254f51378c109ab72392723926df8e4c5050f65.tar.gz
sonarqube-1254f51378c109ab72392723926df8e4c5050f65.zip
SONAR-8136 Provide a special input to configure conditions based on ratings
-rw-r--r--server/sonar-web/src/main/js/apps/quality-gates/components/Condition.js44
-rw-r--r--server/sonar-web/src/main/js/apps/quality-gates/components/ThresholdInput.js86
-rw-r--r--server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/ThresholdInput-test.js92
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('');
+ });
+});