]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-21259 SONAR-21273 Introduce issue measures card for accepted and fixed issues
author7PH <benjamin.raymond@sonarsource.com>
Tue, 19 Dec 2023 14:57:05 +0000 (15:57 +0100)
committersonartech <sonartech@sonarsource.com>
Wed, 17 Jan 2024 20:02:43 +0000 (20:02 +0000)
26 files changed:
server/sonar-web/design-system/src/components/Text.tsx
server/sonar-web/design-system/src/components/icons/HelperHintIcon.tsx
server/sonar-web/design-system/src/components/icons/Icon.tsx
server/sonar-web/design-system/src/components/icons/SnoozeCircleIcon.tsx [new file with mode: 0644]
server/sonar-web/design-system/src/components/icons/TrendDownCircleIcon.tsx [new file with mode: 0644]
server/sonar-web/design-system/src/components/icons/TrendUpCircleIcon.tsx [new file with mode: 0644]
server/sonar-web/design-system/src/components/icons/index.ts
server/sonar-web/design-system/src/theme/light.ts
server/sonar-web/src/main/js/api/measures.ts
server/sonar-web/src/main/js/apps/component-measures/__tests__/__snapshots__/utils-test.ts.snap
server/sonar-web/src/main/js/apps/component-measures/__tests__/utils-test.ts
server/sonar-web/src/main/js/apps/overview/components/App.tsx
server/sonar-web/src/main/js/apps/overview/pullRequests/IssueMeasuresCard.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/overview/pullRequests/IssueMeasuresCardInner.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/overview/pullRequests/MeasuresCardNumber.tsx
server/sonar-web/src/main/js/apps/overview/pullRequests/MeasuresCardPanel.tsx
server/sonar-web/src/main/js/apps/overview/pullRequests/MeasuresCardPercent.tsx
server/sonar-web/src/main/js/apps/overview/pullRequests/PullRequestOverview.tsx
server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/PullRequestOverview-it.tsx
server/sonar-web/src/main/js/apps/overview/utils.ts [deleted file]
server/sonar-web/src/main/js/apps/overview/utils.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/helpers/mocks/metrics.ts
server/sonar-web/src/main/js/helpers/testMocks.ts
server/sonar-web/src/main/js/types/metrics.ts
server/sonar-web/src/main/js/types/types.ts
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index c0e122e83b548e020c25a1164d58650854d4699c..d10fdc61ba1c9963ae8a9b14409c03695ee1efd0 100644 (file)
@@ -67,12 +67,21 @@ export function PageTitle({
   );
 }
 
