]> source.dussan.org Git - sonarqube.git/commitdiff
Fix after review
authorPascal Mugnier <pascal.mugnier@sonarsource.com>
Wed, 23 May 2018 07:18:38 +0000 (09:18 +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 [deleted file]
server/sonar-web/src/main/js/apps/quality-gates/components/Condition.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/ConditionModal.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/Conditions.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/DeleteConditionModalForm.tsx [deleted file]
server/sonar-web/src/main/js/components/controls/ConfirmModal.tsx
server/sonar-web/src/main/js/components/controls/SimpleModal.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
deleted file mode 100644 (file)
index 04e4133..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * 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, QualityGate, Condition } from '../../../app/types';
-
-interface Props {
-  metrics: Metric[];
-  organization?: string;
-  onAddCondition: (condition: Condition) => void;
-  qualityGate: QualityGate;
-}
-
-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}
-            onAddCondition={this.props.onAddCondition}
-            onClose={this.handleModalClose}
-            organization={this.props.organization}
-            qualityGate={this.props.qualityGate}
-          />
-        )}
-      </>
-    );
-  }
-}
index fd05fb8232430f06eb8ec2bcb9c14f5e97b1bb11..587ce6af15ff829688e5847381dd65784721eb88 100644 (file)
@@ -21,11 +21,12 @@ import * as React from 'react';
 import ConditionOperator from './ConditionOperator';
 import Period from './Period';
 import ConditionModal from './ConditionModal';
-import DeleteConditionModalForm from './DeleteConditionModalForm';
 import { Condition as ICondition, Metric, QualityGate } from '../../../app/types';
 import ActionsDropdown, { ActionsDropdownItem } from '../../../components/controls/ActionsDropdown';
-import { translate, getLocalizedMetricName } from '../../../helpers/l10n';
+import { translate, getLocalizedMetricName, translateWithParameters } from '../../../helpers/l10n';
 import { formatMeasure } from '../../../helpers/measures';
+import ConfirmModal from '../../../components/controls/ConfirmModal';
+import { deleteCondition } from '../../../api/quality-gates';
 
 interface Props {
   condition: ICondition;
@@ -63,17 +64,30 @@ export default class Condition extends React.PureComponent<Props, State> {
     this.props.onSaveCondition(newCondition, this.props.condition);
   };
 
-  handleCancelClick = () => {
-    this.props.onRemoveCondition(this.props.condition);
+  handleOpenUpdate = () => {
+    this.setState({ modal: true });
   };
 
-  handleOpenUpdate = () => this.setState({ modal: true });
+  handleUpdateClose = () => {
+    this.setState({ modal: false });
+  };
 
-  handleUpdateClose = () => this.setState({ modal: false });
+  handleDeleteClick = () => {
+    this.setState({ deleteFormOpen: true });
+  };
 
-  handleDeleteClick = () => this.setState({ deleteFormOpen: true });
+  closeDeleteForm = () => {
+    this.setState({ deleteFormOpen: false });
+  };
 
-  closeDeleteForm = () => this.setState({ deleteFormOpen: false });
+  removeCondition = (condition: ICondition) => {
+    if (condition.id !== undefined) {
+      deleteCondition({ id: condition.id, organization: this.props.organization }).then(
+        () => this.props.onRemoveCondition(condition),
+        () => {}
+      );
+    }
+  };
 
   render() {
     const { condition, canEdit, metric, organization, qualityGate } = this.props;
@@ -123,13 +137,18 @@ export default class Condition extends React.PureComponent<Props, State> {
               />
             )}
             {this.state.deleteFormOpen && (
-              <DeleteConditionModalForm
-                condition={condition}
-                metric={metric}
+              <ConfirmModal
+                confirmButtonText={translate('delete')}
+                confirmData={condition}
+                header={translate('quality_gates.delete_condition')}
+                isDestructive={true}
                 onClose={this.closeDeleteForm}
-                onDelete={this.props.onRemoveCondition}
-                organization={organization}
-              />
+                onConfirm={this.removeCondition}>
+                {translateWithParameters(
+                  'quality_gates.delete_condition.confirm.message',
+                  getLocalizedMetricName(this.props.metric)
+                )}
+              </ConfirmModal>
             )}
           </td>
         )}
index 12a557a41a5ba6199f3e791a631fad3c4a59fe07..7071337a79b7650b60e09677e1945c7f54cad30f 100644 (file)
@@ -22,13 +22,12 @@ import AddConditionSelect from './AddConditionSelect';
 import ConditionOperator from './ConditionOperator';
 import ThresholdInput from './ThresholdInput';
 import Period from './Period';
