]> source.dussan.org Git - sonarqube.git/commitdiff
Fix SONAR-10640
authorPascal Mugnier <pascal.mugnier@sonarsource.com>
Wed, 9 May 2018 05:27:30 +0000 (07:27 +0200)
committerSonarTech <sonartech@sonarsource.com>
Thu, 24 May 2018 18:20:46 +0000 (20:20 +0200)
server/sonar-web/src/main/js/apps/quality-gates/components/AddConditionButton.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/quality-gates/components/AddConditionSelect.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/ConditionModal.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/quality-gates/components/ConditionOperator.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/quality-gates/components/Conditions.tsx

diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/AddConditionButton.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/AddConditionButton.tsx
new file mode 100644 (file)
index 0000000..4894313
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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 ConditionModal from './ConditionModal';
+import { Button } from '../../../components/ui/buttons';
+import { translate } from '../../../helpers/l10n';
+import { Metric } from '../../../app/types';
+
+interface Props {
+  metrics: Metric[];
+}
+
+interface State {
+  modal: boolean;
+}
+
+export default class AddConditionButton extends React.PureComponent<Props, State> {
+  mounted = false;
+  state: State = { modal: false };
+
+  componentDidMount() {
+    this.mounted = true;
+  }
+
+  componentWillUnmount() {
+    this.mounted = false;
+  }
+
+  handleClick = () => {
+    this.setState({ modal: true });
+  };
+
+  handleModalClose = () => {
+    if (this.mounted) {
+      this.setState({ modal: false });
+    }
+  };
+
+  render() {
+    return (
+      <>
+        <Button onClick={this.handleClick}>{translate('quality_gates.add_condition')}</Button>
+        {this.state.modal && (
+          <ConditionModal
+            header={translate('quality_gates.add_condition')}
+            metrics={this.props.metrics}
+            onClose={this.handleModalClose}
+          />
+        )}
+      </>
+    );
+  }
+}
index ef67bfd15540de5f527e7d594c2030c580a700dd..8539232bb3f423d0cd7c86d217610918f34b2b43 100644 (file)
@@ -67,14 +67,12 @@ export default class AddConditionSelect extends React.PureComponent<Props> {
     });
 
     return (
-      <div className="big-spacer-top panel bg-muted">
-        <Select
-          className="text-middle input-large"
-          onChange={this.handleChange}
-          options={optionsWithDomains}
-          placeholder={translate('quality_gates.add_condition')}
-        />
-      </div>
+      <Select
+        className="text-middle input-large"
+        onChange={this.handleChange}
+        options={optionsWithDomains}
+        placeholder={translate('quality_gates.add_condition')}
+      />
     );
   }
 }
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/ConditionModal.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/ConditionModal.tsx
new file mode 100644 (file)
index 0000000..f0c2702
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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 AddConditionSelect from './AddConditionSelect';
+import ConditionOperator from './ConditionOperator';
+import Modal from '../../../components/controls/Modal';
+import { SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
+import { translate } from '../../../helpers/l10n';
+import { Metric } from '../../../app/types';
+
+interface Props {
+  metrics: Metric[];
+  header: string;
+  onClose: () => void;
+}
+
+interface State {
+  metric: string;
+  submitting: boolean;
+}
+
+export default class ConditionModal extends React.PureComponent<Props, State> {
+  state = { metric: '', submitting: false };
+
+  handleFormSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => {
+    event.preventDefault();
+    this.setState({ submitting: true });
+  };
+
+  handleChooseType = (metric: string) => {
+    this.setState({ metric });
+  };
+
+  render() {
+    const { header, metrics, onClose } = this.props;
+    const { submitting } = this.state;
+    return (
+      <Modal contentLabel={header} onRequestClose={onClose}>
+        <form onSubmit={this.handleFormSubmit}>
+          <div className="modal-head">
+            <h2>{header}</h2>
+          </div>
+
+          <div className="modal-body">
+            <div className="modal-field">
+              <label htmlFor="create-user-login">
+                {translate('quality_gates.conditions.metric')}
+              </label>
+              <AddConditionSelect metrics={metrics} onAddCondition={this.handleChooseType} />
+            </div>
+            <div className="modal-field">
+              <label htmlFor="create-user-login">
+                {translate('quality_gates.conditions.metric')}
+              </label>
+              <ConditionOperator
+                canEdit={true}
+                condition={}
+                metric={this.state.metric}
+                onOperatorChange={() => {}}
+              />
+            </div>
+          </div>
+
+          <div className="modal-foot">
+            {submitting && <i className="spinner spacer-right" />}
+            <SubmitButton disabled={submitting} id="coding-rules-custom-rule-creation-reactivate">
+              {header}
+            </SubmitButton>
+            <ResetButtonLink
+              disabled={submitting}
+              id="coding-rules-custom-rule-creation-cancel"
+              onClick={onClose}>
+              {translate('cancel')}
+            </ResetButtonLink>
+          </div>
+        </form>
+      </Modal>
+    );
+  }
+}
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/ConditionOperator.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/ConditionOperator.tsx
new file mode 100644 (file)
index 0000000..55c8d3c
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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 Select from '../../../components/controls/Select';
+import { Condition as ICondition, Metric } from '../../../app/types';
+import { translate } from '../../../helpers/l10n';
+
+interface Props {
+  condition: ICondition;
+  canEdit: boolean;
+  metric: Metric;
+  onOperatorChange: ({ value }: any) => void;
+}
+
+export default function ConditionOperator({ condition, canEdit, metric, onOperatorChange }: Props) {
+  if (!canEdit && condition.op) {
+    return metric.type === 'RATING' ? (
+      <span className="note">{translate('quality_gates.operator', condition.op, 'rating')}</span>
+    ) : (
+      <span className="note">{translate('quality_gates.operator', condition.op)}</span>
+    );
+  }
+
+  if (metric.type === 'RATING') {
+    return <span className="note">{translate('quality_gates.operator.GT.rating')}</span>;
+  }
+
+  const operators = ['LT', 'GT', 'EQ', 'NE'];
+  const operatorOptions = operators.map(op => {
+    const label = translate('quality_gates.operator', op);
+    return { label, value: op };
+  });
+
+  return (
+    <Select
+      autofocus={true}
+      className="input-medium"
+      clearable={false}
+      name="operator"
+      onChange={onOperatorChange}
+      options={operatorOptions}
+      searchable={false}
+      value={condition.op}
+    />
+  );
+}
index 0df36b5110fd726c8e94a18b604eb03cb66454b6..07a9f8cc60080555f76f6e90a49f4600b524822a 100644 (file)
@@ -21,6 +21,7 @@ import * as React from 'react';
 import { differenceWith, map, sortBy, uniqBy } from 'lodash';
 import AddConditionSelect from './AddConditionSelect';
 import Condition from './Condition';
+import AddConditionButton from './AddConditionButton';
 import DocTooltip from '../../../components/docs/DocTooltip';
 import { translate, getLocalizedMetricName } from '../../../helpers/l10n';
 import { Condition as ICondition, Metric, QualityGate } from '../../../app/types';
@@ -103,6 +104,9 @@ export default class Conditions extends React.PureComponent<Props, State> {
 
     return (
       <div className="quality-gate-section" id="quality-gate-conditions">
+        <div className="pull-right">
+          <AddConditionButton metrics={availableMetrics} />
+        </div>
         <header className="display-flex-center spacer-bottom">
           <h3>{translate('quality_gates.conditions')}</h3>
           <DocTooltip className="spacer-left" doc="quality-gates/quality-gate-conditions" />