+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info 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 * as React from 'react';
-import { sortBy } from 'lodash';
-import Select from '../../../components/controls/Select';
-import { translate, getLocalizedMetricName, getLocalizedMetricDomain } from '../../../helpers/l10n';
-
-interface Props {
- metrics: T.Metric[];
- onAddCondition: (metric: T.Metric) => void;
-}
-
-interface State {
- value: number;
-}
-
-interface Option {
- disabled?: boolean;
- domain?: string;
- label: string;
- value: number;
-}
-
-export default class AddConditionSelect extends React.PureComponent<Props, State> {
- state = { value: -1 };
-
- handleChange = ({ value }: Option) => {
- this.setState({ value });
- this.props.onAddCondition(this.props.metrics[value]);
- };
-
- render() {
- const { metrics } = this.props;
-
- const options: Option[] = sortBy(
- metrics.map((metric, index) => ({
- value: index,
- label: getLocalizedMetricName(metric),
- domain: metric.domain
- })),
- 'domain'
- );
-
- // use "disabled" property to emulate optgroups
- const optionsWithDomains: Option[] = [];
- options.forEach((option, index, options) => {
- const previous = index > 0 ? options[index - 1] : null;
- if (option.domain && (!previous || previous.domain !== option.domain)) {
- optionsWithDomains.push({
- value: 0,
- label: getLocalizedMetricDomain(option.domain),
- disabled: true
- });
- }
- optionsWithDomains.push(option);
- });
-
- return (
- <Select
- className="text-middle input-large"
- onChange={this.handleChange}
- options={optionsWithDomains}
- placeholder={translate('quality_gates.add_condition')}
- value={this.state.value}
- />
- );
- }
-}
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import ConditionOperator from './ConditionOperator';
import ConditionModal from './ConditionModal';
import ActionsDropdown, { ActionsDropdownItem } from '../../../components/controls/ActionsDropdown';
import { translate, getLocalizedMetricName, translateWithParameters } from '../../../helpers/l10n';
);
};
+ renderOperator() {
+ // TODO can operator be missing?
+ const { op = 'GT' } = this.props.condition;
+ return (
+ <span className="note">
+ {this.props.metric.type === 'RATING'
+ ? translate('quality_gates.operator', op, 'rating')
+ : translate('quality_gates.operator', op)}
+ </span>
+ );
+ }
+
render() {
const { condition, canEdit, metric, organization, qualityGate } = this.props;
return (
)}
</td>
- <td className="thin text-middle nowrap">
- <ConditionOperator canEdit={false} metric={metric} op={condition.op} />
- </td>
+ <td className="thin text-middle nowrap">{this.renderOperator()}</td>
<td className="thin text-middle nowrap">{formatMeasure(condition.error, metric.type)}</td>
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import AddConditionSelect from './AddConditionSelect';
+import MetricSelect from './MetricSelect';
import ConditionOperator from './ConditionOperator';
import ThresholdInput from './ThresholdInput';
import { translate, getLocalizedMetricName } from '../../../helpers/l10n';
import { createCondition, updateCondition } from '../../../api/quality-gates';
import ConfirmModal from '../../../components/controls/ConfirmModal';
import { Alert } from '../../../components/ui/Alert';
+import { getPossibleOperators } from '../utils';
interface Props {
condition?: T.Condition;
this.mounted = false;
}
- getUpdatedCondition = (metric: T.Metric) => {
- return {
- metric: metric.key,
- op: metric.type === 'RATING' ? 'GT' : this.state.op,
- error: this.state.error
- };
- };
+ getSinglePossibleOperator(metric: T.Metric) {
+ const operators = getPossibleOperators(metric);
+ return Array.isArray(operators) ? undefined : operators;
+ }
handleFormSubmit = () => {
if (this.state.metric) {
const { condition, qualityGate, organization } = this.props;
- const newCondition = this.getUpdatedCondition(this.state.metric);
- let submitPromise: Promise<T.Condition>;
- if (condition) {
- submitPromise = updateCondition({ organization, id: condition.id, ...newCondition });
- } else {
- submitPromise = createCondition({ gateId: qualityGate.id, organization, ...newCondition });
- }
+ const newCondition: T.Omit<T.Condition, 'id'> = {
+ metric: this.state.metric.key,
+ op: this.getSinglePossibleOperator(this.state.metric) || this.state.op,
+ error: this.state.error
+ };
+ const submitPromise = condition
+ ? updateCondition({ organization, id: condition.id, ...newCondition })
+ : createCondition({ gateId: qualityGate.id, organization, ...newCondition });
return submitPromise.then(this.props.onAddCondition);
}
return Promise.reject();
};
- handleChooseType = (metric: T.Metric) => {
- this.setState({ metric });
+ handleMetricChange = (metric: T.Metric) => {
+ this.setState({ metric, op: undefined, error: '' });
};
handleOperatorChange = (op: string) => {
{this.state.errorMessage && <Alert variant="error">{this.state.errorMessage}</Alert>}
<div className="modal-field">
<label htmlFor="create-user-login">{translate('quality_gates.conditions.metric')}</label>
- {metrics && (
- <AddConditionSelect metrics={metrics} onAddCondition={this.handleChooseType} />
- )}
+ {metrics && <MetricSelect metrics={metrics} onMetricChange={this.handleMetricChange} />}
{this.props.metric && (
<span className="note">{getLocalizedMetricName(this.props.metric)}</span>
)}
<div className="modal-field">
<label>{translate('quality_gates.conditions.operator')}</label>
<ConditionOperator
- canEdit={true}
metric={metric}
onOperatorChange={this.handleOperatorChange}
op={op}
import * as React from 'react';
import Select from '../../../components/controls/Select';
import { translate } from '../../../helpers/l10n';
+import { getPossibleOperators } from '../utils';
interface Props {
op?: string;
- canEdit: boolean;
metric: T.Metric;
- onOperatorChange?: (op: string) => void;
+ onOperatorChange: (op: string) => void;
}
export default class ConditionOperator extends React.PureComponent<Props> {
handleChange = ({ value }: { label: string; value: string }) => {
- if (this.props.onOperatorChange) {
- this.props.onOperatorChange(value);
- }
+ this.props.onOperatorChange(value);
};
- render() {
- const { canEdit, metric, op } = this.props;
- if (!canEdit && op) {
- return metric.type === 'RATING' ? (
- <span className="note">{translate('quality_gates.operator', op, 'rating')}</span>
- ) : (
- <span className="note">{translate('quality_gates.operator', op)}</span>
- );
- }
+ getLabel(op: string, metric: T.Metric) {
+ return metric.type === 'RATING'
+ ? translate('quality_gates.operator', op, 'rating')
+ : translate('quality_gates.operator', op);
+ }
- if (metric.type === 'RATING') {
- return <span className="note">{translate('quality_gates.operator.GT.rating')}</span>;
- }
+ render() {
+ const operators = getPossibleOperators(this.props.metric);
- const operators = ['LT', 'GT', 'EQ', 'NE'];
- const operatorOptions = operators.map(op => {
- const label = translate('quality_gates.operator', op);
- return { label, value: op };
- });
+ if (Array.isArray(operators)) {
+ const operatorOptions = operators.map(op => {
+ const label = this.getLabel(op, this.props.metric);
+ return { label, value: op };
+ });
- return (
- <Select
- autoFocus={true}
- className="input-medium"
- clearable={false}
- name="operator"
- onChange={this.handleChange}
- options={operatorOptions}
- searchable={false}
- value={op}
- />
- );
+ return (
+ <Select
+ autoFocus={true}
+ className="input-medium"
+ clearable={false}
+ name="operator"
+ onChange={this.handleChange}
+ options={operatorOptions}
+ searchable={false}
+ value={this.props.op}
+ />
+ );
+ } else {
+ return <span className="note">{this.getLabel(operators, this.props.metric)}</span>;
+ }
}
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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 * as React from 'react';
+import { sortBy } from 'lodash';
+import Select from '../../../components/controls/Select';
+import { translate, getLocalizedMetricName, getLocalizedMetricDomain } from '../../../helpers/l10n';
+
+interface Props {
+ metrics: T.Metric[];
+ onMetricChange: (metric: T.Metric) => void;
+}
+
+interface State {
+ value: number;
+}
+
+interface Option {
+ disabled?: boolean;
+ domain?: string;
+ label: string;
+ value: number;
+}
+
+export default class MetricSelect extends React.PureComponent<Props, State> {
+ state = { value: -1 };
+
+ handleChange = ({ value }: Option) => {
+ this.setState({ value });
+ this.props.onMetricChange(this.props.metrics[value]);
+ };
+
+ render() {
+ const { metrics } = this.props;
+
+ const options: Option[] = sortBy(
+ metrics.map((metric, index) => ({
+ value: index,
+ label: getLocalizedMetricName(metric),
+ domain: metric.domain
+ })),
+ 'domain'
+ );
+
+ // use "disabled" property to emulate optgroups
+ const optionsWithDomains: Option[] = [];
+ options.forEach((option, index, options) => {
+ const previous = index > 0 ? options[index - 1] : null;
+ if (option.domain && (!previous || previous.domain !== option.domain)) {
+ optionsWithDomains.push({
+ value: 0,
+ label: getLocalizedMetricDomain(option.domain),
+ disabled: true
+ });
+ }
+ optionsWithDomains.push(option);
+ });
+
+ return (
+ <Select
+ className="text-middle input-large"
+ onChange={this.handleChange}
+ options={optionsWithDomains}
+ placeholder={translate('search.search_for_metrics')}
+ value={this.state.value}
+ />
+ );
+ }
+}
});
return { ...qualityGate, conditions };
}
+
+export function getPossibleOperators(metric: T.Metric) {
+ if (metric.direction === 1) {
+ return 'LT';
+ } else if (metric.direction === -1) {
+ return 'GT';
+ } else {
+ return ['LT', 'GT'];
+ }
+}
search.search_for_directories=Search for directories...
search.search_for_files=Search for files...
search.search_for_modules=Search for modules...
+search.search_for_metrics=Search for metrics...
#------------------------------------------------------------------------------