]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-23299 Quality Gate page shows conditions from other modes
authorViktor Vorona <viktor.vorona@sonarsource.com>
Mon, 28 Oct 2024 15:31:30 +0000 (16:31 +0100)
committersonartech <sonartech@sonarsource.com>
Tue, 5 Nov 2024 20:03:02 +0000 (20:03 +0000)
14 files changed:
server/sonar-web/__mocks__/react-intl.tsx
server/sonar-web/src/main/js/api/mocks/QualityGatesServiceMock.ts
server/sonar-web/src/main/js/apps/component-measures/__tests__/ComponentMeasures-it.tsx
server/sonar-web/src/main/js/apps/projectLinks/__tests__/ProjectLinksApp-it.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/Condition.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/Conditions.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/ConditionsTable.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/List.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/UpdateConditionsFromOtherModeBanner.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/quality-gates/components/UpdateConditionsFromOtherModeModal.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/QualityGate-it.tsx
server/sonar-web/src/main/js/helpers/mocks/metrics.ts
server/sonar-web/src/main/js/queries/quality-gates.ts
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index f8a2a34cc47ff4889506ffd88d172cced9d64f49..f68d0c36c3f4b64670a14851701b91c7b44a01bc 100644 (file)
@@ -29,7 +29,9 @@ module.exports = {
           <>
             {id}
             {Object.entries(values).map(([key, value]) => (
-              <React.Fragment key={key}>{value}</React.Fragment>
+              <React.Fragment key={key}>
+                {typeof value === 'function' ? value() : value}
+              </React.Fragment>
             ))}
           </>
         );
@@ -38,13 +40,21 @@ module.exports = {
     },
     formatDate: jest.fn().mockReturnValue(''),
   }),
