]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-17815 Disable copy and set as default button if QG is not CAYC compliant
authorRevanshu Paliwal <revanshu.paliwal@sonarsource.com>
Thu, 5 Jan 2023 17:18:06 +0000 (18:18 +0100)
committersonartech <sonartech@sonarsource.com>
Fri, 6 Jan 2023 20:03:15 +0000 (20:03 +0000)
server/sonar-web/src/main/js/apps/quality-gates/components/Conditions.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/DetailsHeader.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/QualityGate-it.tsx
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index 7b119a0ee175bfdeb4819bbf41b9f46182edb458..76360b49de94c9aeefa89ec693f8b6ef26bf3f7f 100644 (file)
@@ -25,7 +25,7 @@ import withAvailableFeatures, {
 import withMetricsContext from '../../../app/components/metrics/withMetricsContext';
 import DocumentationTooltip from '../../../components/common/DocumentationTooltip';
 import { Button } from '../../../components/controls/buttons';
-import ModalButton from '../../../components/controls/ModalButton';
+import ModalButton, { ModalProps } from '../../../components/controls/ModalButton';
 import { Alert } from '../../../components/ui/Alert';
 import { getLocalizedMetricName, translate } from '../../../helpers/l10n';
 import { isDiffMetric } from '../../../helpers/measures';
@@ -57,26 +57,25 @@ const FORBIDDEN_METRICS: string[] = [
 ];
 
 export class Conditions extends React.PureComponent<Props> {
-  renderConditionsTable = (conditions: ConditionType[], scope: 'new' | 'overall') => {
-    const {
-      qualityGate,
-      metrics,
-      canEdit,
-      onRemoveCondition,
-      onSaveCondition,
-      updatedConditionId,
-    } = this.props;
-
+  renderConditionModal = ({ onClose }: ModalProps) => {
+    const { metrics, qualityGate, conditions } = this.props;
+    const availableMetrics = differenceWith(
+      map(metrics, (metric) => metric).filter(
+        (metric) =>
+          !metric.hidden &&
+          !FORBIDDEN_METRIC_TYPES.includes(metric.type) &&
+          !FORBIDDEN_METRICS.includes(metric.key)
+      ),
+      conditions,
+      (metric, condition) => metric.key === condition.metric
+    );
     return (
-      <ConditionsTable
+      <ConditionModal
+        header={translate('quality_gates.add_condition')}
+        metrics={availableMetrics}
+        onAddCondition={this.props.onAddCondition}
+        onClose={onClose}
         qualityGate={qualityGate}
-        metrics={metrics}
-        canEdit={canEdit}
-        onRemoveCondition={onRemoveCondition}
-        onSaveCondition={onSaveCondition}
-        updatedConditionId={updatedConditionId}
-        conditions={getOthersConditions(conditions)}
-        scope={scope}
       />
     );
   };
@@ -122,32 +121,11 @@ export class Conditions extends React.PureComponent<Props> {
       metric: metrics[condition.metric],
     }));
 
-    const availableMetrics = differenceWith(
-      map(metrics, (metric) => metric).filter(
-        (metric) =>
-          !metric.hidden &&
-          !FORBIDDEN_METRIC_TYPES.includes(metric.type) &&
-          !FORBIDDEN_METRICS.includes(metric.key)
-      ),
-      conditions,
-      (metric, condition) => metric.key === condition.metric
-    );
-
     return (
       <div className="quality-gate-section">
         {canEdit && (
           <div className="pull-right">
-            <ModalButton
-              modal={({ onClose }) => (
-                <ConditionModal
-                  header={translate('quality_gates.add_condition')}
-                  metrics={availableMetrics}
-                  onAddCondition={this.props.onAddCondition}
-                  onClose={onClose}
-                  qualityGate={this.props.qualityGate}
-                />
-              )}
-            >
+            <ModalButton modal={this.renderConditionModal}>
               {({ onClick }) => (
                 <Button data-test="quality-gates__add-condition" onClick={onClick}>
                   {translate('quality_gates.add_condition')}
index d5749a08e40d2c4edbaf26807918ffea177ffc63..e8bc53a60be47338f9b1ba57488f4999c0e69d1a 100644 (file)
@@ -62,8 +62,8 @@ export default class DetailsHeader extends React.PureComponent<Props> {
   render() {
     const { qualityGate } = this.props;
     const actions = qualityGate.actions || ({} as any);
-    const hasNoConditions =
-      qualityGate.conditions === undefined || qualityGate.conditions.length === 0;
+    const { isCaycCompliant } = qualityGate;
+
     return (
       <div className="layout-page-header-panel layout-page-main-header issues-main-header">
         <div className="layout-page-header-panel-inner layout-page-main-header-inner">
@@ -109,23 +109,32 @@ export default class DetailsHeader extends React.PureComponent<Props> {
                   )}
                 >
                   {({ onClick }) => (
-                    <Button className="little-spacer-left" id="quality-gate-copy" onClick={onClick}>
-                      {translate('copy')}
-                    </Button>
+                    <Tooltip
+                      overlay={
+                        !isCaycCompliant ? translate('quality_gates.cannot_copy_no_cayc') : null
+                      }
+                    >
+                      <Button
+                        className="little-spacer-left"
+                        id="quality-gate-copy"
+                        onClick={onClick}
+                        disabled={!isCaycCompliant}
+                      >
+                        {translate('copy')}
+                      </Button>
+                    </Tooltip>
                   )}
                 </ModalButton>
               )}
               {actions.setAsDefault && (
                 <Tooltip
                   overlay={
-                    hasNoConditions
-                      ? translate('quality_gates.cannot_set_default_no_conditions')
-                      : null
+                    !isCaycCompliant ? translate('quality_gates.cannot_set_default_no_cayc') : null
                   }
                 >
                   <Button
                     className="little-spacer-left"
-                    disabled={hasNoConditions}
+                    disabled={!isCaycCompliant}
                     id="quality-gate-toggle-default"
                     onClick={this.handleSetAsDefaultClick}
                   >
index 964dcc5bcd82503da48a6df39ffb3c34176027d2..5937dd9e77066267b3798c3575225a30cd9b4a84 100644 (file)
@@ -102,11 +102,13 @@ it('should be able to create a quality gate then delete it', async () => {
   });
 });
 
-it('should be able to copy a quality gate', async () => {
+it('should be able to copy a quality gate which is CAYC compliant', async () => {
   const user = userEvent.setup();
   handler.setIsAdmin(true);
   renderQualityGateApp();
 
+  const notDefaultQualityGate = await screen.findByText('Sonar way');
+  await user.click(notDefaultQualityGate);
   const copyButton = await screen.findByRole('button', { name: 'copy' });
 
   await user.click(copyButton);
@@ -118,6 +120,19 @@ it('should be able to copy a quality gate', async () => {
   expect(await screen.findByRole('menuitem', { name: /.* bis/ })).toBeInTheDocument();
 });
 
+it('should not be able to copy a quality gate which is not CAYC compliant', async () => {
+  const user = userEvent.setup();
+  handler.setIsAdmin(true);
+  renderQualityGateApp();
+
+  const notDefaultQualityGate = await screen.findByText('SonarSource way - CFamily');
+  await user.click(notDefaultQualityGate);
+
+  const copyButton = await screen.findByRole('button', { name: 'copy' });
+
+  expect(copyButton).toBeDisabled();
+});
+
 it('should be able to rename a quality gate', async () => {
   const user = userEvent.setup();
   handler.setIsAdmin(true);
@@ -134,7 +149,7 @@ it('should be able to rename a quality gate', async () => {
   expect(await screen.findByRole('menuitem', { name: /New Name.*/ })).toBeInTheDocument();
 });
 
-it('should be able to set as default a quality gate', async () => {
+it('should not be able to set as default a quality gate which is not CAYC compliant', async () => {
   const user = userEvent.setup();
   handler.setIsAdmin(true);
   renderQualityGateApp();
@@ -142,8 +157,19 @@ it('should be able to set as default a quality gate', async () => {
   const notDefaultQualityGate = await screen.findByText('SonarSource way - CFamily');
   await user.click(notDefaultQualityGate);
   const setAsDefaultButton = screen.getByRole('button', { name: 'set_as_default' });
+  expect(setAsDefaultButton).toBeDisabled();
+});
+
+it('should be able to set as default a quality gate which is CAYC compliant', async () => {
+  const user = userEvent.setup();
+  handler.setIsAdmin(true);
+  renderQualityGateApp();
+
+  const notDefaultQualityGate = await screen.findByText('Sonar way');
+  await user.click(notDefaultQualityGate);
+  const setAsDefaultButton = screen.getByRole('button', { name: 'set_as_default' });
   await user.click(setAsDefaultButton);
-  expect(screen.getAllByRole('menuitem')[1]).toHaveTextContent('default');
+  expect(screen.getAllByRole('menuitem')[2]).toHaveTextContent('default');
 });
 
 it('should be able to add a condition', async () => {
index 77d56956966175effcea81294f044db600e01cc4..68cfea13680a8d9f68f871610c73e09b272253db 100644 (file)
@@ -1768,7 +1768,8 @@ quality_gates.create=Create Quality Gate
 quality_gates.rename=Rename Quality Gate
 quality_gates.delete=Delete Quality Gate
 quality_gates.copy=Copy Quality Gate
-quality_gates.cannot_set_default_no_conditions=You must configure at least 1 condition before you can make this the default quality gate.
+quality_gates.cannot_set_default_no_cayc=You must make this quality gate Clean as You Code compliant to make this the default quality gate.
+quality_gates.cannot_copy_no_cayc=You must make this quality gate Clean as You Code compliant to copy.
 quality_gates.is_default_no_conditions=This is the default quality gate, but it has no configured conditions. Please configure at least 1 condition for this quality gate.
 quality_gates.conditions=Conditions
 quality_gates.conditions.help=Your project will fail the Quality Gate if it crosses any metric thresholds set for New Code or Overall Code.