-export function TextError({ text, className }: { className?: string; text: string }) {
-  return (
-    <StyledTextError className={className} title={text}>
-      {text}
-    </StyledTextError>
-  );
+export function TextError({
+  text,
+  className,
+}: Readonly<{
+  className?: string;
+  text: string | React.ReactNode;
+}>) {
+  if (typeof text === 'string') {
+    return (
+      <StyledTextError className={className} title={text}>
+        {text}
+      </StyledTextError>
+    );
+  }
+  return <StyledTextError className={className}>{text}</StyledTextError>;
 }
 
 export function TextSuccess({ text, className }: Readonly<{ className?: string; text: string }>) {
index 3cbe2bf70d6bf6b62d26aba097416de393420bdd..7da2fc7a2755579c4643d25ee158c892592aa9d5 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import { useTheme } from '@emotion/react';
+import { Fragment } from 'react';
 import { themeColor, themeContrast } from '../../helpers/theme';
 import { CustomIcon, IconProps } from './Icon';
 
-export function HelperHintIcon(iconProps: IconProps) {
+type Props = IconProps & {
+  raised?: boolean;
+};
+
+export function HelperHintIcon({ raised, ...iconProps }: Props) {
   const theme = useTheme();
   return (
     <CustomIcon {...iconProps}>
-      <circle cx="8" cy="8" fill={themeColor('iconHelperHint')({ theme })} r="7" />
-      <path
-        d="M6.82812 10.2301h1.61506v-.1449c.00852-.83094.30682-1.21872.98012-1.62355.7969-.47301 1.3168-1.09943 1.3168-2.10085C10.7401 4.86932 9.53835 4 7.84659 4 6.29972 4 5.03835 4.80966 5 6.5142h1.73864c.02556-.6946.54119-1.06534 1.09943-1.06534.57528 0 1.03977.38353 1.03977.97586 0 .55823-.40483.92897-.92898 1.26136-.71591.4517-1.11647.90767-1.12074 2.39912v.1449Zm.83949 2.7273c.54546 0 1.01847-.456 1.02273-1.0227-.00426-.5583-.47727-1.0142-1.02273-1.0142-.5625 0-1.02698.4559-1.02272 1.0142-.00426.5667.46022 1.0227 1.02272 1.0227Z"
-        fill={themeContrast('iconHelperHint')({ theme })}
-      />
+      {raised ? (
+        // eslint-disable-next-line react/jsx-fragments
+        <Fragment>
+          <circle cx="8" cy="8" fill={themeColor('iconHelperHintRaised')({ theme })} r="7" />
+          <path
+            d="M6.82812 10.2301H8.44318V10.0852C8.4517 9.25426 8.75 8.86648 9.4233 8.46165C10.2202 7.98864 10.7401 7.36222 10.7401 6.3608C10.7401 4.86932 9.53835 4 7.84659 4C6.29972 4 5.03835 4.80966 5 6.5142H6.73864C6.7642 5.8196 7.27983 5.44886 7.83807 5.44886C8.41335 5.44886 8.87784 5.83239 8.87784 6.42472C8.87784 6.98295 8.47301 7.35369 7.94886 7.68608C7.23295 8.13778 6.83239 8.59375 6.82812 10.0852V10.2301ZM7.66761 12.9574C8.21307 12.9574 8.68608 12.5014 8.69034 11.9347C8.68608 11.3764 8.21307 10.9205 7.66761 10.9205C7.10511 10.9205 6.64063 11.3764 6.64489 11.9347C6.64063 12.5014 7.10511 12.9574 7.66761 12.9574Z"
+            fill={themeContrast('iconHelperHintRaised')({ theme })}
+          />
+        </Fragment>
+      ) : (
+        // eslint-disable-next-line react/jsx-fragments
+        <Fragment>
+          <circle cx="8" cy="8" fill={themeColor('iconHelperHint')({ theme })} r="7" />
+          <path
+            d="M6.82812 10.2301h1.61506v-.1449c.00852-.83094.30682-1.21872.98012-1.62355.7969-.47301 1.3168-1.09943 1.3168-2.10085C10.7401 4.86932 9.53835 4 7.84659 4 6.29972 4 5.03835 4.80966 5 6.5142h1.73864c.02556-.6946.54119-1.06534 1.09943-1.06534.57528 0 1.03977.38353 1.03977.97586 0 .55823-.40483.92897-.92898 1.26136-.71591.4517-1.11647.90767-1.12074 2.39912v.1449Zm.83949 2.7273c.54546 0 1.01847-.456 1.02273-1.0227-.00426-.5583-.47727-1.0142-1.02273-1.0142-.5625 0-1.02698.4559-1.02272 1.0142-.00426.5667.46022 1.0227 1.02272 1.0227Z"
+            fill={themeContrast('iconHelperHint')({ theme })}
+          />
+        </Fragment>
+      )}
     </CustomIcon>
   );
 }
index ff2d4379a0f60b46d40dcc09a6d57252dcb5d983..d4c68fd7a6463e73b1a4e1232784275f003b1c44 100644 (file)
@@ -37,6 +37,7 @@ export interface IconProps extends Omit<Props, 'children'> {
   fill?: ThemeColors | CSSColor;
   height?: number;
   transform?: string;
+  viewBox?: string;
   width?: number;
 }
 
diff --git a/server/sonar-web/design-system/src/components/icons/SnoozeCircleIcon.tsx b/server/sonar-web/design-system/src/components/icons/SnoozeCircleIcon.tsx
new file mode 100644 (file)
index 0000000..a43b4af
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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 { useTheme } from '@emotion/react';
+import { themeColor, themeContrast } from '../../helpers';
+import { CustomIcon, IconProps } from './Icon';
+
+export function SnoozeCircleIcon(props: Readonly<{ neutral?: boolean } & IconProps>) {
+  const theme = useTheme();
+
+  const bgColor = themeColor('overviewCardWarningIcon')({ theme });
+  const iconColor = themeContrast('overviewCardWarningIcon')({ theme });
+
+  return (
+    <CustomIcon height="36" viewBox="0 0 36 36" width="36" {...props}>
+      <circle cx="18" cy="18" fill={bgColor} r="18" />
+      <path
+        d="M16.5319 17.2149H18.4624L15.7318 20.2936C15.3281 20.7536 15.6658 21.4613 16.2897 21.4613H19.4681C19.8718 21.4613 20.2021 21.1428 20.2021 20.7536C20.2021 20.3643 19.8718 20.0458 19.4681 20.0458H17.5376L20.2682 16.9672C20.6719 16.5072 20.3342 15.7994 19.7103 15.7994H16.5319C16.1282 15.7994 15.7979 16.1179 15.7979 16.5072C15.7979 16.8964 16.1282 17.2149 16.5319 17.2149ZM24.8265 13.9735C24.5696 14.2707 24.1071 14.3132 23.7915 14.0655L21.538 12.2537C21.2297 11.9989 21.1857 11.553 21.4499 11.2558C21.7069 10.9585 22.1693 10.9161 22.4849 11.1638L24.7384 12.9756C25.0467 13.2304 25.0907 13.6762 24.8265 13.9735ZM11.1735 13.9735C11.4304 14.2778 11.8929 14.3132 12.2012 14.0655L14.4546 12.2537C14.7703 11.9989 14.8143 11.553 14.5501 11.2558C14.2931 10.9514 13.8307 10.9161 13.5224 11.1638L11.2616 12.9756C10.9533 13.2304 10.9093 13.6762 11.1735 13.9735ZM18 13.6762C20.8334 13.6762 23.1382 15.8985 23.1382 18.6304C23.1382 21.3622 20.8334 23.5845 18 23.5845C15.1666 23.5845 12.8618 21.3622 12.8618 18.6304C12.8618 15.8985 15.1666 13.6762 18 13.6762ZM18 12.2608C14.3519 12.2608 11.3937 15.1129 11.3937 18.6304C11.3937 22.1478 14.3519 25 18 25C21.6481 25 24.6063 22.1478 24.6063 18.6304C24.6063 15.1129 21.6481 12.2608 18 12.2608Z"
+        fill={iconColor}
+      />
+    </CustomIcon>
+  );
+}
diff --git a/server/sonar-web/design-system/src/components/icons/TrendDownCircleIcon.tsx b/server/sonar-web/design-system/src/components/icons/TrendDownCircleIcon.tsx
new file mode 100644 (file)
index 0000000..c65c312
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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 { useTheme } from '@emotion/react';
+import { themeColor, themeContrast } from '../../helpers';
+import { CustomIcon, IconProps } from './Icon';
+
+export function TrendDownCircleIcon(props: Readonly<IconProps>) {
+  const theme = useTheme();
+
+  const bgColor = themeColor('overviewCardSuccessIcon')({ theme });
+  const iconColor = themeContrast('overviewCardSuccessIcon')({ theme });
+
+  return (
+    <CustomIcon height="36" viewBox="0 0 36 36" width="36" {...props}>
+      <circle cx="18" cy="16" fill={bgColor} r="16" />
+      <path
+        d="M23.3203 20.3404C23.3658 20.3291 23.4095 20.3116 23.4503 20.2886C23.4845 20.2687 23.5158 20.2441 23.5433 20.2156C23.567 20.1872 23.5886 20.157 23.6078 20.1254C23.6375 20.0862 23.6614 20.0428 23.6785 19.9967L23.6922 19.9051C23.7046 19.8587 23.7097 19.8107 23.7072 19.7627L23.6579 19.6389C23.6794 19.5866 23.6912 19.5308 23.6927 19.4743L22.4586 16.3778C22.3931 16.2136 22.2651 16.0821 22.1026 16.0122C21.9402 15.9424 21.7567 15.9399 21.5924 16.0054C21.4282 16.0709 21.2967 16.1989 21.2268 16.3613C21.157 16.5238 21.1545 16.7073 21.22 16.8715L21.9185 18.6241L18.0143 17.3095L18.5396 13.9999C18.5644 13.8431 18.5326 13.6826 18.4497 13.5473C18.3668 13.4119 18.2383 13.3106 18.0874 13.2615L13.1375 11.6461C13.0541 11.6189 12.9662 11.6084 12.8788 11.6152C12.7914 11.622 12.7062 11.646 12.628 11.6858C12.5499 11.7256 12.4804 11.7805 12.4235 11.8472C12.3666 11.9139 12.3234 11.9912 12.2964 12.0746C12.2485 12.2228 12.254 12.3831 12.3119 12.5277C12.348 12.6188 12.4038 12.7007 12.4751 12.7678C12.5465 12.8348 12.6318 12.8853 12.7249 12.9157L17.1303 14.3534L16.599 17.6297C16.5746 17.7848 16.6057 17.9435 16.6868 18.0779C16.7679 18.2123 16.8939 18.3137 17.0425 18.3643L21.1545 19.7683L19.7302 20.336C19.5659 20.4015 19.4344 20.5295 19.3646 20.6919C19.2947 20.8544 19.2923 21.0379 19.3577 21.2021C19.4232 21.3664 19.5512 21.4979 19.7137 21.5677C19.8761 21.6376 20.0596 21.64 20.2238 21.5746L23.3203 20.3404Z"
+        fill={iconColor}
+      />
+    </CustomIcon>
+  );
+}
diff --git a/server/sonar-web/design-system/src/components/icons/TrendUpCircleIcon.tsx b/server/sonar-web/design-system/src/components/icons/TrendUpCircleIcon.tsx
new file mode 100644 (file)
index 0000000..6113b9c
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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 { useTheme } from '@emotion/react';
+import { themeColor, themeContrast } from '../../helpers';
+import { CustomIcon, IconProps } from './Icon';
+
+export function TrendUpCircleIcon(props: Readonly<IconProps>) {
+  const theme = useTheme();
+
+  const bgColor = themeColor('overviewCardErrorIcon')({ theme });
+  const iconColor = themeContrast('overviewCardErrorIcon')({ theme });
+
+  return (
+    <CustomIcon height="36" viewBox="0 0 36 36" width="36" {...props}>
+      <circle cx="18" cy="18" fill={bgColor} r="18" />
+      <g clipPath="url(#clip0_2971_11471)">
+        <path
+          d="M20.8955 12.253C20.7186 12.1492 20.5107 12.1169 20.3175 12.1633C20.1242 12.2096 19.9615 12.3308 19.8652 12.5001C19.7688 12.6695 19.7467 12.8732 19.8036 13.0663C19.8605 13.2595 19.9919 13.4263 20.1688 13.5301L21.7029 14.4305L16.8273 15.1807C16.6524 15.2084 16.4961 15.2967 16.386 15.43C16.276 15.5633 16.2193 15.7331 16.2258 15.9094L16.4151 19.6577L11.2365 20.409C11.1385 20.4231 11.0453 20.4562 10.9621 20.5065C10.879 20.5568 10.8076 20.6233 10.752 20.7022C10.6963 20.7811 10.6576 20.8708 10.6379 20.9662C10.6183 21.0617 10.6181 21.161 10.6374 21.2584C10.6567 21.3559 10.6952 21.4496 10.7505 21.5343C10.8059 21.619 10.877 21.6929 10.96 21.7518C11.0429 21.8108 11.136 21.8537 11.2339 21.8779C11.3318 21.9022 11.4327 21.9075 11.5306 21.8934L17.3493 21.0493C17.5267 21.0238 17.6858 20.9361 17.798 20.802C17.9101 20.668 17.968 20.4964 17.9612 20.3181L17.8022 16.5791L22.3971 15.8686L21.3833 17.6502C21.287 17.8195 21.2648 18.0232 21.3218 18.2163C21.3787 18.4095 21.5101 18.5763 21.687 18.6802C21.8639 18.784 22.0718 18.8163 22.265 18.7699C22.4583 18.7236 22.6209 18.6024 22.7173 18.4331L24.5341 15.2403C24.5768 15.1605 24.6052 15.0735 24.6182 14.983L24.6157 14.8623C24.6171 14.8187 24.6153 14.7749 24.6102 14.7313C24.5971 14.6769 24.576 14.6244 24.5477 14.5753C24.5303 14.5366 24.51 14.4991 24.487 14.4631C24.4598 14.4263 24.4278 14.3931 24.3918 14.3646C24.3477 14.3042 24.293 14.2519 24.2305 14.2103L20.8955 12.253Z"
+          fill={iconColor}
+        />
+      </g>
+      <defs>
+        <clipPath id="clip0_2971_11471">
+          <rect fill="white" height="18" transform="translate(9 9)" width="18" />
+        </clipPath>
+      </defs>
+    </CustomIcon>
+  );
+}
index 2498237a78de02cdb00d1cd7e615b7d145cad9b7..0efa2dea06c2891bfdcdb94efd24151bd4b149b0 100644 (file)
@@ -70,6 +70,7 @@ export { SeverityCriticalIcon } from './SeverityCriticalIcon';
 export { SeverityInfoIcon } from './SeverityInfoIcon';
 export { SeverityMajorIcon } from './SeverityMajorIcon';
 export { SeverityMinorIcon } from './SeverityMinorIcon';
+export { SnoozeCircleIcon } from './SnoozeCircleIcon';
 export { SoftwareImpactSeverityHighIcon } from './SoftwareImpactSeverityHighIcon';
 export { SoftwareImpactSeverityLowIcon } from './SoftwareImpactSeverityLowIcon';
 export { SoftwareImpactSeverityMediumIcon } from './SoftwareImpactSeverityMediumIcon';
@@ -83,7 +84,9 @@ export { StatusReopenedIcon } from './StatusReopenedIcon';
 export { StatusResolvedIcon } from './StatusResolvedIcon';
 export { TestFileIcon } from './TestFileIcon';
 export { TrashIcon } from './TrashIcon';
+export { TrendDownCircleIcon } from './TrendDownCircleIcon';
 export { TrendDirection, TrendIcon, TrendType } from './TrendIcon';
+export { TrendUpCircleIcon } from './TrendUpCircleIcon';
 export { TriangleDownIcon } from './TriangleDownIcon';
 export { TriangleLeftIcon } from './TriangleLeftIcon';
 export { TriangleRightIcon } from './TriangleRightIcon';
index 604f2bf044bf2a77ced81b02b7590cba4c68eca4..1534f0adb1d958b800f7ec2d13f9a9242aa1f25a 100644 (file)
@@ -390,6 +390,7 @@ export const lightTheme = {
     iconStatusResolved: secondary.dark,
     iconNotificationsOn: COLORS.indigo[300],
     iconHelperHint: COLORS.blueGrey[100],
+    iconHelperHintRaised: COLORS.blueGrey[400],
     iconRuleInheritanceOverride: danger.light,
 
     // numbered list
@@ -516,6 +517,9 @@ export const lightTheme = {
 
     // overview
     iconOverviewIssue: COLORS.blueGrey[400],
+    overviewCardWarningIcon: COLORS.yellow[50],
+    overviewCardErrorIcon: COLORS.red[100],
+    overviewCardSuccessIcon: COLORS.green[200],
 
     // graph - chart
     graphPointCircleColor: COLORS.white,
@@ -710,6 +714,11 @@ export const lightTheme = {
     pillInfoIcon: COLORS.blue[700],
     pillAccent: COLORS.indigo[500],
 
+    // project cards
+    overviewCardWarningIcon: COLORS.yellow[700],
+    overviewCardErrorIcon: COLORS.red[500],
+    overviewCardSuccessIcon: COLORS.green[500],
+
     // breadcrumbs
     breadcrumb: secondary.dark,
 
@@ -731,6 +740,7 @@ export const lightTheme = {
     iconSeverityInfo: COLORS.white,
     iconStatusResolved: COLORS.white,
     iconHelperHint: secondary.darker,
+    iconHelperHintRaised: COLORS.white,
 
     // numbered list
     numberedList: COLORS.indigo[800],
index 58389491d5d8e467c5ba0f8c69f4d5dd72409bd4..8df28f012e0be8e3c6e52c39880849ce75e641b8 100644 (file)
@@ -44,7 +44,7 @@ export async function getMeasuresWithMetrics(
   // TODO: Remove this mock (SONAR-21259)
   const mockedMetrics = metrics.filter(
     (metric) =>
-      metric !== MetricKey.pullrequest_addressed_issues && metric !== MetricKey.new_accepted_issues,
+      metric !== MetricKey.pull_request_fixed_issues && metric !== MetricKey.new_accepted_issues,
   );
   const result = (await getJSON(COMPONENT_URL, {
     additionalFields: 'metrics',
@@ -52,9 +52,9 @@ export async function getMeasuresWithMetrics(
     metricKeys: mockedMetrics.join(','),
     ...branchParameters,
   }).catch(throwGlobalError)) as MeasuresAndMetaWithMetrics;
-  if (metrics.includes(MetricKey.pullrequest_addressed_issues)) {
+  if (metrics.includes(MetricKey.pull_request_fixed_issues)) {
     result.metrics.push({
-      key: MetricKey.pullrequest_addressed_issues,
+      key: MetricKey.pull_request_fixed_issues,
       name: 'Addressed Issues',
       description: 'Addressed Issues',
       domain: 'Reliability',
@@ -65,7 +65,7 @@ export async function getMeasuresWithMetrics(
       bestValue: '0',
     });
     result.component.measures?.push({
-      metric: MetricKey.pullrequest_addressed_issues,
+      metric: MetricKey.pull_request_fixed_issues,
       period: {
         index: 0,
         value: '11',
index 2085725441f53f6549959f36fd96edee68828196..139ac8c11c3efccce5c61b0916044cb0bd3d00b2 100644 (file)
@@ -64,34 +64,30 @@ exports[`sortMeasures should sort based on the config 1`] = `
 [
   {
     "metric": {
-      "id": "3",
       "key": "new_bugs",
-      "name": "new_bugs",
+      "name": "New bugs",
       "type": "INT",
     },
   },
   {
     "metric": {
-      "id": "2",
       "key": "new_reliability_remediation_effort",
-      "name": "bugs",
+      "name": "Bugs",
       "type": "INT",
     },
   },
   "overall_category",
   {
     "metric": {
-      "id": "4",
       "key": "bugs",
-      "name": "bugs",
+      "name": "Bugs",
       "type": "INT",
     },
   },
   {
     "metric": {
-      "id": "1",
       "key": "reliability_remediation_effort",
-      "name": "new_bugs",
+      "name": "New bugs",
       "type": "INT",
     },
   },
index da7d8b130d117905d04c2a3cb50af5c1c6410d74..af7563afcc94ec4e7260f35caddad80f7ef1adc7 100644 (file)
@@ -19,7 +19,7 @@
  */
 import { ComponentQualifier } from '../../../types/component';
 import { MeasurePageView } from '../../../types/measures';
-import { MetricKey } from '../../../types/metrics';
+import { MetricKey, MetricType } from '../../../types/metrics';
 import { ComponentMeasure } from '../../../types/types';
 import * as utils from '../utils';
 
@@ -28,7 +28,7 @@ const MEASURES = [
     metric: {
       id: '1',
       key: MetricKey.lines_to_cover,
-      type: 'INT',
+      type: MetricType.Integer,
       name: 'Lines to Cover',
       domain: 'Coverage',
     },
@@ -40,7 +40,7 @@ const MEASURES = [
     metric: {
       id: '2',
       key: MetricKey.coverage,
-      type: 'PERCENT',
+      type: MetricType.Percent,
       name: 'Coverage',
       domain: 'Coverage',
     },
@@ -52,7 +52,7 @@ const MEASURES = [
     metric: {
       id: '3',
       key: MetricKey.duplicated_lines_density,
-      type: 'PERCENT',
+      type: MetricType.Percent,
       name: 'Duplicated Lines (%)',
       domain: 'Duplications',
     },
@@ -66,13 +66,12 @@ describe('filterMeasures', () => {
   it('should exclude banned measures', () => {
     expect(
       utils.filterMeasures([
-        { metric: { id: '1', key: MetricKey.open_issues, name: 'Bugs', type: 'INT' } },
+        { metric: { key: MetricKey.open_issues, name: 'Bugs', type: MetricType.Integer } },
         {
           metric: {
-            id: '2',
             key: MetricKey.critical_violations,
             name: 'Critical Violations',
-            type: 'INT',
+            type: MetricType.Integer,
           },
         },
       ]),
@@ -86,22 +85,20 @@ describe('sortMeasures', () => {
       utils.sortMeasures('Reliability', [
         {
           metric: {
-            id: '1',
             key: MetricKey.reliability_remediation_effort,
-            name: 'new_bugs',
-            type: 'INT',
+            name: 'New bugs',
+            type: MetricType.Integer,
           },
         },
         {
           metric: {
-            id: '2',
             key: MetricKey.new_reliability_remediation_effort,
-            name: 'bugs',
-            type: 'INT',
+            name: 'Bugs',
+            type: MetricType.Integer,
           },
         },
-        { metric: { id: '3', key: MetricKey.new_bugs, name: 'new_bugs', type: 'INT' } },
-        { metric: { id: '4', key: MetricKey.bugs, name: 'bugs', type: 'INT' } },
+        { metric: { key: MetricKey.new_bugs, name: 'New bugs', type: MetricType.Integer } },
+        { metric: { key: MetricKey.bugs, name: 'Bugs', type: MetricType.Integer } },
         'overall_category',
       ]),
     ).toMatchSnapshot();
@@ -168,17 +165,17 @@ describe('extract measure', () => {
       name: 'TEST',
       measures: [
         {
-          metric: 'alert_status',
+          metric: MetricKey.alert_status,
           value: '3.2',
           period: { index: 1, value: '0.0' },
         },
         {
-          metric: 'releasability_rating',
+          metric: MetricKey.releasability_rating,
           value: '3.2',
           period: { index: 1, value: '0.0' },
         },
         {
-          metric: 'releasability_effort',
+          metric: MetricKey.releasability_effort,
           value: '3.2',
           period: { index: 1, value: '0.0' },
         },
@@ -199,7 +196,7 @@ describe('extract measure', () => {
     const measure = utils.banQualityGateMeasure(componentBuilder(ComponentQualifier.File));
     expect(measure).toHaveLength(2);
     measure.forEach(({ metric }) => {
-      expect(['releasability_rating', 'releasability_effort']).toContain(metric);
+      expect([MetricKey.releasability_rating, MetricKey.releasability_effort]).toContain(metric);
     });
   });
 });
index 182ca35881bf7aeab56329b48542870c54c90199..661321fea7a824913040f8cbf95e62027741ef73 100644 (file)
@@ -55,7 +55,7 @@ export function App(props: AppProps) {
       {isPullRequest(branchLike) ? (
         <main>
           <Suggestions suggestions="pull_requests" />
-          <PullRequestOverview branchLike={branchLike} component={component} />
+          <PullRequestOverview pullRequest={branchLike} component={component} />
         </main>
       ) : (
         <main>
diff --git a/server/sonar-web/src/main/js/apps/overview/pullRequests/IssueMeasuresCard.tsx b/server/sonar-web/src/main/js/apps/overview/pullRequests/IssueMeasuresCard.tsx
new file mode 100644 (file)
index 0000000..9922536
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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 styled from '@emotion/styled';
+import {
+  Card,
+  HelperHintIcon,
+  LightLabel,
+  PopupPlacement,
+  SnoozeCircleIcon,
+  TextError,
+  TextSubdued,
+  themeColor,
+  Tooltip,
+  TrendDownCircleIcon,
+  TrendUpCircleIcon,
+} from 'design-system';
+import * as React from 'react';
+import { useIntl } from 'react-intl';
+import { getLeakValue } from '../../../components/measure/utils';
+import { DEFAULT_ISSUES_QUERY } from '../../../components/shared/utils';
+import { getBranchLikeQuery } from '../../../helpers/branch-like';
+import { findMeasure, formatMeasure } from '../../../helpers/measures';
+import { getComponentIssuesUrl } from '../../../helpers/urls';
+import { PullRequest } from '../../../types/branch-like';
+import { MetricKey, MetricType } from '../../../types/metrics';
+import { QualityGateStatusConditionEnhanced } from '../../../types/quality-gates';
+import { Component, MeasureEnhanced } from '../../../types/types';
+import { getConditionRequiredLabel, Status } from '../utils';
+import { IssueMeasuresCardInner } from './IssueMeasuresCardInner';
+
+interface Props {
+  conditions: QualityGateStatusConditionEnhanced[];
+  measures: MeasureEnhanced[];
+  component: Component;
+  pullRequest: PullRequest;
+}
+
+export default function IssueMeasuresCard(
+  props: React.PropsWithChildren<Props & React.HTMLAttributes<HTMLDivElement>>,
+) {
+  const { measures, conditions, component, pullRequest, ...rest } = props;
+
+  const intl = useIntl();
+
+  const issuesCount = getLeakValue(findMeasure(measures, MetricKey.new_violations));
+  const issuesCondition = conditions.find((c) => c.metric === MetricKey.new_violations);
+  const issuesConditionFailed = issuesCondition?.level === Status.ERROR;
+  const fixedCount = findMeasure(measures, MetricKey.pull_request_fixed_issues)?.value;
+  const acceptedCount = getLeakValue(findMeasure(measures, MetricKey.new_accepted_issues));
+
+  const issuesUrl = getComponentIssuesUrl(component.key, {
+    ...getBranchLikeQuery(pullRequest),
+    ...DEFAULT_ISSUES_QUERY,
+  });
+  const fixedUrl = getComponentIssuesUrl(component.key, {
+    branch: pullRequest.target,
+    fixedInPR: pullRequest.key,
+  });
+  const acceptedUrl = getComponentIssuesUrl(component.key, {
+    ...getBranchLikeQuery(pullRequest),
+    ...DEFAULT_ISSUES_QUERY,
+    issueStatuses: 'ACCEPTED',
+  });
+
+  return (
+    <Card className="sw-p-8 sw-rounded-2 sw-flex sw-text-base sw-gap-4" {...rest}>
+      <IssueMeasuresCardInner
+        header={intl.formatMessage({ id: 'overview.pull_request.new_issues' })}
+        data-test="overview__measures-new-violations"
+        data-guiding-id={issuesConditionFailed ? 'overviewZeroNewIssuesSimplification' : undefined}
+        metric={MetricKey.new_violations}
+        value={formatMeasure(issuesCount, MetricType.ShortInteger)}
+        url={issuesUrl}
+        failed={issuesConditionFailed}
+        icon={issuesConditionFailed && <TrendUpCircleIcon />}
+        footer={
+          issuesCondition &&
+          (issuesConditionFailed ? (
+            <TextError
+              className="sw-font-regular sw-body-xs sw-inline"
+              text={getConditionRequiredLabel(issuesCondition, intl, true)}
+            />
+          ) : (
+            <LightLabel className="sw-body-xs">
+              {getConditionRequiredLabel(issuesCondition, intl)}
+            </LightLabel>
+          ))
+        }
+      />
+      <StyledCardSeparator />
+      <IssueMeasuresCardInner
+        header={intl.formatMessage({ id: 'overview.pull_request.accepted_issues' })}
+        metric={MetricKey.new_accepted_issues}
+        value={formatMeasure(acceptedCount, MetricType.ShortInteger)}
+        url={acceptedUrl}
+        icon={acceptedCount !== '0' && <SnoozeCircleIcon />}
+        footer={
+          <TextSubdued className="sw-body-xs">
+            {intl.formatMessage({ id: 'overview.pull_request.accepted_issues.help' })}
+          </TextSubdued>
+        }
+      />
+      <StyledCardSeparator />
+      <IssueMeasuresCardInner
+        header={
+          <>
+            {intl.formatMessage({ id: 'overview.pull_request.fixed_issues' })}
+            <Tooltip
+              overlay={
+                <div className="sw-flex sw-flex-col sw-gap-4">
+                  <span>
+                    {intl.formatMessage({ id: 'overview.pull_request.fixed_issues.disclaimer' })}
+                  </span>
+                  <span>
+                    {intl.formatMessage({ id: 'overview.pull_request.fixed_issues.disclaimer.2' })}
+                  </span>
+                </div>
+              }
+              placement={PopupPlacement.Top}
+            >
+              <HelperHintIcon raised />
+            </Tooltip>
+          </>
+        }
+        metric={MetricKey.pull_request_fixed_issues}
+        value={formatMeasure(fixedCount, MetricType.ShortInteger)}
+        url={fixedUrl}
+        icon={fixedCount !== '0' && <TrendDownCircleIcon />}
+        footer={
+          <TextSubdued className="sw-body-xs">
+            {intl.formatMessage({ id: 'overview.pull_request.fixed_issues.help' })}
+          </TextSubdued>
+        }
+      />
+    </Card>
+  );
+}
+
+const StyledCardSeparator = styled.div`
+  width: 1px;
+  background-color: ${themeColor('projectCardBorder')};
+`;
diff --git a/server/sonar-web/src/main/js/apps/overview/pullRequests/IssueMeasuresCardInner.tsx b/server/sonar-web/src/main/js/apps/overview/pullRequests/IssueMeasuresCardInner.tsx
new file mode 100644 (file)
index 0000000..ccdf8c9
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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 { Badge, ContentLink } from 'design-system';
+import * as React from 'react';
+import { Path } from 'react-router-dom';
+import { translate, translateWithParameters } from '../../../helpers/l10n';
+import { localizeMetric } from '../../../helpers/measures';
+import { MetricKey } from '../../../types/metrics';
+
+interface IssueMeasuresCardInnerProps extends React.HTMLAttributes<HTMLDivElement> {
+  metric: MetricKey;
+  value?: string;
+  header: React.ReactNode;
+  url: Path;
+  failed?: boolean;
+  icon?: React.ReactNode;
+  footer?: React.ReactNode;
+}
+
+export function IssueMeasuresCardInner(props: Readonly<IssueMeasuresCardInnerProps>) {
+  const { header, metric, icon, value, url, failed, footer, ...rest } = props;
+
+  return (
+    <div className="sw-w-1/3 sw-flex sw-flex-col sw-gap-3" {...rest}>
+      <div className="sw-flex sw-flex-col sw-gap-2 sw-font-semibold">
+        <div className="sw-flex sw-items-center sw-gap-2">
+          {header}
+
+          {failed && (
+            <Badge className="sw-h-fit" variant="deleted">
+              {translate('overview.measures.failed_badge')}
+            </Badge>
+          )}
+        </div>
+        <div className="sw-flex sw-justify-between sw-items-center sw-h-9">
+          <div className="sw-h-fit">
+            <ContentLink
+              aria-label={translateWithParameters(
+                'overview.see_more_details_on_x_of_y',
+                value ?? '0',
+                localizeMetric(metric),
+              )}
+              className="it__overview-measures-value sw-w-fit sw-text-lg"
+              to={url}
+            >
+              {value ?? '0'}
+            </ContentLink>
+          </div>
+
+          {icon}
+        </div>
+      </div>
+      {footer}
+    </div>
+  );
+}
index e53f315fee1d9899c10314c14011a2acb1ef4e45..d451fc0711eed19fd577fdeff5449af20b8f4b9e 100644 (file)
@@ -24,7 +24,7 @@ import { To } from 'react-router-dom';
 import { formatMeasure } from '../../../helpers/measures';
 import { MetricKey, MetricType } from '../../../types/metrics';
 import { QualityGateStatusConditionEnhanced } from '../../../types/quality-gates';
-import { Status } from '../utils';
+import { Status, getConditionRequiredLabel } from '../utils';
 import MeasuresCard from './MeasuresCard';
 
 interface Props {
@@ -33,13 +33,12 @@ interface Props {
   url: To;
   value: string;
   conditionMetric: MetricKey;
-  guidingKeyOnError?: string;
 }
 
 export default function MeasuresCardNumber(
   props: React.PropsWithChildren<Props & React.HTMLAttributes<HTMLDivElement>>,
 ) {
-  const { label, value, conditions, url, conditionMetric, guidingKeyOnError, ...rest } = props;
+  const { label, value, conditions, url, conditionMetric, ...rest } = props;
 
   const intl = useIntl();
 
@@ -47,16 +46,6 @@ export default function MeasuresCardNumber(
 
   const conditionFailed = condition?.level === Status.ERROR;
 
-  const requireLabel =
-    condition &&
-    intl.formatMessage(
-      { id: 'overview.quality_gate.required_x' },
-      {
-        operator: condition.op === 'GT' ? '≤' : '≥',
-        value: formatMeasure(condition.error, MetricType.Integer),
-      },
-    );
-
   return (
     <MeasuresCard
       url={url}
@@ -64,15 +53,17 @@ export default function MeasuresCardNumber(
       metric={conditionMetric}
       label={label}
       failed={conditionFailed}
-      data-guiding-id={conditionFailed ? guidingKeyOnError : undefined}
       {...rest}
     >
       <span className="sw-body-xs sw-mt-3">
-        {requireLabel &&
+        {condition &&
           (conditionFailed ? (
-            <TextError className="sw-font-regular" text={requireLabel} />
+            <TextError
+              className="sw-font-regular sw-inline"
+              text={getConditionRequiredLabel(condition, intl, true)}
+            />
           ) : (
-            <LightLabel>{requireLabel}</LightLabel>
+            <LightLabel>{getConditionRequiredLabel(condition, intl)}</LightLabel>
           ))}
       </span>
     </MeasuresCard>
index f0bdfb46e1aaf60645648f98b841bcf1998f776a..2df727a1abe4d0ad3688f70de6f65871f74da69e 100644 (file)
 import classNames from 'classnames';
 import * as React from 'react';
 import { getLeakValue } from '../../../components/measure/utils';
-import { DEFAULT_ISSUES_QUERY } from '../../../components/shared/utils';
 import { getBranchLikeQuery } from '../../../helpers/branch-like';
 import { findMeasure } from '../../../helpers/measures';
-import {
-  getComponentDrilldownUrl,
-  getComponentIssuesUrl,
-  getComponentSecurityHotspotsUrl,
-} from '../../../helpers/urls';
-import { BranchLike } from '../../../types/branch-like';
+import { getComponentDrilldownUrl, getComponentSecurityHotspotsUrl } from '../../../helpers/urls';
+import { PullRequest } from '../../../types/branch-like';
 import { MetricKey } from '../../../types/metrics';
 import { QualityGateStatusConditionEnhanced } from '../../../types/quality-gates';
 import { Component, MeasureEnhanced } from '../../../types/types';
 import { MeasurementType, getMeasurementMetricKey } from '../utils';
+import IssueMeasuresCard from './IssueMeasuresCard';
 import MeasuresCardNumber from './MeasuresCardNumber';
 import MeasuresCardPercent from './MeasuresCardPercent';
 
 interface Props {
   className?: string;
-  branchLike?: BranchLike;
+  pullRequest: PullRequest;
   component: Component;
   measures: MeasureEnhanced[];
   conditions: QualityGateStatusConditionEnhanced[];
 }
 
 export default function MeasuresCardPanel(props: React.PropsWithChildren<Props>) {
-  const { branchLike, component, measures, conditions, className } = props;
+  const { pullRequest, component, measures, conditions, className } = props;
 
-  const newViolations = getLeakValue(findMeasure(measures, MetricKey.new_violations)) as string;
   const newSecurityHotspots = getLeakValue(
     findMeasure(measures, MetricKey.new_security_hotspots),
   ) as string;
 
   return (
-    <div className={classNames('sw-w-full sw-flex sw-flex-row sw-gap-4 sw-mt-4', className)}>
-      <div className="sw-flex-1 sw-flex sw-flex-col sw-gap-4">
-        <MeasuresCardNumber
-          data-test="overview__measures-new-violations"
-          label={newViolations === '1' ? 'issue' : 'issues'}
-          url={getComponentIssuesUrl(component.key, {
-            ...getBranchLikeQuery(branchLike),
-            ...DEFAULT_ISSUES_QUERY,
-          })}
-          value={newViolations}
-          conditions={conditions}
-          conditionMetric={MetricKey.new_violations}
-          guidingKeyOnError="overviewZeroNewIssuesSimplification"
-        />
+    <>
+      <IssueMeasuresCard
+        conditions={conditions}
+        measures={measures}
+        component={component}
+        pullRequest={pullRequest}
+      />
 
-        <MeasuresCardPercent
-          componentKey={component.key}
-          branchLike={branchLike}
-          measurementType={MeasurementType.Coverage}
-          label="overview.quality_gate.coverage"
-          url={getComponentDrilldownUrl({
-            componentKey: component.key,
-            metric: getMeasurementMetricKey(MeasurementType.Coverage, true),
-            branchLike,
-            listView: true,
-          })}
-          conditions={conditions}
-          conditionMetric={MetricKey.new_coverage}
-          newLinesMetric={MetricKey.new_lines_to_cover}
-          afterMergeMetric={MetricKey.coverage}
-          measures={measures}
-        />
-      </div>
+      <div className={classNames('sw-w-full sw-flex sw-flex-row sw-gap-4 sw-mt-4', className)}>
+        <div className="sw-flex-1 sw-flex sw-flex-col sw-gap-4">
+          <MeasuresCardPercent
+            componentKey={component.key}
+            branchLike={pullRequest}
+            measurementType={MeasurementType.Coverage}
+            label="overview.quality_gate.coverage"
+            url={getComponentDrilldownUrl({
+              componentKey: component.key,
+              metric: getMeasurementMetricKey(MeasurementType.Coverage, true),
+              branchLike: pullRequest,
+              listView: true,
+            })}
+            conditions={conditions}
+            conditionMetric={MetricKey.new_coverage}
+            newLinesMetric={MetricKey.new_lines_to_cover}
+            measures={measures}
+          />
 
-      <div className="sw-flex-1 sw-flex sw-flex-col sw-gap-4">
-        <MeasuresCardNumber
-          label={
-            newSecurityHotspots === '1'
-              ? 'issue.type.SECURITY_HOTSPOT'
-              : 'issue.type.SECURITY_HOTSPOT.plural'
-          }
-          url={getComponentSecurityHotspotsUrl(component.key, {
-            ...getBranchLikeQuery(branchLike),
-          })}
-          value={newSecurityHotspots}
-          conditions={conditions}
-          conditionMetric={MetricKey.new_security_hotspots_reviewed}
-        />
+          <MeasuresCardNumber
+            label={
+              newSecurityHotspots === '1'
+                ? 'issue.type.SECURITY_HOTSPOT'
+                : 'issue.type.SECURITY_HOTSPOT.plural'
+            }
+            url={getComponentSecurityHotspotsUrl(component.key, {
+              ...getBranchLikeQuery(pullRequest),
+            })}
+            value={newSecurityHotspots}
+            conditions={conditions}
+            conditionMetric={MetricKey.new_security_hotspots_reviewed}
+          />
+        </div>
 
-        <MeasuresCardPercent
-          componentKey={component.key}
-          branchLike={branchLike}
-          measurementType={MeasurementType.Duplication}
-          label="overview.quality_gate.duplications"
-          url={getComponentDrilldownUrl({
-            componentKey: component.key,
-            metric: getMeasurementMetricKey(MeasurementType.Duplication, true),
-            branchLike,
-            listView: true,
-          })}
-          conditions={conditions}
-          conditionMetric={MetricKey.new_duplicated_lines_density}
-          newLinesMetric={MetricKey.new_lines}
-          afterMergeMetric={MetricKey.duplicated_lines_density}
-          measures={measures}
-        />
+        <div className="sw-flex-1 sw-flex sw-flex-col sw-gap-4">
+          <MeasuresCardPercent
+            componentKey={component.key}
+            branchLike={pullRequest}
+            measurementType={MeasurementType.Duplication}
+            label="overview.quality_gate.duplications"
+            url={getComponentDrilldownUrl({
+              componentKey: component.key,
+              metric: getMeasurementMetricKey(MeasurementType.Duplication, true),
+              branchLike: pullRequest,
+              listView: true,
+            })}
+            conditions={conditions}
+            conditionMetric={MetricKey.new_duplicated_lines_density}
+            newLinesMetric={MetricKey.new_lines}
+            measures={measures}
+          />
+        </div>
       </div>
-    </div>
+    </>
   );
 }
index a65760c056349d98e73f9603caebbf5ee588507c..ab71e1e579bb7adfee99c5240124de2de47e8500 100644 (file)
@@ -35,7 +35,12 @@ import { BranchLike } from '../../../types/branch-like';
 import { MetricKey, MetricType } from '../../../types/metrics';
 import { QualityGateStatusConditionEnhanced } from '../../../types/quality-gates';
 import { MeasureEnhanced } from '../../../types/types';
-import { MeasurementType, Status, getMeasurementMetricKey } from '../utils';
+import {
+  MeasurementType,
+  Status,
+  getConditionRequiredLabel,
+  getMeasurementMetricKey,
+} from '../utils';
 import MeasuresCard from './MeasuresCard';
 
 interface Props {
@@ -48,7 +53,6 @@ interface Props {
   conditions: QualityGateStatusConditionEnhanced[];
   conditionMetric: MetricKey;
   newLinesMetric: MetricKey;
-  afterMergeMetric: MetricKey;
 }
 
 export default function MeasuresCardPercent(
@@ -64,7 +68,6 @@ export default function MeasuresCardPercent(
     conditions,
     conditionMetric,
     newLinesMetric,
-    afterMergeMetric,
   } = props;
 
   const intl = useIntl();
@@ -85,24 +88,9 @@ export default function MeasuresCardPercent(
     listView: true,
   });
 
-  const afterMergeValue = findMeasure(measures, afterMergeMetric)?.value;
-
   const condition = conditions.find((c) => c.metric === conditionMetric);
   const conditionFailed = condition?.level === Status.ERROR;
 
-  const requireLabel =
-    condition &&
-    intl.formatMessage(
-      { id: 'overview.quality_gate.required_x' },
-      {
-        operator: condition.op === 'GT' ? '≤' : '≥',
-        value: formatMeasure(condition.error, MetricType.Percent, {
-          decimals: 2,
-          omitExtraDecimalZeros: true,
-        }),
-      },
-    );
-
   return (
     <MeasuresCard
       value={formatMeasure(value, MetricType.Percent)}
@@ -114,15 +102,18 @@ export default function MeasuresCardPercent(
     >
       <>
         <span className="sw-body-xs sw-mt-3">
-          {requireLabel &&
+          {condition &&
             (conditionFailed ? (
-              <TextError className="sw-font-regular" text={requireLabel} />
+              <TextError
+                className="sw-font-regular sw-inline"
+                text={getConditionRequiredLabel(condition, intl, true)}
+              />
             ) : (
-              <LightLabel>{requireLabel}</LightLabel>
+              <LightLabel>{getConditionRequiredLabel(condition, intl)}</LightLabel>
             ))}
         </span>
 
-        <div className="sw-flex sw-justify-between sw-items-center sw-mt-1">
+        <div className="sw-flex sw-body-sm sw-justify-between sw-items-center sw-mt-1">
           <LightLabel className="sw-flex sw-items-center sw-gap-1 ">
             <FormattedMessage
               defaultMessage={translate(newLinesLabel)}
@@ -144,17 +135,6 @@ export default function MeasuresCardPercent(
               }}
             />
           </LightLabel>
-          <LightLabel className="sw-mt-[1px]">
-            {afterMergeValue && (
-              <FormattedMessage
-                defaultMessage={translate('overview.quality_gate.x_estimated_after_merge')}
-                id="overview.quality_gate.x_estimated_after_merge"
-                values={{
-                  value: <strong>{formatMeasure(afterMergeValue, MetricType.Percent)}</strong>,
-                }}
-              />
-            )}
-          </LightLabel>
         </div>
       </>
     </MeasuresCard>
index d5c82848bbf6e34cb5b6150524c32cd33cec964e..3de4a392362970979b62bb4915fc48b08b8a42af 100644 (file)
@@ -38,12 +38,12 @@ import MeasuresCardPanel from './MeasuresCardPanel';
 import SonarLintAd from './SonarLintAd';
 
 interface Props {
-  branchLike: PullRequest;
+  pullRequest: PullRequest;
   component: Component;
 }
 
-export default function PullRequestOverview(props: Readonly<Props>) {
-  const { component, branchLike } = props;
+export default function PullRequestOverview(props: Readonly<Readonly<Props>>) {
+  const { component, pullRequest } = props;
 
   const {
     data: { conditions, ignoredConditions, status } = {},
@@ -58,7 +58,7 @@ export default function PullRequestOverview(props: Readonly<Props>) {
     useComponentMeasuresWithMetricsQuery(
       component.key,
       uniq([...PR_METRICS, ...(conditions?.map((c) => c.metric) ?? [])]),
-      getBranchLikeQuery(branchLike),
+      getBranchLikeQuery(pullRequest),
       !isLoadingBranchStatusesData,
     );
 
@@ -97,14 +97,14 @@ export default function PullRequestOverview(props: Readonly<Props>) {
     <CenteredLayout>
       <PageContentFontWrapper className="it__pr-overview sw-mt-12 sw-mb-8 sw-grid sw-grid-cols-12 sw-body-sm">
         <div className="sw-col-start-2 sw-col-span-10">
-          <MetaTopBar branchLike={branchLike} measures={measures} />
+          <MetaTopBar branchLike={pullRequest} measures={measures} />
           <BasicSeparator className="sw-my-4" />
 
           {ignoredConditions && <IgnoredConditionWarning />}
 
           {status && (
             <BranchQualityGate
-              branchLike={branchLike}
+              branchLike={pullRequest}
               component={component}
               status={status}
               failedConditions={failedConditions}
@@ -113,7 +113,7 @@ export default function PullRequestOverview(props: Readonly<Props>) {
 
           <MeasuresCardPanel
             className="sw-flex-1"
-            branchLike={branchLike}
+            pullRequest={pullRequest}
             component={component}
             conditions={enhancedConditions}
             measures={measures}
index 23cfee021e4ced77376521cad2a817521099d716..ee0a364e5437920ec2dd962cd09990a5a5d6a996 100644 (file)
@@ -62,6 +62,9 @@ jest.mock('../../../../api/measures', () => {
           mockMeasure({
             metric: MetricKey.new_violations,
           }),
+          mockMeasure({
+            metric: MetricKey.pull_request_fixed_issues,
+          }),
         ],
       },
       metrics: [
@@ -70,6 +73,7 @@ jest.mock('../../../../api/measures', () => {
         mockMetric({ key: MetricKey.new_lines, type: MetricType.ShortInteger }),
         mockMetric({ key: MetricKey.new_bugs, type: MetricType.Integer }),
         mockMetric({ key: MetricKey.new_violations }),
+        mockMetric({ key: MetricKey.pull_request_fixed_issues }),
       ],
     }),
   };
@@ -117,6 +121,36 @@ jest.mock('../../../../api/quality-gates', () => {
   };
 });
 
+it('should render links correctly', async () => {
+  jest.mocked(getQualityGateProjectStatus).mockResolvedValueOnce({
+    status: 'OK',
+    conditions: [],
+    caycStatus: CaycStatus.Compliant,
+    ignoredConditions: false,
+  });
+  renderPullRequestOverview();
+
+  await waitFor(async () => expect(await screen.findByText('metric.level.OK')).toBeInTheDocument());
+  expect(screen.getByLabelText('overview.quality_gate_x.overview.gate.OK')).toBeInTheDocument();
+
+  expect(
+    byRole('link', {
+      name: 'overview.see_more_details_on_x_of_y.1.metric.new_violations.name',
+    }).get(),
+  ).toHaveAttribute(
+    'href',
+    '/project/issues?pullRequest=1001&issueStatuses=OPEN%2CCONFIRMED&id=foo',
+  );
+
+  expect(
+    byRole('link', {
+      name: 'overview.see_more_details_on_x_of_y.1.metric.pull_request_fixed_issues.name',
+    }).get(),
+  ).toHaveAttribute('href', '/project/issues?branch=master&fixedInPullRequest=1001&id=foo');
+
+  expect(screen.getByLabelText('no_data')).toBeInTheDocument();
+});
+
 it('should render correctly for a passed QG', async () => {
   jest.mocked(getQualityGateProjectStatus).mockResolvedValueOnce({
     status: 'OK',
@@ -283,7 +317,7 @@ function renderPullRequestOverview(
   renderComponent(
     <CurrentUserContextProvider currentUser={currentUser}>
       <PullRequestOverview
-        branchLike={mockPullRequest()}
+        pullRequest={mockPullRequest()}
         component={mockComponent({
           breadcrumbs: [mockComponent({ key: 'foo' })],
           key: 'foo',
diff --git a/server/sonar-web/src/main/js/apps/overview/utils.ts b/server/sonar-web/src/main/js/apps/overview/utils.ts
deleted file mode 100644 (file)
index 85ec7ce..0000000
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * 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 { memoize } from 'lodash';
-import CoverageRating from '../../components/ui/CoverageRating';
-import DuplicationsRating from '../../components/ui/DuplicationsRating';
-import { ISSUETYPE_METRIC_KEYS_MAP } from '../../helpers/issues';
-import { translate } from '../../helpers/l10n';
-import { parseAsString } from '../../helpers/query';
-import { IssueType } from '../../types/issues';
-import { MetricKey } from '../../types/metrics';
-import { AnalysisMeasuresVariations, MeasureHistory } from '../../types/project-activity';
-import { Dict, RawQuery } from '../../types/types';
-
-export const METRICS: string[] = [
-  // quality gate
-  MetricKey.alert_status,
-  MetricKey.quality_gate_details, // TODO: still relevant?
-
-  // bugs
-  MetricKey.bugs,
-  MetricKey.new_bugs,
-  MetricKey.reliability_rating,
-  MetricKey.new_reliability_rating,
-
-  // vulnerabilities
-  MetricKey.vulnerabilities,
-  MetricKey.new_vulnerabilities,
-  MetricKey.security_rating,
-  MetricKey.new_security_rating,
-
-  // hotspots
-  MetricKey.security_hotspots,
-  MetricKey.new_security_hotspots,
-  MetricKey.security_hotspots_reviewed,
-  MetricKey.new_security_hotspots_reviewed,
-  MetricKey.security_review_rating,
-  MetricKey.new_security_review_rating,
-
-  // code smells
-  MetricKey.code_smells,
-  MetricKey.new_code_smells,
-  MetricKey.sqale_rating,
-  MetricKey.new_maintainability_rating,
-  MetricKey.sqale_index,
-  MetricKey.new_technical_debt,
-
-  // coverage
-  MetricKey.coverage,
-  MetricKey.new_coverage,
-  MetricKey.lines_to_cover,
-  MetricKey.new_lines_to_cover,
-  MetricKey.tests,
-
-  // duplications
-  MetricKey.duplicated_lines_density,
-  MetricKey.new_duplicated_lines_density,
-  MetricKey.duplicated_blocks,
-
-  // size
-  MetricKey.ncloc,
-  MetricKey.ncloc_language_distribution,
-  MetricKey.projects,
-  MetricKey.lines,
-  MetricKey.new_lines,
-];
-
-export const PR_METRICS: string[] = [
-  MetricKey.coverage,
-  MetricKey.new_coverage,
-  MetricKey.new_lines_to_cover,
-
-  MetricKey.new_violations,
-  MetricKey.duplicated_lines_density,
-  MetricKey.new_duplicated_lines_density,
-  MetricKey.new_lines,
-  MetricKey.new_code_smells,
-  MetricKey.new_maintainability_rating,
-  MetricKey.new_bugs,
-  MetricKey.new_reliability_rating,
-  MetricKey.new_vulnerabilities,
-  MetricKey.new_security_hotspots,
-  MetricKey.new_security_review_rating,
-  MetricKey.new_security_rating,
-];
-
-export const HISTORY_METRICS_LIST: string[] = [
-  MetricKey.bugs,
-  MetricKey.vulnerabilities,
-  MetricKey.sqale_index,
-  MetricKey.duplicated_lines_density,
-  MetricKey.ncloc,
-  MetricKey.coverage,
-  MetricKey.alert_status,
-];
-
-const MEASURES_VARIATIONS_METRICS = [
-  MetricKey.bugs,
-  MetricKey.code_smells,
-  MetricKey.coverage,
-  MetricKey.duplicated_lines_density,
-  MetricKey.vulnerabilities,
-];
-
-export enum MeasurementType {
-  Coverage = 'COVERAGE',
-  Duplication = 'DUPLICATION',
-}
-
-export enum Status {
-  OK = 'OK',
-  ERROR = 'ERROR',
-}
-
-const MEASUREMENTS_MAP = {
-  [MeasurementType.Coverage]: {
-    metric: MetricKey.coverage,
-    newMetric: MetricKey.new_coverage,
-    linesMetric: MetricKey.lines_to_cover,
-    newLinesMetric: MetricKey.new_lines_to_cover,
-    afterMergeMetric: MetricKey.coverage,
-    labelKey: 'metric.coverage.name',
-    expandedLabelKey: 'overview.coverage_on_X_lines',
-    newLinesExpandedLabelKey: 'overview.coverage_on_X_new_lines',
-    iconClass: CoverageRating,
-  },
-  [MeasurementType.Duplication]: {
-    metric: MetricKey.duplicated_lines_density,
-    newMetric: MetricKey.new_duplicated_lines_density,
-    linesMetric: MetricKey.ncloc,
-    newLinesMetric: MetricKey.new_lines,
-    afterMergeMetric: MetricKey.duplicated_lines_density,
-    labelKey: 'metric.duplicated_lines_density.short_name',
-    expandedLabelKey: 'overview.duplications_on_X_lines',
-    newLinesExpandedLabelKey: 'overview.duplications_on_X_new_lines',
-    iconClass: DuplicationsRating,
-  },
-};
-
-export const RATING_TO_SEVERITIES_MAPPING = [
-  'BLOCKER,CRITICAL,MAJOR,MINOR',
-  'BLOCKER,CRITICAL,MAJOR',
-  'BLOCKER,CRITICAL',
-  'BLOCKER',
-];
-
-export const RATING_METRICS_MAPPING: Dict<IssueType> = {
-  [MetricKey.reliability_rating]: IssueType.Bug,
-  [MetricKey.new_reliability_rating]: IssueType.Bug,
-  [MetricKey.security_rating]: IssueType.Vulnerability,
-  [MetricKey.new_security_rating]: IssueType.Vulnerability,
-  [MetricKey.sqale_rating]: IssueType.CodeSmell,
-  [MetricKey.new_maintainability_rating]: IssueType.CodeSmell,
-  [MetricKey.security_review_rating]: IssueType.SecurityHotspot,
-  [MetricKey.new_security_review_rating]: IssueType.SecurityHotspot,
-};
-
-export const METRICS_REPORTED_IN_OVERVIEW_CARDS = [
-  MetricKey.new_violations,
-  MetricKey.violations,
-  MetricKey.new_coverage,
-  MetricKey.coverage,
-  MetricKey.new_security_hotspots_reviewed,
-  MetricKey.security_hotspots_reviewed,
-  MetricKey.new_duplicated_lines_density,
-  MetricKey.duplicated_lines_density,
-];
-
-export function getIssueRatingName(type: IssueType) {
-  return translate('metric_domain', ISSUETYPE_METRIC_KEYS_MAP[type].ratingName);
-}
-
-export function getIssueIconClass(type: IssueType) {
-  return ISSUETYPE_METRIC_KEYS_MAP[type].iconClass;
-}
-
-export function getIssueMetricKey(type: IssueType, useDiffMetric: boolean) {
-  return useDiffMetric
-    ? ISSUETYPE_METRIC_KEYS_MAP[type].newMetric
-    : ISSUETYPE_METRIC_KEYS_MAP[type].metric;
-}
-
-export function getIssueRatingMetricKey(type: IssueType, useDiffMetric: boolean) {
-  return useDiffMetric
-    ? ISSUETYPE_METRIC_KEYS_MAP[type].newRating
-    : ISSUETYPE_METRIC_KEYS_MAP[type].rating;
-}
-
-export function getMeasurementIconClass(type: MeasurementType) {
-  return MEASUREMENTS_MAP[type].iconClass;
-}
-
-export function getMeasurementMetricKey(type: MeasurementType, useDiffMetric: boolean) {
-  return useDiffMetric ? MEASUREMENTS_MAP[type].newMetric : MEASUREMENTS_MAP[type].metric;
-}
-
-export function getMeasurementAfterMergeMetricKey(type: MeasurementType) {
-  return MEASUREMENTS_MAP[type].afterMergeMetric;
-}
-
-export function getMeasurementLinesMetricKey(type: MeasurementType, useDiffMetric: boolean) {
-  return useDiffMetric ? MEASUREMENTS_MAP[type].newLinesMetric : MEASUREMENTS_MAP[type].linesMetric;
-}
-
-export function getMeasurementLabelKeys(type: MeasurementType, useDiffMetric: boolean) {
-  return {
-    expandedLabelKey: useDiffMetric
-      ? MEASUREMENTS_MAP[type].newLinesExpandedLabelKey
-      : MEASUREMENTS_MAP[type].expandedLabelKey,
-    labelKey: MEASUREMENTS_MAP[type].labelKey,
-  };
-}
-
-export const parseQuery = memoize((urlQuery: RawQuery): { codeScope: string } => {
-  return {
-    codeScope: parseAsString(urlQuery['code_scope']),
-  };
-});
-
-export function getAnalysisVariations(measures: MeasureHistory[], analysesCount: number) {
-  if (analysesCount === 0) {
-    return [];
-  }
-
-  const emptyVariations: AnalysisMeasuresVariations[] = Array.from(
-    { length: analysesCount },
-    () => ({}),
-  );
-
-  return measures.reduce((variations, { metric, history }) => {
-    if (!MEASURES_VARIATIONS_METRICS.includes(metric)) {
-      return variations;
-    }
-
-    history.slice(-analysesCount).forEach(({ value = '' }, index, analysesHistory) => {
-      if (index === 0) {
-        variations[index][metric] = parseFloat(value) || 0;
-        return;
-      }
-
-      const previousValue = parseFloat(analysesHistory[index - 1].value ?? '') || 0;
-      const numericValue = parseFloat(value) || 0;
-      const variation = numericValue - previousValue;
-
-      if (variation === 0) {
-        return;
-      }
-
-      variations[index][metric] = variation;
-    });
-
-    return variations;
-  }, emptyVariations);
-}
diff --git a/server/sonar-web/src/main/js/apps/overview/utils.tsx b/server/sonar-web/src/main/js/apps/overview/utils.tsx
new file mode 100644 (file)
index 0000000..a3816df
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * 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 { memoize } from 'lodash';
+import React from 'react';
+import { IntlShape } from 'react-intl';
+import CoverageRating from '../../components/ui/CoverageRating';
+import DuplicationsRating from '../../components/ui/DuplicationsRating';
+import { ISSUETYPE_METRIC_KEYS_MAP } from '../../helpers/issues';
+import { translate } from '../../helpers/l10n';
+import { formatMeasure } from '../../helpers/measures';
+import { parseAsString } from '../../helpers/query';
+import { IssueType } from '../../types/issues';
+import { MetricKey } from '../../types/metrics';
+import { AnalysisMeasuresVariations, MeasureHistory } from '../../types/project-activity';
+import { QualityGateStatusConditionEnhanced } from '../../types/quality-gates';
+import { Dict, RawQuery } from '../../types/types';
+
+export const METRICS: string[] = [
+  // quality gate
+  MetricKey.alert_status,
+  MetricKey.quality_gate_details, // TODO: still relevant?
+
+  // bugs
+  MetricKey.bugs,
+  MetricKey.new_bugs,
+  MetricKey.reliability_rating,
+  MetricKey.new_reliability_rating,
+
+  // vulnerabilities
+  MetricKey.vulnerabilities,
+  MetricKey.new_vulnerabilities,
+  MetricKey.security_rating,
+  MetricKey.new_security_rating,
+
+  // hotspots
+  MetricKey.security_hotspots,
+  MetricKey.new_security_hotspots,
+  MetricKey.security_hotspots_reviewed,
+  MetricKey.new_security_hotspots_reviewed,
+  MetricKey.security_review_rating,
+  MetricKey.new_security_review_rating,
+
+  // code smells
+  MetricKey.code_smells,
+  MetricKey.new_code_smells,
+  MetricKey.sqale_rating,
+  MetricKey.new_maintainability_rating,
+  MetricKey.sqale_index,
+  MetricKey.new_technical_debt,
+
+  // coverage
+  MetricKey.coverage,
+  MetricKey.new_coverage,
+  MetricKey.lines_to_cover,
+  MetricKey.new_lines_to_cover,
+  MetricKey.tests,
+
+  // duplications
+  MetricKey.duplicated_lines_density,
+  MetricKey.new_duplicated_lines_density,
+  MetricKey.duplicated_blocks,
+
+  // size
+  MetricKey.ncloc,
+  MetricKey.ncloc_language_distribution,
+  MetricKey.projects,
+  MetricKey.lines,
+  MetricKey.new_lines,
+];
+
+export const PR_METRICS: string[] = [
+  MetricKey.coverage,
+  MetricKey.new_coverage,
+  MetricKey.new_lines_to_cover,
+
+  MetricKey.new_accepted_issues,
+  MetricKey.new_violations,
+  MetricKey.duplicated_lines_density,
+  MetricKey.new_duplicated_lines_density,
+  MetricKey.new_lines,
+  MetricKey.new_code_smells,
+  MetricKey.new_maintainability_rating,
+  MetricKey.new_bugs,
+  MetricKey.new_reliability_rating,
+  MetricKey.new_vulnerabilities,
+  MetricKey.new_security_hotspots,
+  MetricKey.new_security_review_rating,
+  MetricKey.new_security_rating,
+
+  MetricKey.pull_request_fixed_issues,
+];
+
+export const HISTORY_METRICS_LIST: string[] = [
+  MetricKey.bugs,
+  MetricKey.vulnerabilities,
+  MetricKey.sqale_index,
+  MetricKey.duplicated_lines_density,
+  MetricKey.ncloc,
+  MetricKey.coverage,
+  MetricKey.alert_status,
+];
+
+const MEASURES_VARIATIONS_METRICS = [
+  MetricKey.bugs,
+  MetricKey.code_smells,
+  MetricKey.coverage,
+  MetricKey.duplicated_lines_density,
+  MetricKey.vulnerabilities,
+];
+
+export enum MeasurementType {
+  Coverage = 'COVERAGE',
+  Duplication = 'DUPLICATION',
+}
+
+export enum Status {
+  OK = 'OK',
+  ERROR = 'ERROR',
+}
+
+const MEASUREMENTS_MAP = {
+  [MeasurementType.Coverage]: {
+    metric: MetricKey.coverage,
+    newMetric: MetricKey.new_coverage,
+    linesMetric: MetricKey.lines_to_cover,
+    newLinesMetric: MetricKey.new_lines_to_cover,
+    afterMergeMetric: MetricKey.coverage,
+    labelKey: 'metric.coverage.name',
+    expandedLabelKey: 'overview.coverage_on_X_lines',
+    newLinesExpandedLabelKey: 'overview.coverage_on_X_new_lines',
+    iconClass: CoverageRating,
+  },
+  [MeasurementType.Duplication]: {
+    metric: MetricKey.duplicated_lines_density,
+    newMetric: MetricKey.new_duplicated_lines_density,
+    linesMetric: MetricKey.ncloc,
+    newLinesMetric: MetricKey.new_lines,
+    afterMergeMetric: MetricKey.duplicated_lines_density,
+    labelKey: 'metric.duplicated_lines_density.short_name',
+    expandedLabelKey: 'overview.duplications_on_X_lines',
+    newLinesExpandedLabelKey: 'overview.duplications_on_X_new_lines',
+    iconClass: DuplicationsRating,
+  },
+};
+
+export const RATING_TO_SEVERITIES_MAPPING = [
+  'BLOCKER,CRITICAL,MAJOR,MINOR',
+  'BLOCKER,CRITICAL,MAJOR',
+  'BLOCKER,CRITICAL',
+  'BLOCKER',
+];
+
+export const RATING_METRICS_MAPPING: Dict<IssueType> = {
+  [MetricKey.reliability_rating]: IssueType.Bug,
+  [MetricKey.new_reliability_rating]: IssueType.Bug,
+  [MetricKey.security_rating]: IssueType.Vulnerability,
+  [MetricKey.new_security_rating]: IssueType.Vulnerability,
+  [MetricKey.sqale_rating]: IssueType.CodeSmell,
+  [MetricKey.new_maintainability_rating]: IssueType.CodeSmell,
+  [MetricKey.security_review_rating]: IssueType.SecurityHotspot,
+  [MetricKey.new_security_review_rating]: IssueType.SecurityHotspot,
+};
+
+export const METRICS_REPORTED_IN_OVERVIEW_CARDS = [
+  MetricKey.new_violations,
+  MetricKey.violations,
+  MetricKey.new_coverage,
+  MetricKey.coverage,
+  MetricKey.new_security_hotspots_reviewed,
+  MetricKey.security_hotspots_reviewed,
+  MetricKey.new_duplicated_lines_density,
+  MetricKey.duplicated_lines_density,
+];
+
+export function getIssueRatingName(type: IssueType) {
+  return translate('metric_domain', ISSUETYPE_METRIC_KEYS_MAP[type].ratingName);
+}
+
+export function getIssueIconClass(type: IssueType) {
+  return ISSUETYPE_METRIC_KEYS_MAP[type].iconClass;
+}
+
+export function getIssueMetricKey(type: IssueType, useDiffMetric: boolean) {
+  return useDiffMetric
+    ? ISSUETYPE_METRIC_KEYS_MAP[type].newMetric
+    : ISSUETYPE_METRIC_KEYS_MAP[type].metric;
+}
+
+export function getIssueRatingMetricKey(type: IssueType, useDiffMetric: boolean) {
+  return useDiffMetric
+    ? ISSUETYPE_METRIC_KEYS_MAP[type].newRating
+    : ISSUETYPE_METRIC_KEYS_MAP[type].rating;
+}
+
+export function getMeasurementIconClass(type: MeasurementType) {
+  return MEASUREMENTS_MAP[type].iconClass;
+}
+
+export function getMeasurementMetricKey(type: MeasurementType, useDiffMetric: boolean) {
+  return useDiffMetric ? MEASUREMENTS_MAP[type].newMetric : MEASUREMENTS_MAP[type].metric;
+}
+
+export function getMeasurementAfterMergeMetricKey(type: MeasurementType) {
+  return MEASUREMENTS_MAP[type].afterMergeMetric;
+}
+
+export function getMeasurementLinesMetricKey(type: MeasurementType, useDiffMetric: boolean) {
+  return useDiffMetric ? MEASUREMENTS_MAP[type].newLinesMetric : MEASUREMENTS_MAP[type].linesMetric;
+}
+
+export function getMeasurementLabelKeys(type: MeasurementType, useDiffMetric: boolean) {
+  return {
+    expandedLabelKey: useDiffMetric
+      ? MEASUREMENTS_MAP[type].newLinesExpandedLabelKey
+      : MEASUREMENTS_MAP[type].expandedLabelKey,
+    labelKey: MEASUREMENTS_MAP[type].labelKey,
+  };
+}
+
+export const parseQuery = memoize((urlQuery: RawQuery): { codeScope: string } => {
+  return {
+    codeScope: parseAsString(urlQuery['code_scope']),
+  };
+});
+
+export function getAnalysisVariations(measures: MeasureHistory[], analysesCount: number) {
+  if (analysesCount === 0) {
+    return [];
+  }
+
+  const emptyVariations: AnalysisMeasuresVariations[] = Array.from(
+    { length: analysesCount },
+    () => ({}),
+  );
+
+  return measures.reduce((variations, { metric, history }) => {
+    if (!MEASURES_VARIATIONS_METRICS.includes(metric)) {
+      return variations;
+    }
+
+    history.slice(-analysesCount).forEach(({ value = '' }, index, analysesHistory) => {
+      if (index === 0) {
+        variations[index][metric] = parseFloat(value) || 0;
+        return;
+      }
+
+      const previousValue = parseFloat(analysesHistory[index - 1].value ?? '') || 0;
+      const numericValue = parseFloat(value) || 0;
+      const variation = numericValue - previousValue;
+
+      if (variation === 0) {
+        return;
+      }
+
+      variations[index][metric] = variation;
+    });
+
+    return variations;
+  }, emptyVariations);
+}
+
+export function getConditionRequiredLabel(
+  condition: QualityGateStatusConditionEnhanced,
+  intl: IntlShape,
+  failed = false,
+) {
+  const conditionEl = (
+    <>
+      {condition.op === 'GT' ? '≤' : '≥'}{' '}
+      {formatMeasure(condition.error, condition.measure.metric.type, {
+        decimals: 2,
+        omitExtraDecimalZeros: true,
+      })}
+    </>
+  );
+  return intl.formatMessage(
+    { id: 'overview.quality_gate.required_x' },
+    {
+      requirement: failed ? <b>{conditionEl}</b> : conditionEl,
+    },
+  );
+}
index 2d7e20c26158c85c6d0c262b711b6daef42d8f8f..1134b4e62b716f5a9407d4024aa0166849330bb6 100644 (file)
@@ -21,7 +21,6 @@ import { Dict, Metric } from '../../types/types';
 
 export const DEFAULT_METRICS: Dict<Metric> = {
   new_technical_debt: {
-    id: 'AXJMbIl_PAOIsUIE3guE',
     key: 'new_technical_debt',
     type: 'WORK_DUR',
     name: 'Added Technical Debt',
@@ -32,7 +31,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   blocker_violations: {
-    id: 'AXJMbIl_PAOIsUIE3gtt',
     key: 'blocker_violations',
     type: 'INT',
     name: 'Blocker Issues',
@@ -43,7 +41,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   bugs: {
-    id: 'AXJMbIl_PAOIsUIE3gt_',
     key: 'bugs',
     type: 'INT',
     name: 'Bugs',
@@ -54,7 +51,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   classes: {
-    id: 'AXJMbImPPAOIsUIE3gu5',
     key: 'classes',
     type: 'INT',
     name: 'Classes',
@@ -65,7 +61,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   code_smells: {
-    id: 'AXJMbIl_PAOIsUIE3gt9',
     key: 'code_smells',
     type: 'INT',
     name: 'Code Smells',
@@ -76,7 +71,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   cognitive_complexity: {
-    id: 'AXJMbIl9PAOIsUIE3gtZ',
     key: 'cognitive_complexity',
     type: 'INT',
     name: 'Cognitive Complexity',
@@ -87,7 +81,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   comment_lines: {
-    id: 'AXJMbImPPAOIsUIE3gup',
     key: 'comment_lines',
     type: 'INT',
     name: 'Comment Lines',
@@ -98,7 +91,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   comment_lines_data: {
-    id: 'AXJMbImPPAOIsUIE3guV',
     key: 'comment_lines_data',
     type: 'DATA',
     name: 'comment_lines_data',
@@ -108,7 +100,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   comment_lines_density: {
-    id: 'AXJMbImPPAOIsUIE3guq',
     key: 'comment_lines_density',
     type: 'PERCENT',
     name: 'Comments (%)',
@@ -120,7 +111,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     decimalScale: 1,
   },
   class_complexity: {
-    id: 'AXJMbImPPAOIsUIE3guw',
     key: 'class_complexity',
     type: 'FLOAT',
     name: 'Complexity / Class',
@@ -132,7 +122,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     decimalScale: 1,
   },
   file_complexity: {
-    id: 'AXJMbImPPAOIsUIE3guu',
     key: 'file_complexity',
     type: 'FLOAT',
     name: 'Complexity / File',
@@ -144,7 +133,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     decimalScale: 1,
   },
   function_complexity: {
-    id: 'AXJMbImPPAOIsUIE3guy',
     key: 'function_complexity',
     type: 'FLOAT',
     name: 'Complexity / Function',
@@ -156,7 +144,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     decimalScale: 1,
   },
   complexity_in_classes: {
-    id: 'AXJMbImPPAOIsUIE3guv',
     key: 'complexity_in_classes',
     type: 'INT',
     name: 'Complexity in Classes',
@@ -167,7 +154,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   complexity_in_functions: {
-    id: 'AXJMbImPPAOIsUIE3gux',
     key: 'complexity_in_functions',
     type: 'INT',
     name: 'Complexity in Functions',
@@ -178,7 +164,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   branch_coverage: {
-    id: 'AXJMbIl9PAOIsUIE3gs-',
     key: 'branch_coverage',
     type: 'PERCENT',
     name: 'Condition Coverage',
@@ -190,7 +175,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     decimalScale: 1,
   },
   new_branch_coverage: {
-    id: 'AXJMbIl9PAOIsUIE3gs_',
     key: 'new_branch_coverage',
     type: 'PERCENT',
     name: 'Condition Coverage on New Code',
@@ -202,7 +186,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     decimalScale: 1,
   },
   conditions_to_cover: {
-    id: 'AXJMbIl9PAOIsUIE3gqt',
     key: 'conditions_to_cover',
     type: 'INT',
     name: 'Conditions to Cover',
@@ -213,7 +196,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   new_conditions_to_cover: {
-    id: 'AXJMbIl9PAOIsUIE3gs7',
     key: 'new_conditions_to_cover',
     type: 'INT',
     name: 'Conditions to Cover on New Code',
@@ -224,7 +206,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   confirmed_issues: {
-    id: 'AXJMbIl_PAOIsUIE3gt8',
     key: 'confirmed_issues',
     type: 'INT',
     name: 'Confirmed Issues',
@@ -235,7 +216,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   coverage: {
-    id: 'AXJMbIl9PAOIsUIE3gtg',
     key: 'coverage',
     type: 'PERCENT',
     name: 'Coverage',
@@ -247,7 +227,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     decimalScale: 1,
   },
   new_coverage: {
-    id: 'AXJMbIl_PAOIsUIE3gth',
     key: 'new_coverage',
     type: 'PERCENT',
     name: 'Coverage on New Code',
@@ -259,7 +238,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     decimalScale: 1,
   },
   critical_violations: {
-    id: 'AXJMbIl_PAOIsUIE3gtu',
     key: 'critical_violations',
     type: 'INT',
     name: 'Critical Issues',
@@ -270,7 +248,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   complexity: {
-    id: 'AXJMbImPPAOIsUIE3gut',
     key: 'complexity',
     type: 'INT',
     name: 'Cyclomatic Complexity',
@@ -281,7 +258,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   last_commit_date: {
-    id: 'AXJMbImPPAOIsUIE3gua',
     key: 'last_commit_date',
     type: 'MILLISEC',
     name: 'Date of Last Commit',
@@ -291,7 +267,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   development_cost: {
-    id: 'AXJMbIl_PAOIsUIE3guI',
     key: 'development_cost',
     type: 'STRING',
     name: 'Development Cost',
@@ -302,7 +277,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   new_development_cost: {
-    id: 'AXJMbIl_PAOIsUIE3guJ',
     key: 'new_development_cost',
     type: 'FLOAT',
     name: 'Development Cost on New Code',
@@ -314,7 +288,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     decimalScale: 1,
   },
   directories: {
-    id: 'AXJMbImPPAOIsUIE3gu9',
     key: 'directories',
     type: 'INT',
     name: 'Directories',
@@ -325,7 +298,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   duplicated_blocks: {
-    id: 'AXJMbIl9PAOIsUIE3gsu',
     key: 'duplicated_blocks',
     type: 'INT',
     name: 'Duplicated Blocks',
@@ -336,7 +308,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   new_duplicated_blocks: {
-    id: 'AXJMbIl_PAOIsUIE3gto',
     key: 'new_duplicated_blocks',
     type: 'INT',
     name: 'Duplicated Blocks on New Code',
@@ -347,7 +318,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   duplicated_files: {
-    id: 'AXJMbImPPAOIsUIE3gvA',
     key: 'duplicated_files',
     type: 'INT',
     name: 'Duplicated Files',
@@ -358,7 +328,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   duplicated_lines: {
-    id: 'AXJMbIl9PAOIsUIE3gss',
     key: 'duplicated_lines',
     type: 'INT',
     name: 'Duplicated Lines',
@@ -369,7 +338,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   duplicated_lines_density: {
-    id: 'AXJMbIl_PAOIsUIE3gtp',
     key: 'duplicated_lines_density',
     type: 'PERCENT',
     name: 'Duplicated Lines (%)',
@@ -381,7 +349,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     decimalScale: 1,
   },
   new_duplicated_lines_density: {
-    id: 'AXJMbIl_PAOIsUIE3gtq',
     key: 'new_duplicated_lines_density',
     type: 'PERCENT',
     name: 'Duplicated Lines (%) on New Code',
@@ -393,7 +360,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     decimalScale: 1,
   },
   new_duplicated_lines: {
-    id: 'AXJMbIl9PAOIsUIE3gst',
     key: 'new_duplicated_lines',
     type: 'INT',
     name: 'Duplicated Lines on New Code',
@@ -404,7 +370,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   duplications_data: {
-    id: 'AXJMbIl_PAOIsUIE3gtr',
     key: 'duplications_data',
     type: 'DATA',
     name: 'Duplication Details',
@@ -415,7 +380,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   effort_to_reach_maintainability_rating_a: {
-    id: 'AXJMbIl_PAOIsUIE3guM',
     key: 'effort_to_reach_maintainability_rating_a',
     type: 'WORK_DUR',
     name: 'Effort to Reach Maintainability Rating A',
@@ -426,7 +390,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   executable_lines_data: {
-    id: 'AXJMbImPPAOIsUIE3guW',
     key: 'executable_lines_data',
     type: 'DATA',
     name: 'executable_lines_data',
@@ -436,7 +399,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   false_positive_issues: {
-    id: 'AXJMbIl_PAOIsUIE3gt4',
     key: 'false_positive_issues',
     type: 'INT',
     name: 'False Positive Issues',
@@ -447,7 +409,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   file_complexity_distribution: {
-    id: 'AXJMbIl9PAOIsUIE3gtY',
     key: 'file_complexity_distribution',
     type: 'DISTRIB',
     name: 'File Distribution / Complexity',
@@ -458,7 +419,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   files: {
-    id: 'AXJMbImPPAOIsUIE3gu6',
     key: 'files',
     type: 'INT',
     name: 'Files',
@@ -469,7 +429,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   function_complexity_distribution: {
-    id: 'AXJMbIl9PAOIsUIE3gtX',
     key: 'function_complexity_distribution',
     type: 'DISTRIB',
     name: 'Function Distribution / Complexity',
@@ -480,7 +439,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   functions: {
-    id: 'AXJMbImPPAOIsUIE3gu-',
     key: 'functions',
     type: 'INT',
     name: 'Functions',
@@ -491,7 +449,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   generated_lines: {
-    id: 'AXJMbImPPAOIsUIE3gu0',
     key: 'generated_lines',
     type: 'INT',
     name: 'Generated Lines',
@@ -502,7 +459,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   generated_ncloc: {
-    id: 'AXJMbImPPAOIsUIE3gu4',
     key: 'generated_ncloc',
     type: 'INT',
     name: 'Generated Lines of Code',
@@ -513,7 +469,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   info_violations: {
-    id: 'AXJMbIl_PAOIsUIE3gtx',
     key: 'info_violations',
     type: 'INT',
     name: 'Info Issues',
@@ -524,7 +479,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   violations: {
-    id: 'AXJMbImPPAOIsUIE3gul',
     key: 'violations',
     type: 'INT',
     name: 'Issues',
@@ -535,7 +489,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   last_change_on_maintainability_rating: {
-    id: 'AXJMbImPPAOIsUIE3gud',
     key: 'last_change_on_maintainability_rating',
     type: 'DATA',
     name: 'Last Change on Maintainability Rating',
@@ -545,7 +498,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   last_change_on_releasability_rating: {
-    id: 'AXJMbImPPAOIsUIE3gue',
     key: 'last_change_on_releasability_rating',
     type: 'DATA',
     name: 'Last Change on Releasability Rating',
@@ -555,7 +507,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   last_change_on_reliability_rating: {
-    id: 'AXJMbImPPAOIsUIE3guf',
     key: 'last_change_on_reliability_rating',
     type: 'DATA',
     name: 'Last Change on Reliability Rating',
@@ -565,7 +516,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   last_change_on_security_rating: {
-    id: 'AXJMbImPPAOIsUIE3gug',
     key: 'last_change_on_security_rating',
     type: 'DATA',
     name: 'Last Change on Security Rating',
@@ -575,7 +525,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   last_change_on_security_review_rating: {
-    id: 'AXJMbIl9PAOIsUIE3gs4',
     key: 'last_change_on_security_review_rating',
     type: 'DATA',
     name: 'Last Change on Security Review Rating',
@@ -585,7 +534,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   line_coverage: {
-    id: 'AXJMbIl_PAOIsUIE3gtl',
     key: 'line_coverage',
     type: 'PERCENT',
     name: 'Line Coverage',
@@ -597,7 +545,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     decimalScale: 1,
   },
   new_line_coverage: {
-    id: 'AXJMbIl_PAOIsUIE3gtm',
     key: 'new_line_coverage',
     type: 'PERCENT',
     name: 'Line Coverage on New Code',
@@ -609,7 +556,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     decimalScale: 1,
   },
   lines: {
-    id: 'AXJMbImPPAOIsUIE3guz',
     key: 'lines',
     type: 'INT',
     name: 'Lines',
@@ -620,7 +566,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   ncloc: {
-    id: 'AXJMbImPPAOIsUIE3gu1',
     key: 'ncloc',
     type: 'INT',
     name: 'Lines of Code',
@@ -631,7 +576,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   ncloc_language_distribution: {
-    id: 'AXJMbImPPAOIsUIE3gu3',
     key: 'ncloc_language_distribution',
     type: 'DATA',
     name: 'Lines of Code Per Language',
@@ -642,7 +586,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   lines_to_cover: {
-    id: 'AXJMbImPPAOIsUIE3gu_',
     key: 'lines_to_cover',
     type: 'INT',
     name: 'Lines to Cover',
@@ -653,7 +596,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   new_lines_to_cover: {
-    id: 'AXJMbIl_PAOIsUIE3gti',
     key: 'new_lines_to_cover',
     type: 'INT',
     name: 'Lines to Cover on New Code',
@@ -664,7 +606,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   leak_projects: {
-    id: 'AXJMbImPPAOIsUIE3gvE',
     key: 'leak_projects',
     type: 'DATA',
     name: 'List of technical projects with their leaks',
@@ -673,7 +614,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   sqale_rating: {
-    id: 'AXJMbIl_PAOIsUIE3guF',
     key: 'sqale_rating',
     type: 'RATING',
     name: 'Maintainability Rating',
@@ -684,7 +624,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   maintainability_rating_distribution: {
-    id: 'AX6QkqP7zEziun0YBqmh',
     key: 'maintainability_rating_distribution',
     type: 'DATA',
     name: 'Maintainability Rating Distribution',
@@ -695,7 +634,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   new_maintainability_rating_distribution: {
-    id: 'AX6QkqP8zEziun0YBqml',
     key: 'new_maintainability_rating_distribution',
     type: 'DATA',
     name: 'Maintainability Rating Distribution on New Code',
@@ -706,7 +644,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   new_maintainability_rating: {
-    id: 'AXJMbIl_PAOIsUIE3guH',
     key: 'new_maintainability_rating',
     type: 'RATING',
     name: 'Maintainability Rating on New Code',
@@ -717,7 +654,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   major_violations: {
-    id: 'AXJMbIl_PAOIsUIE3gtv',
     key: 'major_violations',
     type: 'INT',
     name: 'Major Issues',
@@ -728,7 +664,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   minor_violations: {
-    id: 'AXJMbIl_PAOIsUIE3gtw',
     key: 'minor_violations',
     type: 'INT',
     name: 'Minor Issues',
@@ -739,7 +674,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   ncloc_data: {
-    id: 'AXJMbImPPAOIsUIE3guU',
     key: 'ncloc_data',
     type: 'DATA',
     name: 'ncloc_data',
@@ -749,7 +683,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   new_blocker_violations: {
-    id: 'AXJMbIl_PAOIsUIE3gtz',
     key: 'new_blocker_violations',
     type: 'INT',
     name: 'New Blocker Issues',
@@ -760,7 +693,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   new_bugs: {
-    id: 'AXJMbIl_PAOIsUIE3guA',
     key: 'new_bugs',
     type: 'INT',
     name: 'New Bugs',
@@ -771,7 +703,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   new_code_smells: {
-    id: 'AXJMbIl_PAOIsUIE3gt-',
     key: 'new_code_smells',
     type: 'INT',
     name: 'New Code Smells',
@@ -782,7 +713,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   new_critical_violations: {
-    id: 'AXJMbIl_PAOIsUIE3gt0',
     key: 'new_critical_violations',
     type: 'INT',
     name: 'New Critical Issues',
@@ -793,7 +723,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   new_info_violations: {
-    id: 'AXJMbIl_PAOIsUIE3gt3',
     key: 'new_info_violations',
     type: 'INT',
     name: 'New Info Issues',
@@ -804,7 +733,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   new_violations: {
-    id: 'AXJMbIl_PAOIsUIE3gty',
     key: 'new_violations',
     type: 'INT',
     name: 'New Issues',
@@ -815,7 +743,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   new_lines: {
-    id: 'AXJMbImPPAOIsUIE3gu2',
     key: 'new_lines',
     type: 'INT',
     name: 'New Lines',
@@ -826,7 +753,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   new_major_violations: {
-    id: 'AXJMbIl_PAOIsUIE3gt1',
     key: 'new_major_violations',
     type: 'INT',
     name: 'New Major Issues',
@@ -837,7 +763,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   new_minor_violations: {
-    id: 'AXJMbIl_PAOIsUIE3gt2',
     key: 'new_minor_violations',
     type: 'INT',
     name: 'New Minor Issues',
@@ -848,7 +773,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   new_security_hotspots: {
-    id: 'AXJMbIl9PAOIsUIE3gsw',
     key: 'new_security_hotspots',
     type: 'INT',
     name: 'New Security Hotspots',
@@ -859,7 +783,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   new_vulnerabilities: {
-    id: 'AXJMbIl_PAOIsUIE3guC',
     key: 'new_vulnerabilities',
     type: 'INT',
     name: 'New Vulnerabilities',
@@ -870,7 +793,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   unanalyzed_c: {
-    id: 'AXTb6RMqLLQlB5osv3xN',
     key: 'unanalyzed_c',
     type: 'INT',
     name: 'Number of unanalyzed c files',
@@ -880,7 +802,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   unanalyzed_cpp: {
-    id: 'AXTb6RMtLLQlB5osv3xO',
     key: 'unanalyzed_cpp',
     type: 'INT',
     name: 'Number of unanalyzed c++ files',
@@ -890,7 +811,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   open_issues: {
-    id: 'AXJMbIl_PAOIsUIE3gt6',
     key: 'open_issues',
     type: 'INT',
     name: 'Open Issues',
@@ -901,7 +821,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   quality_profiles: {
-    id: 'AXJMbImPPAOIsUIE3guZ',
     key: 'quality_profiles',
     type: 'DATA',
     name: 'Profiles',
@@ -912,7 +831,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   projects: {
-    id: 'AXJMbImPPAOIsUIE3guo',
     key: 'projects',
     type: 'INT',
     name: 'Project branches',
@@ -923,7 +841,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   public_api: {
-    id: 'AXJMbImPPAOIsUIE3gun',
     key: 'public_api',
     type: 'INT',
     name: 'Public API',
@@ -934,7 +851,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   public_documented_api_density: {
-    id: 'AXJMbImPPAOIsUIE3gur',
     key: 'public_documented_api_density',
     type: 'PERCENT',
     name: 'Public Documented API (%)',
@@ -946,7 +862,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     decimalScale: 1,
   },
   public_undocumented_api: {
-    id: 'AXJMbImPPAOIsUIE3gus',
     key: 'public_undocumented_api',
     type: 'INT',
     name: 'Public Undocumented API',
@@ -957,7 +872,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   quality_gate_details: {
-    id: 'AXJMbImPPAOIsUIE3guY',
     key: 'quality_gate_details',
     type: 'DATA',
     name: 'Quality Gate Details',
@@ -968,7 +882,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   alert_status: {
-    id: 'AXJMbImPPAOIsUIE3guX',
     key: 'alert_status',
     type: 'LEVEL',
     name: 'Quality Gate Status',
@@ -979,7 +892,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   releasability_rating: {
-    id: 'AXJMbImPPAOIsUIE3guc',
     key: 'releasability_rating',
     type: 'RATING',
     name: 'Releasability rating',
@@ -989,7 +901,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   releasability_rating_distribution: {
-    id: 'AX6QkqP7zEziun0YBqmg',
     key: 'releasability_rating_distribution',
     type: 'DATA',
     name: 'Releasability Rating Distribution',
@@ -1000,7 +911,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   reliability_rating: {
-    id: 'AXJMbIl_PAOIsUIE3guP',
     key: 'reliability_rating',
     type: 'RATING',
     name: 'Reliability Rating',
@@ -1011,7 +921,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   reliability_rating_distribution: {
-    id: 'AX6QkqP7zEziun0YBqmi',
     key: 'reliability_rating_distribution',
     type: 'DATA',
     name: 'Reliability Rating Distribution',
@@ -1022,7 +931,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   new_reliability_rating_distribution: {
-    id: 'AX6QkqP8zEziun0YBqmm',
     key: 'new_reliability_rating_distribution',
     type: 'DATA',
     name: 'Reliability Rating Distribution on New Code',
@@ -1033,7 +941,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   new_reliability_rating: {
-    id: 'AXJMbIl_PAOIsUIE3guQ',
     key: 'new_reliability_rating',
     type: 'RATING',
     name: 'Reliability Rating on New Code',
@@ -1044,7 +951,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   reliability_remediation_effort: {
-    id: 'AXJMbIl_PAOIsUIE3guN',
     key: 'reliability_remediation_effort',
     type: 'WORK_DUR',
     name: 'Reliability Remediation Effort',
@@ -1055,7 +961,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   new_reliability_remediation_effort: {
-    id: 'AXJMbIl_PAOIsUIE3guO',
     key: 'new_reliability_remediation_effort',
     type: 'WORK_DUR',
     name: 'Reliability Remediation Effort on New Code',
@@ -1066,7 +971,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   reopened_issues: {
-    id: 'AXJMbIl_PAOIsUIE3gt7',
     key: 'reopened_issues',
     type: 'INT',
     name: 'Reopened Issues',
@@ -1077,7 +981,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   security_hotspots: {
-    id: 'AXJMbIl9PAOIsUIE3gsv',
     key: 'security_hotspots',
     type: 'INT',
     name: 'Security Hotspots',
@@ -1088,7 +991,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   security_hotspots_reviewed: {
-    id: 'AXJMbIl9PAOIsUIE3gs0',
     key: 'security_hotspots_reviewed',
     type: 'PERCENT',
     name: 'Security Hotspots Reviewed',
@@ -1100,7 +1002,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     decimalScale: 1,
   },
   new_security_hotspots_reviewed: {
-    id: 'AXJMbIl9PAOIsUIE3gs1',
     key: 'new_security_hotspots_reviewed',
     type: 'PERCENT',
     name: 'Security Hotspots Reviewed on New Code',
@@ -1112,7 +1013,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     decimalScale: 1,
   },
   security_rating: {
-    id: 'AXJMbIl_PAOIsUIE3guS',
     key: 'security_rating',
     type: 'RATING',
     name: 'Security Rating',
@@ -1123,7 +1023,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   security_rating_distribution: {
-    id: 'AX6QkqP7zEziun0YBqmj',
     key: 'security_rating_distribution',
     type: 'DATA',
     name: 'Security Rating Distribution',
@@ -1134,7 +1033,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   new_security_rating_distribution: {
-    id: 'AX6QkqP8zEziun0YBqmn',
     key: 'new_security_rating_distribution',
     type: 'DATA',
     name: 'Security Rating Distribution on New Code',
@@ -1145,7 +1043,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   new_security_rating: {
-    id: 'AXJMbImPPAOIsUIE3guT',
     key: 'new_security_rating',
     type: 'RATING',
     name: 'Security Rating on New Code',
@@ -1156,7 +1053,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   security_remediation_effort: {
-    id: 'AXJMbIl_PAOIsUIE3guG',
     key: 'security_remediation_effort',
     type: 'WORK_DUR',
     name: 'Security Remediation Effort',
@@ -1167,7 +1063,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   new_security_remediation_effort: {
-    id: 'AXJMbIl_PAOIsUIE3guR',
     key: 'new_security_remediation_effort',
     type: 'WORK_DUR',
     name: 'Security Remediation Effort on New Code',
@@ -1178,7 +1073,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   security_review_rating: {
-    id: 'AXJMbIl9PAOIsUIE3gsx',
     key: 'security_review_rating',
     type: 'RATING',
     name: 'Security Review Rating',
@@ -1189,7 +1083,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   security_review_rating_distribution: {
-    id: 'AX6QkqP8zEziun0YBqmk',
     key: 'security_review_rating_distribution',
     type: 'DATA',
     name: 'Security Review Rating Distribution',
@@ -1200,7 +1093,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   new_security_review_rating_distribution: {
-    id: 'AX6QkqP8zEziun0YBqmo',
     key: 'new_security_review_rating_distribution',
     type: 'DATA',
     name: 'Security Review Rating Distribution on New Code',
@@ -1211,7 +1103,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   new_security_review_rating: {
-    id: 'AXJMbIl9PAOIsUIE3gtA',
     key: 'new_security_review_rating',
     type: 'RATING',
     name: 'Security Review Rating on New Code',
@@ -1222,7 +1113,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   security_hotspots_reviewed_status: {
-    id: 'AXJMbIl9PAOIsUIE3gs2',
     key: 'security_hotspots_reviewed_status',
     type: 'INT',
     name: 'Security Review Reviewed Status',
@@ -1233,7 +1123,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   new_security_hotspots_reviewed_status: {
-    id: 'AXJMbIl9PAOIsUIE3gtB',
     key: 'new_security_hotspots_reviewed_status',
     type: 'INT',
     name: 'Security Review Reviewed Status on New Code',
@@ -1244,7 +1133,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   security_hotspots_to_review_status: {
-    id: 'AXJMbIl9PAOIsUIE3gs3',
     key: 'security_hotspots_to_review_status',
     type: 'INT',
     name: 'Security Review To Review Status',
@@ -1255,7 +1143,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   new_security_hotspots_to_review_status: {
-    id: 'AXJMbIl9PAOIsUIE3gs5',
     key: 'new_security_hotspots_to_review_status',
     type: 'INT',
     name: 'Security Review To Review Status on New Code',
@@ -1266,7 +1153,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   skipped_tests: {
-    id: 'AXJMbIl9PAOIsUIE3gtd',
     key: 'skipped_tests',
     type: 'INT',
     name: 'Skipped Unit Tests',
@@ -1277,7 +1163,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   statements: {
-    id: 'AXJMbImPPAOIsUIE3gum',
     key: 'statements',
     type: 'INT',
     name: 'Statements',
@@ -1288,7 +1173,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   sqale_index: {
-    id: 'AXJMbIl_PAOIsUIE3guD',
     key: 'sqale_index',
     type: 'WORK_DUR',
     name: 'Technical Debt',
@@ -1300,7 +1184,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   sqale_debt_ratio: {
-    id: 'AXJMbIl_PAOIsUIE3guK',
     key: 'sqale_debt_ratio',
     type: 'PERCENT',
     name: 'Technical Debt Ratio',
@@ -1313,7 +1196,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     decimalScale: 1,
   },
   new_sqale_debt_ratio: {
-    id: 'AXJMbIl_PAOIsUIE3guL',
     key: 'new_sqale_debt_ratio',
     type: 'PERCENT',
     name: 'Technical Debt Ratio on New Code',
@@ -1325,7 +1207,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     decimalScale: 1,
   },
   maintainability_rating_effort: {
-    id: 'AXJMbImPPAOIsUIE3gvD',
     key: 'maintainability_rating_effort',
     type: 'DATA',
     name: 'Total number of projects having worst maintainability rating',
@@ -1335,7 +1216,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   reliability_rating_effort: {
-    id: 'AXJMbImPPAOIsUIE3gvC',
     key: 'reliability_rating_effort',
     type: 'DATA',
     name: 'Total number of projects having worst reliability rating',
@@ -1345,7 +1225,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   security_rating_effort: {
-    id: 'AXJMbImPPAOIsUIE3gvB',
     key: 'security_rating_effort',
     type: 'DATA',
     name: 'Total number of projects having worst security rating',
@@ -1355,7 +1234,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   security_review_rating_effort: {
-    id: 'AXJMbIl9PAOIsUIE3gs6',
     key: 'security_review_rating_effort',
     type: 'DATA',
     name: 'Total number of projects having worst security review rating',
@@ -1365,7 +1243,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   releasability_effort: {
-    id: 'AXJMbImPPAOIsUIE3gub',
     key: 'releasability_effort',
     type: 'INT',
     name: 'Total number of projects not production ready',
@@ -1375,7 +1252,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: true,
   },
   uncovered_conditions: {
-    id: 'AXJMbIl9PAOIsUIE3gs8',
     key: 'uncovered_conditions',
     type: 'INT',
     name: 'Uncovered Conditions',
@@ -1386,7 +1262,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   new_uncovered_conditions: {
-    id: 'AXJMbIl9PAOIsUIE3gs9',
     key: 'new_uncovered_conditions',
     type: 'INT',
     name: 'Uncovered Conditions on New Code',
@@ -1397,7 +1272,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   uncovered_lines: {
-    id: 'AXJMbIl_PAOIsUIE3gtj',
     key: 'uncovered_lines',
     type: 'INT',
     name: 'Uncovered Lines',
@@ -1408,7 +1282,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   new_uncovered_lines: {
-    id: 'AXJMbIl_PAOIsUIE3gtk',
     key: 'new_uncovered_lines',
     type: 'INT',
     name: 'Uncovered Lines on New Code',
@@ -1419,7 +1292,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   test_execution_time: {
-    id: 'AXJMbIl9PAOIsUIE3gtb',
     key: 'test_execution_time',
     type: 'MILLISEC',
     name: 'Unit Test Duration',
@@ -1430,7 +1302,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   test_errors: {
-    id: 'AXJMbIl9PAOIsUIE3gtc',
     key: 'test_errors',
     type: 'INT',
     name: 'Unit Test Errors',
@@ -1441,7 +1312,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   test_failures: {
-    id: 'AXJMbIl9PAOIsUIE3gte',
     key: 'test_failures',
     type: 'INT',
     name: 'Unit Test Failures',
@@ -1452,7 +1322,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   tests: {
-    id: 'AXJMbIl9PAOIsUIE3gta',
     key: 'tests',
     type: 'INT',
     name: 'Unit Tests',
@@ -1463,7 +1332,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   test_success_density: {
-    id: 'AXJMbIl9PAOIsUIE3gtf',
     key: 'test_success_density',
     type: 'PERCENT',
     name: 'Unit Test Success (%)',
@@ -1475,7 +1343,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     decimalScale: 1,
   },
   vulnerabilities: {
-    id: 'AXJMbIl_PAOIsUIE3guB',
     key: 'vulnerabilities',
     type: 'INT',
     name: 'Vulnerabilities',
@@ -1486,7 +1353,6 @@ export const DEFAULT_METRICS: Dict<Metric> = {
     hidden: false,
   },
   accepted_issues: {
-    id: 'AXJMbIl_PAOIsUIE3ga7',
     key: 'accepted_issues',
     type: 'INT',
     name: 'Accepted Issues',
index 0a4b5e9f32efe30c8e305eb7e574222717435af8..0ef2c641c7c6975a5ada365b58382b7aea680d5e 100644 (file)
@@ -426,7 +426,6 @@ export function mockMetric(
   const type = overrides.type || MetricType.Percent;
   return {
     ...overrides,
-    id: key,
     key,
     name,
     type,
index 43e1cc79d95b83e0ed4f9267ad172c500d3cdf32..f1b6edd1f0d720f930313d3b67c2b969a392ed87 100644 (file)
@@ -117,7 +117,7 @@ export enum MetricKey {
   public_api = 'public_api',
   public_documented_api_density = 'public_documented_api_density',
   public_undocumented_api = 'public_undocumented_api',
-  pullrequest_addressed_issues = 'pullrequest_addressed_issues',
+  pull_request_fixed_issues = 'pull_request_fixed_issues',
   quality_gate_details = 'quality_gate_details',
   quality_profiles = 'quality_profiles',
   releasability_effort = 'releasability_effort',
index 35ee598d76ece7d530bd3c1ca31cdbac73cd7c04..416d5c4cd3c1659b0696bde0ab3879efeb504bae 100644 (file)
@@ -393,7 +393,6 @@ export interface Metric {
   domain?: string;
   hidden?: boolean;
   higherValuesAreBetter?: boolean;
-  id: string;
   key: string;
   name: string;
   qualitative?: boolean;
index f162c8c0c84ae3fc8c6490e60060e0c12100c580..f43ef32e6700cdd7bceaa19b8db2b7359ae4ceae 100644 (file)
@@ -3264,6 +3264,10 @@ metric.wont_fix_issues.description=Won't fix issues
 metric.wont_fix_issues.name=Won't Fix Issues
 metric.accepted_issues.description=Accepted issues
 metric.accepted_issues.name=Accepted Issues
+metric.pull_request_fixed_issues.name=Fixed issues
+metric.pull_request_fixed_issues.description=Fixed issues
+metric.new_accepted_issues.name=Accepted issues
+metric.new_accepted_issues.description=Accepted issues
 
 #------------------------------------------------------------------------------
 #
@@ -3845,6 +3849,13 @@ overview.X_conditions_failed={0} failed conditions
 overview.failed_condition.x_rating_required={rating} is {value}. Required {threshold}
 overview.failed_condition.x_required={metric}. Required {threshold}
 overview.fix_failed_conditions_with_sonarlint=Fix issues before they fail your Quality Gate with {link} in your IDE. Power up with connected mode!
+overview.pull_request.new_issues=New issues
+overview.pull_request.fixed_issues=Fixed issues
+overview.pull_request.fixed_issues.help=Estimation of issues fixed by this PR
+overview.pull_request.fixed_issues.disclaimer=Only issues fixed on the files modified by the pull request are taken into account. Issues incidentally fixed on unmodified files are not counted.
+overview.pull_request.fixed_issues.disclaimer.2=When the pull request and the target branch are not synchronized, issues introduced on the target branch may be incorrectly considered fixed by the pull request. Rebasing the pull request would give an updated value.
+overview.pull_request.accepted_issues=Accepted issues
+overview.pull_request.accepted_issues.help=Valid issues that were not fixed
 overview.quality_gate.status=Quality Gate Status
 overview.quality_gate=Quality Gate
 overview.quality_gate_x=Quality Gate: {0}
@@ -3875,7 +3886,7 @@ overview.quality_gate.on_x_new_lines=On {link} New Lines.
 overview.quality_gate.x_estimated_after_merge={value} Estimated after merge
 overview.quality_gate.require_fixing={count, plural, one {requires} other {require}} fixing
 overview.quality_gate.require_reviewing={count, plural, one {requires} other {require}} reviewing
-overview.quality_gate.required_x=Required {operator} {value}
+overview.quality_gate.required_x=Required {requirement}
 overview.quality_profiles=Quality Profiles used
 overview.new_code_period_x=New Code: {0}
 overview.max_new_code_period_from_x=Max New Code from: {0}