-  FormattedMessage: ({ id, values }: { id: string; values?: { [x: string]: React.ReactNode } }) => {
+  FormattedMessage: ({
+    id,
+    values,
+  }: {
+    id: string;
+    values?: { [x: string]: React.ReactNode | (() => React.ReactNode) };
+  }) => {
     return (
       <>
         {id}
         {values !== undefined &&
           Object.entries(values).map(([key, value]) => (
-            <React.Fragment key={key}>{value}</React.Fragment>
+            <React.Fragment key={key}>
+              {typeof value === 'function' ? value() : value}
+            </React.Fragment>
           ))}
       </>
     );
index 93e97f60996141808e5cf4164c83d3389f6db8d0..d32c988dd194e0b6f451d18e7ad9cfac09f18a39 100644 (file)
@@ -21,6 +21,7 @@
 import { cloneDeep, flatten, omit, remove } from 'lodash';
 import { MetricKey } from '~sonar-aligned/types/metrics';
 import { Project } from '../../apps/quality-gates/components/Projects';
+import { MQR_CONDITIONS_MAP, STANDARD_CONDITIONS_MAP } from '../../apps/quality-gates/utils';
 import {
   mockQualityGate,
   mockQualityGateApplicationStatus,
@@ -119,6 +120,8 @@ export class QualityGatesServiceMock {
             error: '3',
           },
         ],
+        hasStandardConditions: true,
+        hasMQRConditions: false,
         isDefault: true,
         isBuiltIn: false,
         caycStatus: CaycStatus.Compliant,
@@ -140,19 +143,31 @@ export class QualityGatesServiceMock {
             error: '0',
             isCaycCondition: true,
           },
-          { id: 'AXJMbIUHPAOIsUIE3eNs', metric: 'new_security_rating', op: 'GT', error: '1' },
-          { id: 'AXJMbIUHPAOIsUIE3eNy', metric: 'new_security_rating', op: 'GT', error: '0' },
+          {
+            id: 'AXJMbIUHPAOIsUIE3eOl',
+            metric: MetricKey.new_software_quality_security_rating,
+            op: 'GT',
+            error: '1',
+          },
+          {
+            id: 'AXJMbIUHPAOIsUIE3eOd',
+            metric: MetricKey.new_software_quality_security_rating,
+            op: 'GT',
+            error: '0',
+          },
           { id: 'deprecated', metric: 'function_complexity', op: 'LT', error: '1' },
         ],
         isDefault: false,
         isBuiltIn: false,
+        hasStandardConditions: false,
+        hasMQRConditions: true,
         caycStatus: CaycStatus.NonCompliant,
       }),
       mockQualityGate({
         name: 'Sonar way',
         conditions: [
           {
-            id: 'AXJMbIUHPAOIsUIE3eNs',
+            id: 'AXJMbIUHPAOIsUIE3eQQ',
             metric: 'new_violations',
             op: 'GT',
             error: '0',
@@ -182,16 +197,26 @@ export class QualityGatesServiceMock {
         ],
         isDefault: false,
         isBuiltIn: true,
-        caycStatus: CaycStatus.Compliant,
-        hasStandardConditions: true,
+        hasStandardConditions: false,
         hasMQRConditions: false,
+        caycStatus: CaycStatus.Compliant,
       }),
       mockQualityGate({
         name: 'Non Cayc QG',
         conditions: [
-          { id: 'AXJMbIUHPAOIsUIE3eNs', metric: 'new_security_rating', op: 'GT', error: '1' },
-          { id: 'AXJMbIUHPAOIsUIE3eOD', metric: 'new_reliability_rating', op: 'GT', error: '1' },
-          { id: 'AXJMbIUHPAOIsUIE3eOF', metric: 'new_coverage', op: 'LT', error: '80' },
+          {
+            id: 'AXJMbIUHPAOIsUIE3eCC',
+            metric: MetricKey.new_software_quality_security_rating,
+            op: 'LT',
+            error: '80',
+          },
+          {
+            id: 'AXJMbIUHPAOIsUIE3eOD',
+            metric: MetricKey.new_software_quality_reliability_rating,
+            op: 'LT',
+            error: '80',
+          },
+          { id: 'AXJMbIUHPAOIsUIE3eOA', metric: MetricKey.new_coverage, op: 'LT', error: '80' },
         ],
         isDefault: false,
         isBuiltIn: false,
@@ -202,12 +227,24 @@ export class QualityGatesServiceMock {
       mockQualityGate({
         name: 'Non Cayc Compliant QG',
         conditions: [
-          { id: 'AXJMbIUHPAOIsUIE3eNs', metric: 'new_security_rating', op: 'GT', error: '1' },
-          { id: 'AXJMbIUHPAOIsUIE3eOD', metric: 'new_reliability_rating', op: 'GT', error: '1' },
-          { id: 'AXJMbIUHPAOIsUIE3eOF', metric: 'new_coverage', op: 'LT', error: '80' },
+          {
+            id: 'AXJMbIUHPAOIsUIE3eDD',
+            metric: MetricKey.new_software_quality_security_rating,
+            op: 'GT',
+            error: '1',
+          },
+          {
+            id: 'AXJMbIUHPAOIsUIE3eDA',
+            metric: MetricKey.new_software_quality_reliability_rating,
+            op: 'GT',
+            error: '1',
+          },
+          { id: 'AXJMbIUHPAOIsUIE3eDK', metric: MetricKey.new_coverage, op: 'LT', error: '80' },
         ],
         isDefault: false,
         isBuiltIn: false,
+        hasStandardConditions: false,
+        hasMQRConditions: true,
         caycStatus: CaycStatus.Compliant,
       }),
       mockQualityGate({
@@ -239,6 +276,8 @@ export class QualityGatesServiceMock {
         ],
         isDefault: false,
         isBuiltIn: false,
+        hasStandardConditions: true,
+        hasMQRConditions: false,
         caycStatus: CaycStatus.OverCompliant,
       }),
       mockQualityGate({
@@ -246,15 +285,53 @@ export class QualityGatesServiceMock {
         conditions: [],
         isDefault: false,
         isBuiltIn: false,
+        hasStandardConditions: false,
+        hasMQRConditions: false,
         caycStatus: CaycStatus.NonCompliant,
       }),
       mockQualityGate({
         name: 'QG without new code conditions',
         conditions: [
-          { id: 'AXJMbIUHPAOIsUIE3eNs', metric: 'security_rating', op: 'GT', error: '1' },
+          { id: 'AXJMbIUHPAOIsUIE3eAA', metric: 'security_rating', op: 'GT', error: '1' },
         ],
         isDefault: false,
         isBuiltIn: false,
+        hasStandardConditions: true,
+        hasMQRConditions: false,
+        caycStatus: CaycStatus.NonCompliant,
+      }),
+      mockQualityGate({
+        name: 'QG with MQR conditions',
+        conditions: [
+          {
+            id: 'AXJMbIUHPAOIsUIE3eWW',
+            metric: MetricKey.software_quality_security_rating,
+            op: 'GT',
+            error: '1',
+          },
+          {
+            id: 'AXJMbIUHPAOIsUIE3eW1',
+            metric: MetricKey.new_software_quality_blocker_issues,
+            op: 'GT',
+            error: '1',
+          },
+          {
+            id: 'AXJMbIUHPAOIsUIE3eW2',
+            metric: MetricKey.new_software_quality_high_issues,
+            op: 'GT',
+            error: '1',
+          },
+          {
+            id: 'AXJMbIUHPAOIsUIE3eW3',
+            metric: MetricKey.high_impact_accepted_issues,
+            op: 'GT',
+            error: '1',
+          },
+        ],
+        isDefault: false,
+        isBuiltIn: false,
+        hasStandardConditions: false,
+        hasMQRConditions: true,
         caycStatus: CaycStatus.NonCompliant,
       }),
     ];
@@ -469,6 +546,10 @@ export class QualityGatesServiceMock {
 
     conditions.push(newCondition);
     qg.conditions = conditions;
+    qg.hasMQRConditions =
+      qg.hasMQRConditions || MQR_CONDITIONS_MAP[metric as MetricKey] !== undefined;
+    qg.hasStandardConditions =
+      qg.hasStandardConditions || STANDARD_CONDITIONS_MAP[metric as MetricKey] !== undefined;
     return this.reply(newCondition);
   };
 
@@ -483,6 +564,17 @@ export class QualityGatesServiceMock {
     condition.error = error;
     condition.isCaycCondition = isCaycCondition;
 
+    const qg = this.list.find((qg) => qg.conditions?.find((c) => c.id === id));
+
+    if (qg) {
+      qg.hasMQRConditions =
+        qg.conditions?.some((c) => MQR_CONDITIONS_MAP[c.metric as MetricKey] !== undefined) ||
+        false;
+      qg.hasStandardConditions =
+        qg.conditions?.some((c) => STANDARD_CONDITIONS_MAP[c.metric as MetricKey] !== undefined) ||
+        false;
+    }
+
     return this.reply(condition);
   };
 
@@ -490,6 +582,18 @@ export class QualityGatesServiceMock {
     this.list.forEach((q) => {
       remove(q.conditions || [], (c) => c.id === id);
     });
+
+    const qg = this.list.find((qg) => qg.conditions?.find((c) => c.id === id));
+
+    if (qg) {
+      qg.hasMQRConditions =
+        qg.conditions?.some((c) => MQR_CONDITIONS_MAP[c.metric as MetricKey] !== undefined) ||
+        false;
+      qg.hasStandardConditions =
+        qg.conditions?.some((c) => STANDARD_CONDITIONS_MAP[c.metric as MetricKey] !== undefined) ||
+        false;
+    }
+
     return Promise.resolve();
   };
 
index 03805f6a7ea084ccac151cc78e82dd2ba6db8881..6e7255c6f673744f312fdd985066a661b82eeecc 100644 (file)
@@ -94,14 +94,14 @@ describe('rendering', () => {
     await user.click(ui.maintainabilityDomainBtn.get());
     [
       'component_measures.metric.new_maintainability_issues.name 5',
-      'Software Quality Maintainability Remediation Effort on new code work_duration.x_minutes.1',
-      'Software Quality Technical Debt Ratio on New Code 1.0%',
-      'Software Quality Maintainability Rating on New Code metric.has_rating_X.D metric.software_quality_maintainability_rating.tooltip.D.0.0%',
+      'Added Technical Debt work_duration.x_minutes.1',
+      'Technical Debt Ratio on New Code 1.0%',
+      'Maintainability Rating on New Code metric.has_rating_X.D metric.software_quality_maintainability_rating.tooltip.D.0.0%',
       'component_measures.metric.maintainability_issues.name 2',
-      'Software Quality Maintainability Remediation Effort work_duration.x_minutes.1',
-      'Software Quality Technical Debt Ratio 1.0%',
-      'Software Quality Maintainability Rating metric.has_rating_X.D metric.software_quality_maintainability_rating.tooltip.D.0.0%',
-      'Software Quality Effort to Reach Maintainability Rating A work_duration.x_minutes.1',
+      'Technical Debt work_duration.x_minutes.1',
+      'Technical Debt Ratio 1.0%',
+      'Maintainability Rating metric.has_rating_X.D metric.software_quality_maintainability_rating.tooltip.D.0.0%',
+      'Effort to Reach Maintainability Rating A work_duration.x_minutes.1',
     ].forEach((measure) => {
       expect(ui.measureLink(measure).get()).toBeInTheDocument();
     });
@@ -539,7 +539,7 @@ describe('navigation', () => {
     await user.click(
       ui
         .measureLink(
-          'Software Quality Maintainability Rating metric.has_rating_X.D metric.software_quality_maintainability_rating.tooltip.D.0.0%',
+          'Maintainability Rating metric.has_rating_X.D metric.software_quality_maintainability_rating.tooltip.D.0.0%',
         )
         .get(),
     );
index b3b3fbf9c8069de4294de8c003f11a7d5e6f3461..2bd8326b835072d40c2102d9058a575b2a37e1f1 100644 (file)
@@ -41,7 +41,7 @@ it('renders project links app and can do CRUD operations', async () => {
   renderProjectLinksApp();
   await ui.appIsLoaded();
 
-  expect(ui.noResultsTable.get()).toBeInTheDocument();
+  expect(await ui.noResultsTable.find()).toBeInTheDocument();
 
   // Create link
   await ui.createLink(newLinkName1, 'https://link.com');
index 0716b3bbde64ed00d9b88dae7a85378fa6285fa9..1ce1c2a71d645b72276dd5d993c493a7c03a09ef 100644 (file)
@@ -24,22 +24,37 @@ import {
   ButtonSize,
   ButtonVariety,
   IconDelete,
+  IconRefresh,
   ModalAlert,
 } from '@sonarsource/echoes-react';
-import { ActionCell, ContentCell, NumericalCell, TableRow, TextError } from '~design-system';
+import { useIntl } from 'react-intl';
+import {
+  ActionCell,
+  ContentCell,
+  NumericalCell,
+  Pill,
+  PillHighlight,
+  PillVariant,
+  TableRow,
+  TextError,
+} from '~design-system';
 import { useMetrics } from '../../../app/components/metrics/withMetricsContext';
 import { getLocalizedMetricName, translate, translateWithParameters } from '../../../helpers/l10n';
 import { getOperatorLabel } from '../../../helpers/qualityGates';
 import { useDeleteConditionMutation } from '../../../queries/quality-gates';
+import { useStandardExperienceMode } from '../../../queries/settings';
 import { MetricKey } from '../../../sonar-aligned/types/metrics';
 import { CaycStatus, Condition as ConditionType, Metric, QualityGate } from '../../../types/types';
 import {
   getLocalizedMetricNameNoDiffMetric,
   isConditionWithFixedValue,
   isNonEditableMetric,
+  MQR_CONDITIONS_MAP,
+  STANDARD_CONDITIONS_MAP,
 } from '../utils';
 import ConditionValue from './ConditionValue';
 import EditConditionModal from './EditConditionModal';
+import UpdateConditionsFromOtherModeModal from './UpdateConditionsFromOtherModeModal';
 
 export enum ConditionChange {
   Added = 'added',
@@ -66,14 +81,26 @@ export default function ConditionComponent({
 }: Readonly<Props>) {
   const { mutateAsync: deleteCondition } = useDeleteConditionMutation(qualityGate.name);
   const metrics = useMetrics();
+  const intl = useIntl();
+  const { data: isStandard } = useStandardExperienceMode();
   const { op = 'GT' } = condition;
 
   const isCaycCompliantAndOverCompliant = qualityGate.caycStatus !== CaycStatus.NonCompliant;
+  const isMetricFromOtherMode = isStandard
+    ? MQR_CONDITIONS_MAP[condition.metric as MetricKey] !== undefined
+    : STANDARD_CONDITIONS_MAP[condition.metric as MetricKey] !== undefined;
 
   return (
     <TableRow>
       <ContentCell>
         {getLocalizedMetricNameNoDiffMetric(metric, metrics)}
+        {isMetricFromOtherMode && canEdit && (
+          <Pill className="sw-ml-2" variant={PillVariant.Neutral} highlight={PillHighlight.Medium}>
+            {intl.formatMessage({
+              id: `quality_gates.metric.${isStandard ? 'mqr' : 'standard'}_mode_short`,
+            })}
+          </Pill>
+        )}
         {metric.hidden && <TextError className="sw-ml-1" text={translate('deprecated')} />}
       </ContentCell>
 
@@ -90,10 +117,32 @@ export default function ConditionComponent({
       <ActionCell>
         {!isCaycModal && canEdit && (
           <>
+            {isMetricFromOtherMode && (
+              <UpdateConditionsFromOtherModeModal
+                condition={condition}
+                qualityGateName={qualityGate.name}
+              >
+                <ButtonIcon
+                  Icon={IconRefresh}
+                  variety={ButtonVariety.PrimaryGhost}
+                  className="sw-mr-4"
+                  ariaLabel={intl.formatMessage(
+                    { id: 'quality_gates.mqr_mode_update.single_metric.tooltip.message' },
+                    {
+                      metric: getLocalizedMetricNameNoDiffMetric(metric, metrics),
+                      mode: intl.formatMessage({
+                        id: `settings.mode.${isStandard ? 'standard' : 'mqr'}.name`,
+                      }),
+                    },
+                  )}
+                />
+              </UpdateConditionsFromOtherModeModal>
+            )}
             {(!isCaycCompliantAndOverCompliant ||
               !isConditionWithFixedValue(condition) ||
               (isCaycCompliantAndOverCompliant && showEdit)) &&
-              !isNonEditableMetric(condition.metric as MetricKey) && (
+              !isNonEditableMetric(condition.metric as MetricKey) &&
+              !isMetricFromOtherMode && (
                 <EditConditionModal
                   condition={condition}
                   header={translate('quality_gates.update_condition')}
index be3d0fb8f827d82145979c4298d5744105abd70e..1e34ece57f3898d7eaf2818c0a9fffc913520dc0 100644 (file)
@@ -18,7 +18,7 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
-import { Button, Spinner } from '@sonarsource/echoes-react';
+import { Spinner } from '@sonarsource/echoes-react';
 import { uniqBy } from 'lodash';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
@@ -61,7 +61,7 @@ import CaycFixOptimizeBanner from './CaycFixOptimizeBanner';
 import CaycReviewUpdateConditionsModal from './ConditionReviewAndUpdateModal';
 import ConditionsTable from './ConditionsTable';
 import QGRecommendedIcon from './QGRecommendedIcon';
-import UpdateConditionsFromOtherModeModal from './UpdateConditionsFromOtherModeModal';
+import UpdateConditionsFromOtherModeBanner from './UpdateConditionsFromOtherModeBanner';
 
 interface Props {
   isFetching?: boolean;
@@ -126,6 +126,8 @@ export default function Conditions({ qualityGate, isFetching }: Readonly<Props>)
   );
 
   const conditionsToOtherModeMap = isStandardMode ? MQR_CONDITIONS_MAP : STANDARD_CONDITIONS_MAP;
+  const hasConditionsFromOtherMode =
+    qualityGate[isStandardMode ? 'hasMQRConditions' : 'hasStandardConditions'];
 
   return (
     <Spinner isLoading={isLoading}>
@@ -166,33 +168,27 @@ export default function Conditions({ qualityGate, isFetching }: Readonly<Props>)
           </LightLabel>
         </div>
       )}
-      {isCompliantCustomQualityGate && !isOptimizing && <CaycCompliantBanner />}
-      {isCompliantCustomQualityGate && isOptimizing && canEdit && (
+      {(!hasConditionsFromOtherMode || !canEdit) &&
+        isCompliantCustomQualityGate &&
+        !isOptimizing && <CaycCompliantBanner />}
+      {!hasConditionsFromOtherMode && isCompliantCustomQualityGate && isOptimizing && canEdit && (
         <CaycFixOptimizeBanner renderCaycModal={renderCaycModal} isOptimizing />
       )}
-      {caycStatus === CaycStatus.NonCompliant && canEdit && (
+      {!hasConditionsFromOtherMode && caycStatus === CaycStatus.NonCompliant && canEdit && (
         <CaycFixOptimizeBanner renderCaycModal={renderCaycModal} />
       )}
-      <UpdateConditionsFromOtherModeModal
-        qualityGateName={qualityGate.name}
-        newCodeConditions={newCodeConditions.filter(
-          (c) => conditionsToOtherModeMap[c.metric as MetricKey] !== undefined,
-        )}
-        overallCodeConditions={overallCodeConditions.filter(
-          (c) => conditionsToOtherModeMap[c.metric as MetricKey] !== undefined,
-        )}
-      >
-        {/* TODO test example  */}
-        <Button>Review and update metrics</Button>
-      </UpdateConditionsFromOtherModeModal>
-      <UpdateConditionsFromOtherModeModal
-        qualityGateName={qualityGate.name}
-        isSingleMetric
-        condition={newCodeConditions.find((c) => c.metric.includes('rating'))!}
-      >
-        {/* TODO test example  */}
-        <Button>Test single</Button>
-      </UpdateConditionsFromOtherModeModal>
+      {hasConditionsFromOtherMode && canEdit && (
+        <UpdateConditionsFromOtherModeBanner
+          qualityGateName={qualityGate.name}
+          newCodeConditions={newCodeConditions.filter(
+            (c) => conditionsToOtherModeMap[c.metric as MetricKey] !== undefined,
+          )}
+          overallCodeConditions={overallCodeConditions.filter(
+            (c) => conditionsToOtherModeMap[c.metric as MetricKey] !== undefined,
+          )}
+        />
+      )}
+
       <header className="sw-flex sw-items-center sw-mt-9 sw-mb-4 sw-justify-between">
         <div className="sw-flex">
           <HeadingDark className="sw-typo-lg-semibold sw-m-0">
@@ -270,9 +266,16 @@ export default function Conditions({ qualityGate, isFetching }: Readonly<Props>)
 
         {newCodeConditions.length > 0 && (
           <div>
-            <HeadingDark as="h3" className="sw-mb-2">
-              {translate('quality_gates.conditions.new_code', 'long')}
-            </HeadingDark>
+            <div className="sw-flex sw-justify-between">
+              <HeadingDark className="sw-mb-2">
+                {translate('quality_gates.conditions.new_code', 'long')}
+              </HeadingDark>
+              {hasFeature(Feature.BranchSupport) && (
+                <Note className="sw-mb-2 sw-typo-default">
+                  {translate('quality_gates.conditions.new_code', 'description')}
+                </Note>
+              )}
+            </div>
 
             <ConditionsTable
               qualityGate={qualityGate}
@@ -282,20 +285,21 @@ export default function Conditions({ qualityGate, isFetching }: Readonly<Props>)
               showEdit={editing}
               scope="new"
             />
-
-            {hasFeature(Feature.BranchSupport) && (
-              <Note className="sw-mb-2 sw-typo-default">
-                {translate('quality_gates.conditions.new_code', 'description')}
-              </Note>
-            )}
           </div>
         )}
 
         {overallCodeConditions.length > 0 && (
           <div className="sw-mt-5">
-            <HeadingDark as="h3" className="sw-mb-2">
-              {translate('quality_gates.conditions.overall_code', 'long')}
-            </HeadingDark>
+            <div className="sw-flex sw-justify-between">
+              <HeadingDark className="sw-mb-2">
+                {translate('quality_gates.conditions.overall_code', 'long')}
+              </HeadingDark>
+              {hasFeature(Feature.BranchSupport) && (
+                <Note className="sw-mb-2 sw-typo-default">
+                  {translate('quality_gates.conditions.overall_code', 'description')}
+                </Note>
+              )}
+            </div>
 
             <ConditionsTable
               qualityGate={qualityGate}
@@ -304,12 +308,6 @@ export default function Conditions({ qualityGate, isFetching }: Readonly<Props>)
               conditions={overallCodeConditions}
               scope="overall"
             />
-
-            {hasFeature(Feature.BranchSupport) && (
-              <Note className="sw-mb-2 sw-typo-default">
-                {translate('quality_gates.conditions.overall_code', 'description')}
-              </Note>
-            )}
           </div>
         )}
       </div>
index b0d5bb9565e2fc0d686008ccde5abd486e5e6021..72b521d0614822fd1a96cce37f266935b424f937 100644 (file)
@@ -68,7 +68,7 @@ export default function ConditionsTable({
   return (
     <Table
       columnCount={4}
-      columnWidths={['300px', 'auto', 'auto', 'auto']}
+      columnWidths={['auto', '150px', '150px', '200px']}
       className="sw-my-2"
       header={<Header />}
       data-test={`quality-gates__conditions-${scope}`}
index d1b3cff60faca2c45fca42a9876281799c2dca70..e5707e03241d508d4587c8838016d725f4529584 100644 (file)
@@ -57,6 +57,7 @@ export default function List({ qualityGates, currentQualityGate }: Readonly<Prop
           const isBuiltInTitle = isBuiltIn ? ` ${translate('quality_gates.built_in')}` : '';
           const isAICodeAssuranceQualityGate =
             hasFeature(Feature.AiCodeAssurance) && isBuiltIn && name === 'Sonar way';
+
           const shouldShowQualityGateUpdateIcon =
             actions?.manageConditions === true &&
             ((isStandard && hasMQRConditions === true) ||
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/UpdateConditionsFromOtherModeBanner.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/UpdateConditionsFromOtherModeBanner.tsx
new file mode 100644 (file)
index 0000000..48e8eb5
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 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 { Button, ButtonVariety, IconRefresh } from '@sonarsource/echoes-react';
+import { FormattedMessage, useIntl } from 'react-intl';
+import { CardWithPrimaryBackground, SubHeadingHighlight } from '~design-system';
+import DocumentationLink from '../../../components/common/DocumentationLink';
+import { DocLink } from '../../../helpers/doc-links';
+import { useStandardExperienceMode } from '../../../queries/settings';
+import { Condition } from '../../../types/types';
+import UpdateConditionsFromOtherModeModal from './UpdateConditionsFromOtherModeModal';
+
+interface Props {
+  newCodeConditions: Condition[];
+  overallCodeConditions: Condition[];
+  qualityGateName: string;
+}
+
+export default function UpdateConditionsFromOtherModeBanner(props: Readonly<Props>) {
+  const { data: isStandard } = useStandardExperienceMode();
+  const intl = useIntl();
+  return (
+    <CardWithPrimaryBackground className="sw-mt-9 sw-p-8">
+      <SubHeadingHighlight className="sw-mb-2">
+        {intl.formatMessage(
+          { id: 'quality_gates.mode_banner.title' },
+          {
+            mode: intl.formatMessage({
+              id: `settings.mode.${isStandard ? 'standard' : 'mqr'}.name`,
+            }),
+          },
+        )}
+      </SubHeadingHighlight>
+      <div>
+        <FormattedMessage
+          id="quality_gates.mode_banner.description"
+          values={{
+            link: (
+              <DocumentationLink to={isStandard ? DocLink.ModeStandard : DocLink.ModeMQR}>
+                {intl.formatMessage({
+                  id: `settings.mode.${isStandard ? 'standard' : 'mqr'}.name`,
+                })}
+              </DocumentationLink>
+            ),
+            otherMode: intl.formatMessage({
+              id: `settings.mode.${isStandard ? 'mqr' : 'standard'}.name`,
+            }),
+          }}
+        />
+      </div>
+      <UpdateConditionsFromOtherModeModal {...props}>
+        <Button className="sw-mt-4" prefix={<IconRefresh />} variety={ButtonVariety.Primary}>
+          {intl.formatMessage({ id: 'quality_gates.mode_banner.button' })}
+        </Button>
+      </UpdateConditionsFromOtherModeModal>
+    </CardWithPrimaryBackground>
+  );
+}
index 50775c76dda4be5317e06cf28b29903fb8f2968c..5d876ba848a8c64dd11c76c2aa84e53d723ef541 100644 (file)
@@ -50,13 +50,11 @@ import ConditionValue from './ConditionValue';
 type Props = React.PropsWithChildren & { qualityGateName: string } & (
     | {
         condition?: never;
-        isSingleMetric?: false;
         newCodeConditions: Condition[];
         overallCodeConditions: Condition[];
       }
     | {
         condition: Condition;
-        isSingleMetric: true;
         newCodeConditions?: never;
         overallCodeConditions?: never;
       }
@@ -66,7 +64,6 @@ export default function UpdateConditionsFromOtherModeModal({
   newCodeConditions,
   overallCodeConditions,
   qualityGateName,
-  isSingleMetric,
   condition,
   children,
 }: Readonly<Props>) {
@@ -75,6 +72,7 @@ export default function UpdateConditionsFromOtherModeModal({
   const [error, setError] = React.useState(false);
   const intl = useIntl();
   const mapper = isStandard ? MQR_CONDITIONS_MAP : STANDARD_CONDITIONS_MAP;
+  const isSingleMetric = !!condition;
   const { mutate: updateConditions, isPending } = useUpdateOrDeleteConditionsMutation(
     qualityGateName,
     isSingleMetric,
@@ -174,6 +172,7 @@ export default function UpdateConditionsFromOtherModeModal({
                     {intl.formatMessage({ id: 'overview.new_code' })}
                   </Heading>
                   <Table
+                    data-testid="quality-gates__conditions-new"
                     columnCount={3}
                     columnWidths={['35%', '35%', 'auto']}
                     className="sw-my-2"
@@ -191,6 +190,7 @@ export default function UpdateConditionsFromOtherModeModal({
                     {intl.formatMessage({ id: 'overview.overall_code' })}
                   </Heading>
                   <Table
+                    data-testid="quality-gates__conditions-overall"
                     columnCount={3}
                     columnWidths={['35%', '35%', 'auto']}
                     className="sw-my-2"
@@ -225,7 +225,7 @@ function SingleMetric({ condition }: Readonly<{ condition: Condition }>) {
       <div>
         <Text as="div" size={TextSize.Small}>
           {intl.formatMessage({
-            id: `quality_gates.update_conditions.${isStandard ? 'mqr' : 'standard'}_mode_header`,
+            id: `quality_gates.metric.${isStandard ? 'mqr' : 'standard'}_mode_long`,
           })}
         </Text>
         <Text as="div" size={TextSize.Small} isHighlighted>
@@ -238,7 +238,7 @@ function SingleMetric({ condition }: Readonly<{ condition: Condition }>) {
           <>
             <Text as="div" size={TextSize.Small}>
               {intl.formatMessage({
-                id: `quality_gates.update_conditions.${isStandard ? 'standard' : 'mqr'}_mode_header`,
+                id: `quality_gates.metric.${isStandard ? 'standard' : 'mqr'}_mode_long`,
               })}
             </Text>
             <Text as="div" size={TextSize.Small} isHighlighted>
@@ -246,7 +246,7 @@ function SingleMetric({ condition }: Readonly<{ condition: Condition }>) {
             </Text>
           </>
         ) : (
-          <Text size={TextSize.Small}>
+          <Text size={TextSize.Small} colorOverride="echoes-color-text-danger">
             {intl.formatMessage({ id: 'quality_gates.update_conditions.removed' })}
           </Text>
         )}
@@ -264,7 +264,7 @@ function Header() {
       <ContentCell className="sw-justify-between sw-pr-4">
         <Heading as="h4" className="sw-typo-semibold sw-m-0 sw-whitespace-nowrap">
           {intl.formatMessage({
-            id: `quality_gates.update_conditions.${isStandard ? 'mqr' : 'standard'}_mode_header`,
+            id: `quality_gates.metric.${isStandard ? 'mqr' : 'standard'}_mode_long`,
           })}
         </Heading>
         <IconArrowRight />
@@ -272,7 +272,7 @@ function Header() {
       <ContentCell>
         <Heading as="h4" className="sw-typo-semibold sw-m-0 sw-whitespace-nowrap">
           {intl.formatMessage({
-            id: `quality_gates.update_conditions.${isStandard ? 'standard' : 'mqr'}_mode_header`,
+            id: `quality_gates.metric.${isStandard ? 'standard' : 'mqr'}_mode_long`,
           })}
         </Heading>
       </ContentCell>
index 1798c704ddc9fe19081220476c0a81a8c67716a6..c30f631dd71f8ae563b62796da499f9abdb3ecaf 100644 (file)
@@ -20,7 +20,7 @@
 
 import { screen, waitFor, within } from '@testing-library/react';
 import userEvent from '@testing-library/user-event';
-import { byLabelText, byRole, byTestId } from '~sonar-aligned/helpers/testSelector';
+import { byLabelText, byRole, byTestId, byText } from '~sonar-aligned/helpers/testSelector';
 import { QualityGatesServiceMock } from '../../../../api/mocks/QualityGatesServiceMock';
 import SettingsServiceMock from '../../../../api/mocks/SettingsServiceMock';
 import UsersServiceMock from '../../../../api/mocks/UsersServiceMock';
@@ -34,6 +34,26 @@ import { CaycStatus } from '../../../../types/types';
 import { NoticeType } from '../../../../types/users';
 import routes from '../../routes';
 
+const ui = {
+  batchUpdate: byRole('button', { name: 'quality_gates.mode_banner.button' }),
+  singleUpdate: byRole('button', {
+    name: /quality_gates.mqr_mode_update.single_metric.tooltip.message/,
+  }),
+  removeCondition: byRole('button', { name: /quality_gates.condition.delete/ }),
+  listItem: byTestId('js-subnavigation-item'),
+  requiresUpdateIndicator: byTestId('quality-gates-mqr-standard-mode-update-indicator'),
+  qualityGateListItem: (qualityGateName: string) => byRole('link', { name: qualityGateName }),
+  newConditionRow: byTestId('quality-gates__conditions-new').byRole('row'),
+  overallConditionRow: byTestId('quality-gates__conditions-overall').byRole('row'),
+  batchDialog: byRole('dialog', { name: /quality_gates.update_conditions.header/ }),
+  singleDialog: byRole('dialog', { name: /quality_gates.update_conditions.header.single_metric/ }),
+  updateMetricsBtn: byRole('button', { name: 'quality_gates.update_conditions.update_metrics' }),
+  updateSingleBtn: byRole('button', { name: 'update_verb' }),
+  cancelBtn: byRole('button', { name: 'cancel' }),
+  standardBadge: byText('quality_gates.metric.standard_mode_short'),
+  mqrBadge: byText('quality_gates.metric.mqr_mode_short'),
+};
+
 let qualityGateHandler: QualityGatesServiceMock;
 let usersHandler: UsersServiceMock;
 let settingsHandler: SettingsServiceMock;
@@ -82,9 +102,7 @@ it('should show MQR mode update icon if standard mode conditions are present', a
   qualityGateHandler.setIsAdmin(true);
   renderQualityGateApp();
 
-  expect(
-    await screen.findByTestId('quality-gates-mqr-standard-mode-update-indicator'),
-  ).toBeInTheDocument();
+  expect(await ui.requiresUpdateIndicator.findAll()).toHaveLength(3);
 });
 
 it('should show Standard mode update icon if MQR mode conditions are present', async () => {
@@ -92,9 +110,7 @@ it('should show Standard mode update icon if MQR mode conditions are present', a
   qualityGateHandler.setIsAdmin(true);
   renderQualityGateApp();
 
-  expect(
-    await screen.findByTestId('quality-gates-mqr-standard-mode-update-indicator'),
-  ).toBeInTheDocument();
+  expect(await ui.requiresUpdateIndicator.findAll()).toHaveLength(4);
 });
 
 it('should render the built-in quality gate properly', async () => {
@@ -271,8 +287,8 @@ it('should be able to add a condition on overall code', async () => {
   );
 
   // In real app there are no metrics with selectable condition operator
-  // so we manually changed direction for Info Issues to 0 to test this behavior
-  await user.click(await dialog.byRole('option', { name: 'Info Issues' }).find());
+  // so we manually changed direction for Cognitive Complexity to 0 to test this behavior
+  await user.click(await dialog.byRole('option', { name: 'Cognitive Complexity' }).find());
 
   await user.click(await dialog.byLabelText('quality_gates.conditions.operator').find());
 
@@ -284,7 +300,7 @@ it('should be able to add a condition on overall code', async () => {
   const overallConditions = byTestId('quality-gates__conditions-overall');
 
   expect(
-    await overallConditions.byRole('cell', { name: 'Info Issues' }).find(),
+    await overallConditions.byRole('cell', { name: 'Cognitive Complexity' }).find(),
   ).toBeInTheDocument();
   expect(await overallConditions.byRole('cell', { name: '42' }).find()).toBeInTheDocument();
 });
@@ -314,7 +330,7 @@ it('should be able to select a rating', async () => {
   const overallConditions = byTestId('quality-gates__conditions-overall');
 
   expect(
-    await overallConditions.byRole('cell', { name: 'Maintainability Rating' }).find(),
+    await overallConditions.byRole('cell', { name: /Maintainability Rating/ }).find(),
   ).toBeInTheDocument();
   expect(await overallConditions.byRole('cell', { name: 'B' }).find()).toBeInTheDocument();
 });
@@ -913,6 +929,171 @@ describe('The Permissions section', () => {
   });
 });
 
+describe('Mode transition', () => {
+  describe('MQR mode', () => {
+    it('should not see that quality gates require updates if not an admin', async () => {
+      const user = userEvent.setup();
+      renderQualityGateApp();
+
+      expect(await ui.listItem.findAll()).toHaveLength(9);
+      expect(ui.requiresUpdateIndicator.query()).not.toBeInTheDocument();
+      await user.click(ui.qualityGateListItem('SonarSource way default').get());
+      expect(byText('quality_gates.cayc.banner.title').get()).toBeInTheDocument();
+      expect(ui.batchUpdate.query()).not.toBeInTheDocument();
+      expect(ui.singleUpdate.query()).not.toBeInTheDocument();
+      expect(ui.standardBadge.query()).not.toBeInTheDocument();
+    });
+
+    it('should see that quality gates require updates if an admin', async () => {
+      const user = userEvent.setup();
+      qualityGateHandler.setIsAdmin(true);
+      renderQualityGateApp();
+
+      expect(await ui.listItem.findAll()).toHaveLength(9);
+      expect(
+        ui.qualityGateListItem('SonarSource way default').by(ui.requiresUpdateIndicator).get(),
+      ).toBeInTheDocument();
+      await user.click(ui.qualityGateListItem('SonarSource way default').get());
+      expect(byText('quality_gates.cayc.banner.title').query()).not.toBeInTheDocument();
+      expect(ui.batchUpdate.get()).toBeInTheDocument();
+      expect(ui.singleUpdate.getAll()).toHaveLength(5);
+      expect(ui.standardBadge.getAll()).toHaveLength(5);
+    });
+
+    it('should update conditions to MQR mode', async () => {
+      const user = userEvent.setup();
+      qualityGateHandler.setIsAdmin(true);
+      renderQualityGateApp();
+
+      expect(await ui.listItem.findAll()).toHaveLength(9);
+      await user.click(ui.qualityGateListItem('SonarSource way default').get());
+
+      await user.click(ui.batchUpdate.get());
+      expect(ui.batchDialog.get()).toBeInTheDocument();
+      // + 1 for headers
+      expect(ui.batchDialog.by(ui.newConditionRow).getAll()).toHaveLength(4);
+      expect(ui.batchDialog.by(ui.overallConditionRow).getAll()).toHaveLength(3);
+      await user.click(ui.batchDialog.by(ui.cancelBtn).get());
+
+      expect(ui.newConditionRow.getAt(7)).toHaveTextContent(
+        'Reliability Ratingquality_gates.metric.standard_mode_short',
+      );
+      expect(ui.singleUpdate.get(ui.newConditionRow.getAt(7))).toBeInTheDocument();
+      await user.click(ui.singleUpdate.get(ui.newConditionRow.getAt(7)));
+      expect(ui.singleDialog.get()).toBeInTheDocument();
+      expect(ui.singleDialog.get()).toHaveTextContent(
+        'quality_gates.metric.standard_mode_longReliability Ratingquality_gates.metric.mqr_mode_longReliability Rating',
+      );
+      await user.click(ui.updateSingleBtn.get());
+
+      expect(ui.singleUpdate.getAll()).toHaveLength(4);
+      expect(ui.standardBadge.getAll()).toHaveLength(4);
+
+      await user.click(ui.batchUpdate.get());
+      expect(ui.batchDialog.get()).toBeInTheDocument();
+      // + 1 for headers
+      expect(ui.batchDialog.by(ui.newConditionRow).getAll()).toHaveLength(3);
+      expect(ui.batchDialog.by(ui.overallConditionRow).getAll()).toHaveLength(3);
+      expect(ui.batchDialog.by(ui.newConditionRow).getAt(1)).toHaveTextContent(
+        'Maintainability RatingMaintainability Rating',
+      );
+      expect(ui.batchDialog.by(ui.overallConditionRow).getAt(1)).toHaveTextContent(
+        'Reliability RatingReliability Rating',
+      );
+      await user.click(ui.batchDialog.by(ui.updateMetricsBtn).get());
+
+      expect(byText('quality_gates.cayc.banner.title').get()).toBeInTheDocument();
+      expect(ui.batchUpdate.query()).not.toBeInTheDocument();
+      expect(ui.singleUpdate.query()).not.toBeInTheDocument();
+      expect(ui.standardBadge.query()).not.toBeInTheDocument();
+    });
+  });
+
+  describe('Standard mode', () => {
+    beforeEach(() => {
+      settingsHandler.set(SettingsKey.MQRMode, 'false');
+    });
+
+    it('should not see that quality gates require updates if not an admin', async () => {
+      const user = userEvent.setup();
+      renderQualityGateApp();
+
+      expect(await ui.listItem.findAll()).toHaveLength(9);
+      expect(ui.requiresUpdateIndicator.query()).not.toBeInTheDocument();
+      await user.click(ui.qualityGateListItem('QG with MQR conditions').get());
+      expect(ui.batchUpdate.query()).not.toBeInTheDocument();
+      expect(ui.singleUpdate.query()).not.toBeInTheDocument();
+      expect(ui.mqrBadge.query()).not.toBeInTheDocument();
+    });
+
+    it('should see that quality gates require updates if an admin', async () => {
+      const user = userEvent.setup();
+      qualityGateHandler.setIsAdmin(true);
+      renderQualityGateApp();
+
+      expect(await ui.listItem.findAll()).toHaveLength(9);
+      expect(
+        ui.qualityGateListItem('QG with MQR conditions').by(ui.requiresUpdateIndicator).get(),
+      ).toBeInTheDocument();
+      await user.click(ui.qualityGateListItem('QG with MQR conditions').get());
+      expect(ui.batchUpdate.get()).toBeInTheDocument();
+      expect(ui.singleUpdate.getAll()).toHaveLength(4);
+      expect(ui.mqrBadge.getAll()).toHaveLength(4);
+    });
+
+    it('should update conditions to Standard mode', async () => {
+      const user = userEvent.setup();
+      qualityGateHandler.setIsAdmin(true);
+      renderQualityGateApp();
+
+      expect(await ui.listItem.findAll()).toHaveLength(9);
+      await user.click(ui.qualityGateListItem('QG with MQR conditions').get());
+
+      await user.click(ui.batchUpdate.get());
+      expect(ui.batchDialog.get()).toBeInTheDocument();
+      // + 1 for headers
+      expect(ui.batchDialog.by(ui.newConditionRow).getAll()).toHaveLength(3);
+      expect(ui.batchDialog.by(ui.overallConditionRow).getAll()).toHaveLength(3);
+      await user.click(ui.batchDialog.by(ui.cancelBtn).get());
+
+      expect(ui.newConditionRow.getAt(1)).toHaveTextContent(
+        'Blocker Severity Issuesquality_gates.metric.mqr_mode_short',
+      );
+      expect(ui.singleUpdate.get(ui.newConditionRow.getAt(1))).toBeInTheDocument();
+      await user.click(ui.singleUpdate.get(ui.newConditionRow.getAt(1)));
+      expect(ui.singleDialog.get()).toBeInTheDocument();
+      expect(ui.singleDialog.get()).toHaveTextContent(
+        'quality_gates.metric.mqr_mode_longBlocker Severity Issuesquality_gates.metric.standard_mode_longBlocker Issues',
+      );
+      await user.click(ui.updateSingleBtn.get());
+
+      expect(ui.singleUpdate.getAll()).toHaveLength(3);
+      expect(ui.mqrBadge.getAll()).toHaveLength(3);
+
+      await user.click(ui.batchUpdate.get());
+      expect(ui.batchDialog.get()).toBeInTheDocument();
+      // + 1 for headers
+      expect(ui.batchDialog.by(ui.newConditionRow).getAll()).toHaveLength(2);
+      expect(ui.batchDialog.by(ui.overallConditionRow).getAll()).toHaveLength(3);
+      expect(ui.batchDialog.by(ui.newConditionRow).getAt(1)).toHaveTextContent(
+        'High Severity IssuesCritical Issues',
+      );
+      expect(ui.batchDialog.by(ui.overallConditionRow).getAt(1)).toHaveTextContent(
+        'Blocker and High Severity Accepted Issuesquality_gates.update_conditions.removed',
+      );
+      expect(ui.batchDialog.by(ui.overallConditionRow).getAt(2)).toHaveTextContent(
+        'Security RatingSecurity Rating',
+      );
+      await user.click(ui.batchDialog.by(ui.updateMetricsBtn).get());
+
+      expect(byText('quality_gates.cayc_missing.banner.title').get()).toBeInTheDocument();
+      expect(ui.batchUpdate.query()).not.toBeInTheDocument();
+      expect(ui.singleUpdate.query()).not.toBeInTheDocument();
+      expect(ui.mqrBadge.query()).not.toBeInTheDocument();
+    });
+  });
+});
+
 function renderQualityGateApp(context?: RenderContext) {
   return renderAppRoutes('quality_gates', routes, context);
 }
index 58438bbfaad87b1f0e3b0c4f5c3280b63dbf83a8..0701da72488bbef2aa0f06cc24790970030e587d 100644 (file)
@@ -43,6 +43,18 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: true,
     hidden: false,
   },
+  new_software_quality_maintainability_remediation_effort: {
+    id: 'bf182476-9397-4471-812d-7e40568ef1b0',
+    key: 'new_software_quality_maintainability_remediation_effort',
+    type: 'WORK_DUR',
+    name: 'Added Technical Debt',
+    description:
+      'Total effort (in minutes) to fix all the maintainability issues on new code on the component and therefore to comply to all the requirements.',
+    domain: 'Maintainability',
+    direction: -1,
+    qualitative: true,
+    hidden: false,
+  },
   analysis_from_sonarqube_9_4: {
     id: 'AX_iDGfBRf9uEywNDdeh',
     key: 'analysis_from_sonarqube_9_4',
@@ -55,6 +67,17 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: false,
     hidden: true,
   },
+  high_impact_accepted_issues: {
+    id: 'AY0aC41wVDhd53-OniNc',
+    key: 'high_impact_accepted_issues',
+    type: 'INT',
+    name: 'Blocker and High Severity Accepted Issues',
+    description: 'Accepted issues with blocker or high impact',
+    domain: 'Issues',
+    direction: -1,
+    qualitative: false,
+    hidden: false,
+  },
   blocker_violations: {
     id: 'AXJMbIl_PAOIsUIE3gtt',
     key: 'blocker_violations',
@@ -66,6 +89,17 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: true,
     hidden: false,
   },
+  software_quality_blocker_issues: {
+    id: '9a1650ae-056f-4d40-b761-0ae06b9f15b2',
+    key: 'software_quality_blocker_issues',
+    type: 'INT',
+    name: 'Blocker Severity Issues',
+    description: 'Blocker Severity issues',
+    domain: 'Issues',
+    direction: -1,
+    qualitative: true,
+    hidden: false,
+  },
   bugs: {
     id: 'AXJMbIl_PAOIsUIE3gt_',
     key: 'bugs',
@@ -106,7 +140,7 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     name: 'Cognitive Complexity',
     description: 'Cognitive complexity',
     domain: 'Complexity',
-    direction: -1,
+    direction: 0, // manually changed direction to test quality gate condition operator
     qualitative: false,
     hidden: false,
   },
@@ -427,6 +461,17 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: false,
     hidden: false,
   },
+  effort_to_reach_software_quality_maintainability_rating_a: {
+    id: '0f195cdf-5d79-4be0-90e4-c6e0afb58551',
+    key: 'effort_to_reach_software_quality_maintainability_rating_a',
+    type: 'WORK_DUR',
+    name: 'Effort to Reach Maintainability Rating A',
+    description: 'Effort to reach maintainability rating A',
+    domain: 'Maintainability',
+    direction: -1,
+    qualitative: true,
+    hidden: false,
+  },
   effort_to_reach_maintainability_rating_a: {
     id: 'AXJMbIl_PAOIsUIE3guM',
     key: 'effort_to_reach_maintainability_rating_a',
@@ -525,15 +570,15 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: false,
     hidden: false,
   },
-  high_impact_accepted_issues: {
-    id: 'AY0aC41wVDhd53-OniNc',
-    key: 'high_impact_accepted_issues',
+  software_quality_high_issues: {
+    id: '50f6240a-85c5-4aaf-a928-657c7f03b6ef',
+    key: 'software_quality_high_issues',
     type: 'INT',
-    name: 'Blocker and High Severity Accepted Issues',
-    description: 'Accepted issues with blocker or high impact',
+    name: 'High Severity Issues',
+    description: 'High Severity issues',
     domain: 'Issues',
     direction: -1,
-    qualitative: false,
+    qualitative: true,
     hidden: false,
   },
   info_violations: {
@@ -543,7 +588,18 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     name: 'Info Issues',
     description: 'Info issues',
     domain: 'Issues',
-    direction: 0, // manually changed direction to test quality gate condition operator
+    direction: -1,
+    qualitative: true,
+    hidden: false,
+  },
+  software_quality_info_issues: {
+    id: 'cfc48499-476f-43fb-999e-43bb33e7c93a',
+    key: 'software_quality_info_issues',
+    type: 'INT',
+    name: 'Info Severity Issues',
+    description: 'Info Severity issues',
+    domain: 'Issues',
+    direction: -1,
     qualitative: true,
     hidden: false,
   },
@@ -629,16 +685,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: false,
     hidden: true,
   },
-  last_change_on_software_quality_releasability_rating: {
-    id: 'a2aebcc4-366d-49b3-852b-c7b36f43e1c7',
-    key: 'last_change_on_software_quality_releasability_rating',
-    type: 'DATA',
-    name: 'Last Change on Software Quality Releasability Rating',
-    domain: 'Releasability',
-    direction: 0,
-    qualitative: false,
-    hidden: true,
-  },
   last_change_on_software_quality_reliability_rating: {
     id: '42889539-14b7-45a5-a383-8c4d4a5e48a5',
     key: 'last_change_on_software_quality_reliability_rating',
@@ -659,16 +705,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: false,
     hidden: true,
   },
-  last_change_on_software_quality_security_review_rating: {
-    id: '0f4f143d-b76b-40c9-8769-7f959f4a49ea',
-    key: 'last_change_on_software_quality_security_review_rating',
-    type: 'DATA',
-    name: 'Last Change on SoftwareQuality Security Review Rating',
-    domain: 'Security',
-    direction: 0,
-    qualitative: false,
-    hidden: true,
-  },
   line_coverage: {
     id: 'AXJMbIl_PAOIsUIE3gtl',
     key: 'line_coverage',
@@ -757,6 +793,17 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: false,
     hidden: true,
   },
+  software_quality_low_issues: {
+    id: '452a1f9d-c0c6-4001-b5ce-921b748423e2',
+    key: 'software_quality_low_issues',
+    type: 'INT',
+    name: 'Low Severity Issues',
+    description: 'Low Severity issues',
+    domain: 'Issues',
+    direction: -1,
+    qualitative: true,
+    hidden: false,
+  },
   maintainability_issues: {
     id: 'acc8fd75-3acf-499f-809c-f104af89d16d',
     key: 'maintainability_issues',
@@ -768,6 +815,28 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: false,
     hidden: false,
   },
+  software_quality_maintainability_issues: {
+    id: '163c2107-797a-46c8-a1a9-912b00dae7df',
+    key: 'software_quality_maintainability_issues',
+    type: 'INT',
+    name: 'Maintainability Issues',
+    description: 'Maintainability Issues',
+    domain: 'Maintainability',
+    direction: -1,
+    qualitative: false,
+    hidden: false,
+  },
+  software_quality_maintainability_rating: {
+    id: '9fc76baf-f660-4f65-a271-b2ae7f849239',
+    key: 'software_quality_maintainability_rating',
+    type: 'RATING',
+    name: 'Maintainability Rating',
+    description: 'Maintainability rating',
+    domain: 'Maintainability',
+    direction: -1,
+    qualitative: true,
+    hidden: false,
+  },
   sqale_rating: {
     id: 'AXJMbIl_PAOIsUIE3guF',
     key: 'sqale_rating',
@@ -801,6 +870,17 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: true,
     hidden: true,
   },
+  new_software_quality_maintainability_rating: {
+    id: 'c5d12cc4-e712-4701-a395-c9113ce13c3e',
+    key: 'new_software_quality_maintainability_rating',
+    type: 'RATING',
+    name: 'Maintainability Rating on New Code',
+    description: 'Maintainability rating on new code',
+    domain: 'Maintainability',
+    direction: -1,
+    qualitative: true,
+    hidden: false,
+  },
   new_maintainability_rating: {
     id: 'AXJMbIl_PAOIsUIE3guH',
     key: 'new_maintainability_rating',
@@ -823,6 +903,17 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: true,
     hidden: false,
   },
+  software_quality_medium_issues: {
+    id: '5c85ee75-753a-44db-b357-5ea54cd2d88b',
+    key: 'software_quality_medium_issues',
+    type: 'INT',
+    name: 'Medium Severity Issues',
+    description: 'Medium Severity issues',
+    domain: 'Issues',
+    direction: -1,
+    qualitative: true,
+    hidden: false,
+  },
   minor_violations: {
     id: 'AXJMbIl_PAOIsUIE3gtw',
     key: 'minor_violations',
@@ -866,6 +957,17 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: true,
     hidden: false,
   },
+  new_software_quality_blocker_issues: {
+    id: '24492b83-d35f-4cbd-b12f-0b1168cb7c9a',
+    key: 'new_software_quality_blocker_issues',
+    type: 'INT',
+    name: 'New Blocker Severity Issues',
+    description: 'New Blocker Severity issues',
+    domain: 'Issues',
+    direction: -1,
+    qualitative: true,
+    hidden: false,
+  },
   new_bugs: {
     id: 'AXJMbIl_PAOIsUIE3guA',
     key: 'new_bugs',
@@ -899,6 +1001,17 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: true,
     hidden: false,
   },
+  new_software_quality_high_issues: {
+    id: '1f2e2f4d-4069-4998-885b-287cb87939b6',
+    key: 'new_software_quality_high_issues',
+    type: 'INT',
+    name: 'New High Severity Issues',
+    description: 'New High Severity issues',
+    domain: 'Issues',
+    direction: -1,
+    qualitative: true,
+    hidden: false,
+  },
   new_info_violations: {
     id: 'AXJMbIl_PAOIsUIE3gt3',
     key: 'new_info_violations',
@@ -910,6 +1023,17 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: true,
     hidden: false,
   },
+  new_software_quality_info_issues: {
+    id: '6857dd13-4d48-4a6f-b985-889930ee3508',
+    key: 'new_software_quality_info_issues',
+    type: 'INT',
+    name: 'New Info Severity Issues',
+    description: 'New Info Severity issues',
+    domain: 'Issues',
+    direction: -1,
+    qualitative: true,
+    hidden: false,
+  },
   new_violations: {
     id: 'AXJMbIl_PAOIsUIE3gty',
     key: 'new_violations',
@@ -932,6 +1056,17 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: false,
     hidden: false,
   },
+  new_software_quality_low_issues: {
+    id: '8ecc3d65-72e7-4a36-9d1b-84344ba017f3',
+    key: 'new_software_quality_low_issues',
+    type: 'INT',
+    name: 'New Low Severity Issues',
+    description: 'New Low Severity issues',
+    domain: 'Issues',
+    direction: -1,
+    qualitative: true,
+    hidden: false,
+  },
   new_maintainability_issues: {
     id: '9385d0e6-8991-40b1-b94a-5a260e6146f0',
     key: 'new_maintainability_issues',
@@ -943,6 +1078,17 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: false,
     hidden: false,
   },
+  new_software_quality_maintainability_issues: {
+    id: 'e0216417-de54-4beb-8948-f61bd53987ed',
+    key: 'new_software_quality_maintainability_issues',
+    type: 'INT',
+    name: 'New Maintainability Issues',
+    description: 'New Maintainability Issues',
+    domain: 'Maintainability',
+    direction: -1,
+    qualitative: true,
+    hidden: false,
+  },
   new_major_violations: {
     id: 'AXJMbIl_PAOIsUIE3gt1',
     key: 'new_major_violations',
@@ -954,6 +1100,17 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: true,
     hidden: false,
   },
+  new_software_quality_medium_issues: {
+    id: '9d634fca-caee-4bee-8e23-37744d014194',
+    key: 'new_software_quality_medium_issues',
+    type: 'INT',
+    name: 'New Medium Severity Issues',
+    description: 'New Medium Severity issues',
+    domain: 'Issues',
+    direction: -1,
+    qualitative: true,
+    hidden: false,
+  },
   new_minor_violations: {
     id: 'AXJMbIl_PAOIsUIE3gt2',
     key: 'new_minor_violations',
@@ -976,6 +1133,17 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: false,
     hidden: false,
   },
+  new_software_quality_reliability_issues: {
+    id: 'bfcac26d-2ce7-4fbf-b5c6-ea4f6556825d',
+    key: 'new_software_quality_reliability_issues',
+    type: 'INT',
+    name: 'New Reliability Issues',
+    description: 'New Reliability Issues',
+    domain: 'Reliability',
+    direction: -1,
+    qualitative: true,
+    hidden: false,
+  },
   new_security_hotspots: {
     id: 'AXJMbIl9PAOIsUIE3gsw',
     key: 'new_security_hotspots',
@@ -987,6 +1155,17 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: true,
     hidden: false,
   },
+  new_software_quality_security_issues: {
+    id: 'ecf1983d-ea7e-4df6-b377-d16f4a5a59e6',
+    key: 'new_software_quality_security_issues',
+    type: 'INT',
+    name: 'New Security Issues',
+    description: 'New Security Issues',
+    domain: 'Security',
+    direction: -1,
+    qualitative: true,
+    hidden: false,
+  },
   new_security_issues: {
     id: '6887ef7d-ee21-449c-b1ff-f3f7930ba27f',
     key: 'new_security_issues',
@@ -1161,6 +1340,17 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: false,
     hidden: false,
   },
+  software_quality_reliability_issues: {
+    id: '765f3905-47df-4d9c-b568-9184f341a737',
+    key: 'software_quality_reliability_issues',
+    type: 'INT',
+    name: 'Reliability Issues',
+    description: 'Reliability Issues',
+    domain: 'Reliability',
+    direction: -1,
+    qualitative: false,
+    hidden: false,
+  },
   reliability_rating: {
     id: 'AXJMbIl_PAOIsUIE3guP',
     key: 'reliability_rating',
@@ -1172,6 +1362,17 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: true,
     hidden: false,
   },
+  software_quality_reliability_rating: {
+    id: '6548ffa4-8a5e-4445-a28d-e2fd9fdbba78',
+    key: 'software_quality_reliability_rating',
+    type: 'RATING',
+    name: 'Reliability Rating',
+    description: 'Reliability rating',
+    domain: 'Reliability',
+    direction: -1,
+    qualitative: true,
+    hidden: false,
+  },
   reliability_rating_distribution: {
     id: 'AX3sJDjuJHBehddvNyhO',
     key: 'reliability_rating_distribution',
@@ -1205,6 +1406,17 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: true,
     hidden: false,
   },
+  new_software_quality_reliability_rating: {
+    id: 'ab82dcac-cf81-4780-965d-1384ce9e8983',
+    key: 'new_software_quality_reliability_rating',
+    type: 'RATING',
+    name: 'Reliability Rating on New Code',
+    description: 'Reliability rating on new code',
+    domain: 'Reliability',
+    direction: -1,
+    qualitative: true,
+    hidden: false,
+  },
   reliability_remediation_effort: {
     id: 'AXJMbIl_PAOIsUIE3guN',
     key: 'reliability_remediation_effort',
@@ -1216,6 +1428,28 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: true,
     hidden: false,
   },
+  software_quality_reliability_remediation_effort: {
+    id: 'f2094b93-e08c-4350-ad8f-f265974278a8',
+    key: 'software_quality_reliability_remediation_effort',
+    type: 'WORK_DUR',
+    name: 'Reliability Remediation Effort',
+    description: 'Reliability remediation effort',
+    domain: 'Reliability',
+    direction: -1,
+    qualitative: true,
+    hidden: false,
+  },
+  new_software_quality_reliability_remediation_effort: {
+    id: '45f9a292-5f6e-459e-8d81-134d5aaedef9',
+    key: 'new_software_quality_reliability_remediation_effort',
+    type: 'WORK_DUR',
+    name: 'Reliability Remediation Effort on New Code',
+    description: 'Reliability remediation effort on new code',
+    domain: 'Reliability',
+    direction: -1,
+    qualitative: true,
+    hidden: false,
+  },
   new_reliability_remediation_effort: {
     id: 'AXJMbIl_PAOIsUIE3guO',
     key: 'new_reliability_remediation_effort',
@@ -1284,6 +1518,17 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: false,
     hidden: false,
   },
+  software_quality_security_issues: {
+    id: '7133e418-aadb-4cac-b31f-b13bf036a7ff',
+    key: 'software_quality_security_issues',
+    type: 'INT',
+    name: 'Security Issues',
+    description: 'Security Issues',
+    domain: 'Security',
+    direction: -1,
+    qualitative: false,
+    hidden: false,
+  },
   security_rating: {
     id: 'AXJMbIl_PAOIsUIE3guS',
     key: 'security_rating',
@@ -1295,6 +1540,17 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: true,
     hidden: false,
   },
+  software_quality_security_rating: {
+    id: 'db22dacd-a3fd-41d2-8617-0cb7cfc86429',
+    key: 'software_quality_security_rating',
+    type: 'RATING',
+    name: 'Security Rating',
+    description: 'Security rating',
+    domain: 'Security',
+    direction: -1,
+    qualitative: true,
+    hidden: false,
+  },
   security_rating_distribution: {
     id: 'AX3sJDjuJHBehddvNyhP',
     key: 'security_rating_distribution',
@@ -1317,6 +1573,17 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: true,
     hidden: true,
   },
+  new_software_quality_security_rating: {
+    id: '228b9a04-09a2-418e-9ea4-3584a57a95ba',
+    key: 'new_software_quality_security_rating',
+    type: 'RATING',
+    name: 'Security Rating on New Code',
+    description: 'Security rating on new code',
+    domain: 'Security',
+    direction: -1,
+    qualitative: true,
+    hidden: false,
+  },
   new_security_rating: {
     id: 'AXJMbImPPAOIsUIE3guT',
     key: 'new_security_rating',
@@ -1328,6 +1595,17 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: true,
     hidden: false,
   },
+  software_quality_security_remediation_effort: {
+    id: '43652a84-3ca7-4506-9c09-00ea2b6c6e71',
+    key: 'software_quality_security_remediation_effort',
+    type: 'WORK_DUR',
+    name: 'Security Remediation Effort',
+    description: 'Security remediation effort',
+    domain: 'Security',
+    direction: -1,
+    qualitative: true,
+    hidden: false,
+  },
   security_remediation_effort: {
     id: 'AXJMbIl_PAOIsUIE3guG',
     key: 'security_remediation_effort',
@@ -1350,6 +1628,17 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: true,
     hidden: false,
   },
+  new_software_quality_security_remediation_effort: {
+    id: 'd5d0020a-419c-4387-b00f-523ad8a6a3e4',
+    key: 'new_software_quality_security_remediation_effort',
+    type: 'WORK_DUR',
+    name: 'Security Remediation Effort on New Code',
+    description: 'Security remediation effort on new code',
+    domain: 'Security',
+    direction: -1,
+    qualitative: true,
+    hidden: false,
+  },
   security_review_rating: {
     id: 'AXJMbIl9PAOIsUIE3gsx',
     key: 'security_review_rating',
@@ -1449,28 +1738,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: true,
     hidden: false,
   },
-  effort_to_reach_software_quality_maintainability_rating_a: {
-    id: '0f195cdf-5d79-4be0-90e4-c6e0afb58551',
-    key: 'effort_to_reach_software_quality_maintainability_rating_a',
-    type: 'WORK_DUR',
-    name: 'Software Quality Effort to Reach Maintainability Rating A',
-    description: 'Software quality effort to reach maintainability rating A',
-    domain: 'Maintainability',
-    direction: -1,
-    qualitative: true,
-    hidden: false,
-  },
-  software_quality_maintainability_rating: {
-    id: '9fc76baf-f660-4f65-a271-b2ae7f849239',
-    key: 'software_quality_maintainability_rating',
-    type: 'RATING',
-    name: 'Software Quality Maintainability Rating',
-    description: 'Software quality maintainability rating',
-    domain: 'Maintainability',
-    direction: -1,
-    qualitative: true,
-    hidden: false,
-  },
   software_quality_maintainability_rating_distribution: {
     id: 'b39b797b-216d-4800-810e-2277012ee096',
     key: 'software_quality_maintainability_rating_distribution',
@@ -1503,73 +1770,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: false,
     hidden: true,
   },
-  new_software_quality_maintainability_rating: {
-    id: 'c5d12cc4-e712-4701-a395-c9113ce13c3e',
-    key: 'new_software_quality_maintainability_rating',
-    type: 'RATING',
-    name: 'Software Quality Maintainability Rating on New Code',
-    description: 'Software quality maintainability rating on new code',
-    domain: 'Maintainability',
-    direction: -1,
-    qualitative: true,
-    hidden: false,
-  },
-  software_quality_maintainability_remediation_effort: {
-    id: '24edda40-db1c-4acd-9c9b-66d5bcca8486',
-    key: 'software_quality_maintainability_remediation_effort',
-    type: 'WORK_DUR',
-    name: 'Software Quality Maintainability Remediation Effort',
-    description:
-      'Software quality total effort (in minutes) to fix all the maintainability issues on the component and therefore to comply to all the requirements.',
-    domain: 'Maintainability',
-    direction: -1,
-    qualitative: true,
-    hidden: false,
-  },
-  new_software_quality_maintainability_remediation_effort: {
-    id: 'bf182476-9397-4471-812d-7e40568ef1b0',
-    key: 'new_software_quality_maintainability_remediation_effort',
-    type: 'WORK_DUR',
-    name: 'Software Quality Maintainability Remediation Effort on new code',
-    description:
-      'Software quality total effort (in minutes) to fix all the maintainability issues on new code on the component and therefore to comply to all the requirements.',
-    domain: 'Maintainability',
-    direction: -1,
-    qualitative: true,
-    hidden: false,
-  },
-  software_quality_releasability_rating: {
-    id: '1fb38855-84b8-41b2-88a0-50c3dceda102',
-    key: 'software_quality_releasability_rating',
-    type: 'RATING',
-    name: 'Software Quality Releasability rating',
-    domain: 'Releasability',
-    direction: -1,
-    qualitative: true,
-    hidden: false,
-  },
-  software_quality_releasability_rating_distribution: {
-    id: 'a34a08a2-29b5-4efb-bd2a-eebe3dc10dab',
-    key: 'software_quality_releasability_rating_distribution',
-    type: 'DATA',
-    name: 'Software Quality Releasability Rating Distribution',
-    description: 'Software Quality Releasability rating distribution',
-    domain: 'Releasability',
-    direction: -1,
-    qualitative: true,
-    hidden: true,
-  },
-  software_quality_reliability_rating: {
-    id: '6548ffa4-8a5e-4445-a28d-e2fd9fdbba78',
-    key: 'software_quality_reliability_rating',
-    type: 'RATING',
-    name: 'Software Quality Reliability Rating',
-    description: 'Software quality reliability rating',
-    domain: 'Reliability',
-    direction: -1,
-    qualitative: true,
-    hidden: false,
-  },
   software_quality_reliability_rating_distribution: {
     id: '571de2d7-d1ef-460b-8f99-e29e0aa6218c',
     key: 'software_quality_reliability_rating_distribution',
@@ -1602,50 +1802,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: false,
     hidden: true,
   },
-  new_software_quality_reliability_rating: {
-    id: 'ab82dcac-cf81-4780-965d-1384ce9e8983',
-    key: 'new_software_quality_reliability_rating',
-    type: 'RATING',
-    name: 'Software Quality Reliability Rating on New Code',
-    description: 'Software quality reliability rating on new code',
-    domain: 'Reliability',
-    direction: -1,
-    qualitative: true,
-    hidden: false,
-  },
-  software_quality_reliability_remediation_effort: {
-    id: 'f2094b93-e08c-4350-ad8f-f265974278a8',
-    key: 'software_quality_reliability_remediation_effort',
-    type: 'WORK_DUR',
-    name: 'Software Quality Reliability Remediation Effort',
-    description: 'Software quality reliability remediation effort',
-    domain: 'Reliability',
-    direction: -1,
-    qualitative: true,
-    hidden: false,
-  },
-  new_software_quality_reliability_remediation_effort: {
-    id: '45f9a292-5f6e-459e-8d81-134d5aaedef9',
-    key: 'new_software_quality_reliability_remediation_effort',
-    type: 'WORK_DUR',
-    name: 'Software Quality Reliability Remediation Effort on New Code',
-    description: 'Software quality reliability remediation effort on new code',
-    domain: 'Reliability',
-    direction: -1,
-    qualitative: true,
-    hidden: false,
-  },
-  software_quality_security_rating: {
-    id: 'db22dacd-a3fd-41d2-8617-0cb7cfc86429',
-    key: 'software_quality_security_rating',
-    type: 'RATING',
-    name: 'Software Quality Security Rating',
-    description: 'Software quality security rating',
-    domain: 'Security',
-    direction: -1,
-    qualitative: true,
-    hidden: false,
-  },
   software_quality_security_rating_distribution: {
     id: 'f9a76abe-7663-47b3-a27c-1dea7e6b4861',
     key: 'software_quality_security_rating_distribution',
@@ -1678,89 +1834,37 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     qualitative: false,
     hidden: true,
   },
-  new_software_quality_security_rating: {
-    id: '228b9a04-09a2-418e-9ea4-3584a57a95ba',
-    key: 'new_software_quality_security_rating',
-    type: 'RATING',
-    name: 'Software Quality Security Rating on New Code',
-    description: 'Software quality security rating on new code',
-    domain: 'Security',
+  statements: {
+    id: 'AXJMbImPPAOIsUIE3gum',
+    key: 'statements',
+    type: 'INT',
+    name: 'Statements',
+    description: 'Number of statements',
+    domain: 'Size',
     direction: -1,
-    qualitative: true,
+    qualitative: false,
     hidden: false,
   },
-  software_quality_security_remediation_effort: {
-    id: '43652a84-3ca7-4506-9c09-00ea2b6c6e71',
-    key: 'software_quality_security_remediation_effort',
+  software_quality_maintainability_remediation_effort: {
+    id: '24edda40-db1c-4acd-9c9b-66d5bcca8486',
+    key: 'software_quality_maintainability_remediation_effort',
     type: 'WORK_DUR',
-    name: 'Software Quality Security Remediation Effort',
-    description: 'Software quality security remediation effort',
-    domain: 'Security',
+    name: 'Technical Debt',
+    description:
+      'Total effort (in minutes) to fix all the maintainability issues on the component and therefore to comply to all the requirements.',
+    domain: 'Maintainability',
     direction: -1,
     qualitative: true,
     hidden: false,
   },
-  new_software_quality_security_remediation_effort: {
-    id: 'd5d0020a-419c-4387-b00f-523ad8a6a3e4',
-    key: 'new_software_quality_security_remediation_effort',
+  sqale_index: {
+    id: 'AXJMbIl_PAOIsUIE3guD',
+    key: 'sqale_index',
     type: 'WORK_DUR',
-    name: 'Software Quality Security Remediation Effort on New Code',
-    description: 'Software quality security remediation effort on new code',
-    domain: 'Security',
-    direction: -1,
-    qualitative: true,
-    hidden: false,
-  },
-  software_quality_security_review_rating: {
-    id: '6e09531b-dee8-4c23-9a76-dc335cf79019',
-    key: 'software_quality_security_review_rating',
-    type: 'RATING',
-    name: 'Software Quality Security Review Rating',
-    description: 'Software quality security review rating',
-    domain: 'SecurityReview',
-    direction: -1,
-    qualitative: true,
-    hidden: false,
-  },
-  software_quality_security_review_rating_distribution: {
-    id: '3b9d046c-a319-4cbf-99c4-15c206e71401',
-    key: 'software_quality_security_review_rating_distribution',
-    type: 'DATA',
-    name: 'software Quality Security Review Rating Distribution',
-    description: 'Software Quality Security review rating distribution',
-    domain: 'Security',
-    direction: -1,
-    qualitative: true,
-    hidden: true,
-  },
-  new_software_quality_security_review_rating_distribution: {
-    id: 'b6565b9b-3676-405f-8149-a37cb0bd78b9',
-    key: 'new_software_quality_security_review_rating_distribution',
-    type: 'DATA',
-    name: 'Software Quality Security Review Rating Distribution on New Code',
-    description: 'Software Quality Security review rating distribution on new code',
-    domain: 'Security',
-    direction: -1,
-    qualitative: true,
-    hidden: true,
-  },
-  software_quality_security_review_rating_effort: {
-    id: '8d6d023e-6764-42ee-9fb7-bc1f17bda205',
-    key: 'software_quality_security_review_rating_effort',
-    type: 'DATA',
-    name: 'Software Quality Security Review Rating Effort',
-    domain: 'Security',
-    direction: 0,
-    qualitative: false,
-    hidden: true,
-  },
-  new_software_quality_security_review_rating: {
-    id: '4d4b1d18-da7e-403c-a3f0-99951c58b050',
-    key: 'new_software_quality_security_review_rating',
-    type: 'RATING',
-    name: 'Software Quality Security Review Rating on New Code',
-    description: 'Software quality security review rating on new code',
-    domain: 'SecurityReview',
+    name: 'Technical Debt',
+    description:
+      'Total effort (in minutes) to fix all the issues on the component and therefore to comply to all the requirements.',
+    domain: 'Maintainability',
     direction: -1,
     qualitative: true,
     hidden: false,
@@ -1769,57 +1873,34 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     id: '8a7a5279-9dfe-4fdf-9886-9203ae50be5c',
     key: 'software_quality_maintainability_debt_ratio',
     type: 'PERCENT',
-    name: 'Software Quality Technical Debt Ratio',
+    name: 'Technical Debt Ratio',
     description:
-      'Software quality ratio of the actual technical debt compared to the estimated cost to develop the whole source code from scratch',
+      'Ratio of the actual technical debt compared to the estimated cost to develop the whole source code from scratch',
     domain: 'Maintainability',
     direction: -1,
     qualitative: true,
     hidden: false,
     decimalScale: 1,
   },
-  new_software_quality_maintainability_debt_ratio: {
-    id: '23330467-a21e-4254-a76a-2eb99aab6f0f',
-    key: 'new_software_quality_maintainability_debt_ratio',
+  sqale_debt_ratio: {
+    id: 'AXJMbIl_PAOIsUIE3guK',
+    key: 'sqale_debt_ratio',
     type: 'PERCENT',
-    name: 'Software Quality Technical Debt Ratio on New Code',
-    description: 'Software quality technical debt ratio software quality of new/changed code.',
-    domain: 'Maintainability',
-    direction: -1,
-    qualitative: true,
-    hidden: false,
-    decimalScale: 1,
-  },
-  statements: {
-    id: 'AXJMbImPPAOIsUIE3gum',
-    key: 'statements',
-    type: 'INT',
-    name: 'Statements',
-    description: 'Number of statements',
-    domain: 'Size',
-    direction: -1,
-    qualitative: false,
-    hidden: false,
-  },
-  sqale_index: {
-    id: 'AXJMbIl_PAOIsUIE3guD',
-    key: 'sqale_index',
-    type: 'WORK_DUR',
-    name: 'Technical Debt',
+    name: 'Technical Debt Ratio',
     description:
-      'Total effort (in minutes) to fix all the issues on the component and therefore to comply to all the requirements.',
+      'Ratio of the actual technical debt compared to the estimated cost to develop the whole source code from scratch',
     domain: 'Maintainability',
     direction: -1,
     qualitative: true,
     hidden: false,
+    decimalScale: 1,
   },
-  sqale_debt_ratio: {
-    id: 'AXJMbIl_PAOIsUIE3guK',
-    key: 'sqale_debt_ratio',
+  new_software_quality_maintainability_debt_ratio: {
+    id: '23330467-a21e-4254-a76a-2eb99aab6f0f',
+    key: 'new_software_quality_maintainability_debt_ratio',
     type: 'PERCENT',
-    name: 'Technical Debt Ratio',
-    description:
-      'Ratio of the actual technical debt compared to the estimated cost to develop the whole source code from scratch',
+    name: 'Technical Debt Ratio on New Code',
+    description: 'Technical Debt Ratio on New Code',
     domain: 'Maintainability',
     direction: -1,
     qualitative: true,
index acc880b1e731a8d57a11f0e2e1096c596f2517c0..d8f6a4e88423666cfded4be701d3efdf75d63359 100644 (file)
@@ -239,7 +239,7 @@ export function useUpdateConditionMutation(gateName: string) {
   });
 }
 
-export function useUpdateOrDeleteConditionsMutation(gateName: string, isSingleMetric?: boolean) {
+export function useUpdateOrDeleteConditionsMutation(gateName: string, isSingleMetric = false) {
   const queryClient = useQueryClient();
   const intl = useIntl();
 
index eb50f757551fcaabf7fb93bc2a21eec27ce3f491..ea963b436ed82b229dc93c52b46e7d7901d4ff2a 100644 (file)
@@ -2555,6 +2555,7 @@ quality_gates.ai_generated.tootltip.message=Sonar way ensures clean AI-generated
 quality_gates.ai_generated.description=Sonar way ensures {link}
 quality_gates.ai_generated.description.clean_ai_generated_code=clean AI-generated code
 quality_gates.mqr_mode_update.tooltip.message=Update the metrics of this quality gate
+quality_gates.mqr_mode_update.single_metric.tooltip.message=Update {metric} metric to {mode}
 quality_gates.update_conditions.update_metrics=Update metrics
 quality_gates.update_conditions.header=Update all metrics of “{qualityGate}” gate
 quality_gates.update_conditions.header.single_metric=Update this metric
@@ -2563,10 +2564,16 @@ quality_gates.update_conditions.description.line2=They will be calculated differ
 quality_gates.update_conditions.description.line3=Note that the update to {mode} might cause your quality gate to fail. {link}
 quality_gates.update_conditions.description.link=For more information, refer to the documentation.
 quality_gates.update_conditions.standard_mode_header=Standard Experience Metric
-quality_gates.update_conditions.mqr_mode_header=MQR Mode Metric
+quality_gates.metric.standard_mode_short=Standard Experience
+quality_gates.metric.standard_mode_long=Standard Experience Metric
+quality_gates.metric.mqr_mode_short=MQR Mode
+quality_gates.metric.mqr_mode_long=MQR Mode Metric
 quality_gates.update_conditions.operator_and_value_header=Operator and Value
 quality_gates.update_conditions.removed=Condition will be removed
 quality_gates.update_conditions.error=Failed to update some conditions
+quality_gates.mode_banner.title=This quality gate is using conditions with metrics that belong to the {mode}
+quality_gates.mode_banner.description=This instance is currently in the {link}. We recommend you update the metrics of your quality gate conditions to ensure accurate categorization and ranking of your issues in this mode. Conditions that use {otherMode} metrics can’t be edited until they are updated.
+quality_gates.mode_banner.button=Review and update metrics
 
 
 #------------------------------------------------------------------------------