-import Modal from '../../../components/controls/Modal';
-import { SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
 import { translate, getLocalizedMetricName } from '../../../helpers/l10n';
 import { Metric, QualityGate, Condition } from '../../../app/types';
 import { createCondition, updateCondition } from '../../../api/quality-gates';
 import { isDiffMetric } from '../../../helpers/measures';
 import { parseError } from '../../../helpers/request';
+import ConfirmModal from '../../../components/controls/ConfirmModal';
 
 interface Props {
   condition?: Condition;
@@ -52,6 +51,8 @@ interface State {
 }
 
 export default class ConditionModal extends React.PureComponent<Props, State> {
+  mounted = false;
+
   constructor(props: Props) {
     super(props);
     this.state = {
@@ -64,13 +65,25 @@ export default class ConditionModal extends React.PureComponent<Props, State> {
     };
   }
 
+  componentDidMount() {
+    this.mounted = true;
+  }
+
+  componentWillUnmount() {
+    this.mounted = false;
+  }
+
   handleError = (error: any) => {
-    parseError(error).then(
-      message => {
-        this.setState({ errorMessage: message });
-      },
-      () => {}
-    );
+    if (this.mounted) {
+      parseError(error).then(
+        message => {
+          this.setState({ errorMessage: message, submitting: false });
+        },
+        () => {
+          this.setState({ submitting: false });
+        }
+      );
+    }
   };
 
   getUpdatedCondition = (metric: Metric) => {
@@ -93,14 +106,11 @@ export default class ConditionModal extends React.PureComponent<Props, State> {
   };
 
   handleConditionResponse = (newCondition: Condition) => {
-    this.setState({ errorMessage: undefined, submitting: false });
     this.props.onAddCondition(newCondition);
     this.props.onClose();
   };
 
-  handleFormSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => {
-    event.preventDefault();
-
+  handleFormSubmit = () => {
     if (this.state.metric) {
       const { condition, qualityGate, organization } = this.props;
       this.setState({ submitting: true });
@@ -130,95 +140,84 @@ export default class ConditionModal extends React.PureComponent<Props, State> {
     this.setState({ metric });
   };
 
-  handlePeriodChange = (period: boolean) => this.setState({ period });
+  handlePeriodChange = (period: boolean) => {
+    this.setState({ period });
+  };
 
-  handleOperatorChange = (op: string) => this.setState({ op });
+  handleOperatorChange = (op: string) => {
+    this.setState({ op });
+  };
 
-  handleWarningChange = (warning: string) => this.setState({ warning });
+  handleWarningChange = (warning: string) => {
+    this.setState({ warning });
+  };
 
-  handleErrorChange = (error: string) => this.setState({ error });
+  handleErrorChange = (error: string) => {
+    this.setState({ error });
+  };
 
   render() {
     const { header, metrics, onClose } = this.props;
-    const { period, op, warning, error, metric, submitting } = this.state;
+    const { period, op, warning, error, metric } = this.state;
     return (
-      <Modal contentLabel={header} onRequestClose={onClose}>
-        <form onSubmit={this.handleFormSubmit}>
-          <div className="modal-head">
-            <h2>{header}</h2>
-          </div>
-
-          <div className="modal-body">
-            {this.state.errorMessage && (
-              <div className="alert alert-danger">{this.state.errorMessage}</div>
-            )}
+      <ConfirmModal
+        confirmButtonText={header}
+        header={header}
+        onClose={onClose}
+        onConfirm={this.handleFormSubmit}>
+        {this.state.errorMessage && (
+          <div className="alert alert-warning modal-alert">{this.state.errorMessage}</div>
+        )}
+        <div className="modal-field">
+          <label htmlFor="create-user-login">{translate('quality_gates.conditions.metric')}</label>
+          {metrics && (
+            <AddConditionSelect metrics={metrics} onAddCondition={this.handleChooseType} />
+          )}
+          {this.props.metric && (
+            <span className="note">{getLocalizedMetricName(this.props.metric)}</span>
+          )}
+        </div>
+        {metric && (
+          <>
+            <div className="modal-field">
+              <label>{translate('quality_gates.conditions.leak')}</label>
+              <Period
+                canEdit={true}
+                metric={metric}
+                onPeriodChange={this.handlePeriodChange}
+                period={period}
+              />
+            </div>
+            <div className="modal-field">
+              <label>{translate('quality_gates.conditions.operator')}</label>
+              <ConditionOperator
+                canEdit={true}
+                metric={metric}
+                onOperatorChange={this.handleOperatorChange}
+                op={op}
+              />
+            </div>
+            <div className="modal-field">
+              <label>{translate('quality_gates.conditions.warning')}</label>
+              <ThresholdInput
+                metric={metric}
+                name="warning"
+                onChange={this.handleWarningChange}
+                value={warning}
+              />
+            </div>
             <div className="modal-field">
-              <label htmlFor="create-user-login">
-                {translate('quality_gates.conditions.metric')}
-              </label>
-              {metrics && (
-                <AddConditionSelect metrics={metrics} onAddCondition={this.handleChooseType} />
-              )}
-              {this.props.metric && (
-                <span className="note">{getLocalizedMetricName(this.props.metric)}</span>
-              )}
+              <label>{translate('quality_gates.conditions.error')}</label>
+              <ThresholdInput
+                metric={metric}
+                name="error"
+                onChange={this.handleErrorChange}
+                value={error}
+              />
             </div>
-            {metric && (
-              <>
-                <div className="modal-field">
-                  <label>{translate('quality_gates.conditions.leak')}</label>
-                  <Period
-                    canEdit={true}
-                    metric={metric}
-                    onPeriodChange={this.handlePeriodChange}
-                    period={period}
-                  />
-                </div>
-                <div className="modal-field">
-                  <label>{translate('quality_gates.conditions.operator')}</label>
-                  <ConditionOperator
-                    canEdit={true}
-                    metric={metric}
-                    onOperatorChange={this.handleOperatorChange}
-                    op={op}
-                  />
-                </div>
-                <div className="modal-field">
-                  <label>{translate('quality_gates.conditions.warning')}</label>
-                  <ThresholdInput
-                    metric={metric}
-                    name="warning"
-                    onChange={this.handleWarningChange}
-                    value={warning}
-                  />
-                </div>
-                <div className="modal-field">
-                  <label>{translate('quality_gates.conditions.error')}</label>
-                  <ThresholdInput
-                    metric={metric}
-                    name="error"
-                    onChange={this.handleErrorChange}
-                    value={error}
-                  />
-                </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>
+          </>
+        )}
+      </ConfirmModal>
     );
   }
 }
index 1b15c245d387846e4a9370b712a9ec2947953198..0eebf3c693dce3db0470fda6df0f9a9edabd7bac 100644 (file)
 import * as React from 'react';
 import { differenceWith, map, sortBy, uniqBy } from 'lodash';
 import Condition from './Condition';
-import AddConditionButton from './AddConditionButton';
+import ConditionModal from './ConditionModal';
 import DocTooltip from '../../../components/docs/DocTooltip';
 import { translate, getLocalizedMetricName } from '../../../helpers/l10n';
 import { Condition as ICondition, Metric, QualityGate } from '../../../app/types';
+import ModalButton from '../../../components/controls/ModalButton';
+import { Button } from '../../../components/ui/buttons';
 
 interface Props {
   canEdit: boolean;
@@ -36,19 +38,7 @@ interface Props {
   qualityGate: QualityGate;
 }
 
-interface State {
-  error?: string;
-}
-
-export default class Conditions extends React.PureComponent<Props, State> {
-  state: State = {};
-
-  componentWillUpdate(nextProps: Props) {
-    if (nextProps.qualityGate !== this.props.qualityGate) {
-      this.setState({ error: undefined });
-    }
-  }
-
+export default class Conditions extends React.PureComponent<Props> {
   getConditionKey = (condition: ICondition, index: number) => {
     return condition.id ? condition.id : `new-${index}`;
   };
@@ -91,12 +81,21 @@ export default class Conditions extends React.PureComponent<Props, State> {
       <div className="quality-gate-section" id="quality-gate-conditions">
         {canEdit && (
           <div className="pull-right">
-            <AddConditionButton
-              metrics={availableMetrics}
-              onAddCondition={this.props.onAddCondition}
-              organization={organization}
-              qualityGate={qualityGate}
-            />
+            <ModalButton
+              modal={({ onClose }) => (
+                <ConditionModal
+                  header={translate('quality_gates.add_condition')}
+                  metrics={availableMetrics}
+                  onAddCondition={this.props.onAddCondition}
+                  onClose={onClose}
+                  organization={this.props.organization}
+                  qualityGate={this.props.qualityGate}
+                />
+              )}>
+              {({ onClick }) => (
+                <Button onClick={onClick}>{translate('quality_gates.add_condition')}</Button>
+              )}
+            </ModalButton>
           </div>
         )}
         <header className="display-flex-center spacer-bottom">
@@ -106,8 +105,6 @@ export default class Conditions extends React.PureComponent<Props, State> {
 
         <div className="big-spacer-bottom">{translate('quality_gates.introduction')}</div>
 
-        {this.state.error && <div className="alert alert-danger">{this.state.error}</div>}
-
         {uniqDuplicates.length > 0 && (
           <div className="alert alert-warning">
             <p>{translate('quality_gates.duplicated_conditions')}</p>
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/DeleteConditionModalForm.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/DeleteConditionModalForm.tsx
deleted file mode 100644 (file)
index 0477d1d..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * 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 Modal from '../../../components/controls/Modal';
-import { SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
-import { translate, translateWithParameters, getLocalizedMetricName } from '../../../helpers/l10n';
-import { Condition, Metric } from '../../../app/types';
-import { deleteCondition } from '../../../api/quality-gates';
-
-interface Props {
-  onClose: () => void;
-  condition: Condition;
-  metric: Metric;
-  onDelete: (condition: Condition) => void;
-  organization?: string;
-}
-
-interface State {
-  loading: boolean;
-  name: string | null;
-}
-
-export default class DeleteConditionModalForm extends React.PureComponent<Props, State> {
-  mounted = false;
-  state: State = { loading: false, name: null };
-
-  componentDidMount() {
-    this.mounted = true;
-  }
-
-  componentWillUnmount() {
-    this.mounted = false;
-  }
-
-  handleFormSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => {
-    event.preventDefault();
-    this.setState({ loading: true });
-    const { organization, condition } = this.props;
-    if (condition.id !== undefined) {
-      deleteCondition({ id: condition.id, organization }).then(
-        () => this.props.onDelete(condition),
-        () => {
-          if (this.mounted) {
-            this.setState({ loading: false });
-          }
-        }
-      );
-    }
-  };
-
-  render() {
-    const header = translate('quality_gates.delete_condition');
-
-    return (
-      <Modal contentLabel={header} onRequestClose={this.props.onClose}>
-        <form id="delete-condition-form" onSubmit={this.handleFormSubmit}>
-          <div className="modal-head">
-            <h2>{header}</h2>
-          </div>
-          <div className="modal-body">
-            <div className="js-modal-messages" />
-            <p>
-              {translateWithParameters(
-                'quality_gates.delete_condition.confirm.message',
-                getLocalizedMetricName(this.props.metric)
-              )}
-            </p>
-          </div>
-          <div className="modal-foot">
-            {this.state.loading && <i className="spinner spacer-right" />}
-            <SubmitButton
-              className="button-red"
-              disabled={this.state.loading}
-              id="delete-profile-submit">
-              {translate('delete')}
-            </SubmitButton>
-            <ResetButtonLink id="delete-profile-cancel" onClick={this.props.onClose}>
-              {translate('cancel')}
-            </ResetButtonLink>
-          </div>
-        </form>
-      </Modal>
-    );
-  }
-}
index 631d0743d896dfd7c9c653e347274665a8349716..6456e5a790cfd5f5d559afb62013163c1e124ed1 100644 (file)
@@ -23,18 +23,18 @@ import DeferredSpinner from '../common/DeferredSpinner';
 import { translate } from '../../helpers/l10n';
 import { SubmitButton, ResetButtonLink } from '../ui/buttons';
 
-interface Props {
+interface Props<T> {
   children: React.ReactNode;
   confirmButtonText: string;
-  confirmData?: string;
+  confirmData?: T;
   confirmDisable?: boolean;
   header: string;
   isDestructive?: boolean;
   onClose: () => void;
-  onConfirm: (data?: string) => void | Promise<void>;
+  onConfirm: (data?: T) => void | Promise<void>;
 }
 
-export default class ConfirmModal extends React.PureComponent<Props> {
+export default class ConfirmModal<T = string> extends React.PureComponent<Props<T>> {
   mounted = false;
 
   componentDidMount() {
index e85d13031edadda27eda4dc12b5e2a593fa7587b..98a77bce7f93e0ba0ba1eabda8836a9d6c784709 100644 (file)
@@ -38,7 +38,7 @@ interface State {
   submitting: boolean;
 }
 
-export default class SimpleModal extends React.PureComponent<Props, State> {
+export default class SimpleModal extends React.Component<Props, State> {
   mounted = false;
   state: State = { submitting: false };