]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-23536 Project badges page supports MQR mode
authorstanislavh <stanislav.honcharov@sonarsource.com>
Wed, 13 Nov 2024 10:50:50 +0000 (11:50 +0100)
committersonartech <sonartech@sonarsource.com>
Thu, 14 Nov 2024 20:02:49 +0000 (20:02 +0000)
server/sonar-web/src/main/js/api/mocks/WebApiServiceMock.ts
server/sonar-web/src/main/js/apps/projectInformation/__tests__/ProjectInformationApp-it.tsx
server/sonar-web/src/main/js/apps/projectInformation/badges/ProjectBadges.tsx
server/sonar-web/src/main/js/apps/projectInformation/badges/__tests__/ProjectBadges-it.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/projectInformation/badges/__tests__/ProjectBadges-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/web-api/__tests__/WebApi-it.tsx
server/sonar-web/src/main/js/queries/badges.ts
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index 11e32e2a0b9a5b5d458b8d8bf93e8fc37069e370..b2ea2630e1143e929a10519b2c0ff398d82f4ccb 100644 (file)
@@ -21,6 +21,7 @@
 import { cloneDeep } from 'lodash';
 import { OpenAPIV3 } from 'openapi-types';
 import { mockAction } from '../../helpers/mocks/webapi';
+import { MetricKey } from '../../sonar-aligned/types/metrics';
 import { fetchOpenAPI, fetchWebApi } from '../web-api';
 import { openApiTestData } from './data/web-api';
 
@@ -49,6 +50,44 @@ const BASE_DOMAINS = [
     path: 'internal/thing1',
     since: '1.3',
   },
+  {
+    path: 'api/project_badges',
+    actions: [
+      mockAction({
+        key: 'measure',
+        params: [
+          {
+            key: 'metric',
+            description: 'Badge Metric key',
+            required: true,
+            internal: false,
+            possibleValues: [
+              MetricKey.bugs,
+              MetricKey.software_quality_reliability_issues,
+              MetricKey.code_smells,
+              MetricKey.software_quality_maintainability_issues,
+              MetricKey.vulnerabilities,
+              MetricKey.software_quality_security_issues,
+              MetricKey.sqale_rating,
+              MetricKey.software_quality_maintainability_rating,
+              MetricKey.security_rating,
+              MetricKey.software_quality_security_rating,
+              MetricKey.reliability_rating,
+              MetricKey.software_quality_reliability_rating,
+              MetricKey.coverage,
+              MetricKey.duplicated_lines_density,
+              MetricKey.alert_status,
+              MetricKey.security_hotspots,
+              MetricKey.ncloc,
+            ],
+          },
+        ],
+      }),
+    ],
+    description: 'Badges API',
+    internal: false,
+    since: '1.3',
+  },
 ];
 
 export default class WebApiServiceMock {
index 473923080d83a93429a96020fdd2459c1e9df73b..0d7ba65ab3a9c01582efb7c092ef07d07d4e8121 100644 (file)
@@ -30,6 +30,7 @@ import { MeasuresServiceMock } from '../../../api/mocks/MeasuresServiceMock';
 import NotificationsMock from '../../../api/mocks/NotificationsMock';
 import { ProjectBadgesServiceMock } from '../../../api/mocks/ProjectBadgesServiceMock';
 import ProjectLinksServiceMock from '../../../api/mocks/ProjectLinksServiceMock';
+import SettingsServiceMock from '../../../api/mocks/SettingsServiceMock';
 import { mockComponent } from '../../../helpers/mocks/component';
 import { mockCurrentUser, mockLoggedInUser, mockMeasure } from '../../../helpers/testMocks';
 import {
@@ -56,6 +57,7 @@ const badgesHandler = new ProjectBadgesServiceMock();
 const notificationsHandler = new NotificationsMock();
 const branchesHandler = new BranchesServiceMock();
 const aiCodeAssurance = new AiCodeAssuredServiceMock();
+const settingsHandler = new SettingsServiceMock();
 
 const ui = {
   projectPageTitle: byRole('heading', { name: 'project.info.title' }),
@@ -80,6 +82,7 @@ afterEach(() => {
   notificationsHandler.reset();
   branchesHandler.reset();
   aiCodeAssurance.reset();
+  settingsHandler.reset();
 });
 
 it('should show fields for project', async () => {
index 247e5e68d7b87c2cb4cab89aaf4f6c94eb45e93e..28cdc20e5d89b433151298583fc547bf8866ed33 100644 (file)
@@ -36,11 +36,9 @@ import { Image } from '~sonar-aligned/components/common/Image';
 import { getBranchLikeQuery } from '~sonar-aligned/helpers/branch-like';
 import { MetricKey } from '~sonar-aligned/types/metrics';
 import { useAvailableFeatures } from '../../../app/components/available-features/withAvailableFeatures';
-import { translate, translateWithParameters } from '../../../helpers/l10n';
-import { localizeMetric } from '../../../helpers/measures';
+import { translate } from '../../../helpers/l10n';
 import {
-  DEPRECATED_METRIC_KEYS,
-  useBadgeMetricsQuery,
+  useBadgeMetrics,
   useBadgeTokenQuery,
   useRenewBagdeTokenMutation,
 } from '../../../queries/badges';
@@ -68,7 +66,7 @@ export default function ProjectBadges(props: ProjectBadgesProps) {
     isLoading: isLoadingToken,
     isFetching: isFetchingToken,
   } = useBadgeTokenQuery(project);
-  const { data: metricOptions, isLoading: isLoadingMetrics } = useBadgeMetricsQuery();
+  const { data: metricOptions, isLoading: isLoadingMetrics } = useBadgeMetrics();
   const { mutate: renewToken, isPending: isRenewing } = useRenewBagdeTokenMutation();
   const { hasFeature } = useAvailableFeatures();
   const isLoading = isLoadingMetrics || isLoadingToken || isRenewing;
@@ -156,31 +154,19 @@ export default function ProjectBadges(props: ProjectBadgesProps) {
       </Spinner>
 
       {BadgeType.measure === selectedType && (
-        <>
-          <FormField htmlFor="badge-param-customize" label={translate('overview.badges.metric')}>
-            <InputSelect
-              className="sw-w-abs-300"
-              inputId="badge-param-customize"
-              options={metricOptions}
-              onChange={(option) => {
-                if (option) {
-                  setSelectedMetric(option.value);
-                }
-              }}
-              value={metricOptions.find((m) => m.value === selectedMetric)}
-            />
-          </FormField>
-
-          {DEPRECATED_METRIC_KEYS.includes(selectedMetric) && (
-            <FlagMessage className="sw-mb-4" variant="warning">
-              {translateWithParameters(
-                'overview.badges.deprecated_badge_x_y',
-                localizeMetric(selectedMetric),
-                translate('qualifier', qualifier),
-              )}
-            </FlagMessage>
-          )}
-        </>
+        <FormField htmlFor="badge-param-customize" label={translate('overview.badges.metric')}>
+          <InputSelect
+            className="sw-w-abs-300"
+            inputId="badge-param-customize"
+            options={metricOptions}
+            onChange={(option) => {
+              if (option) {
+                setSelectedMetric(option.value);
+              }
+            }}
+            value={metricOptions.find((m) => m.value === selectedMetric)}
+          />
+        </FormField>
       )}
 
       <BasicSeparator className="sw-mb-4" />
diff --git a/server/sonar-web/src/main/js/apps/projectInformation/badges/__tests__/ProjectBadges-it.tsx b/server/sonar-web/src/main/js/apps/projectInformation/badges/__tests__/ProjectBadges-it.tsx
new file mode 100644 (file)
index 0000000..c79d23a
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * 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 { screen, waitFor } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { MetricKey } from '~sonar-aligned/types/metrics';
+import { ProjectBadgesServiceMock } from '../../../../api/mocks/ProjectBadgesServiceMock';
+import SettingsServiceMock from '../../../../api/mocks/SettingsServiceMock';
+import WebApiServiceMock from '../../../../api/mocks/WebApiServiceMock';
+import { getProjectBadgesToken } from '../../../../api/project-badges';
+import { mockBranch } from '../../../../helpers/mocks/branch-like';
+import { mockComponent } from '../../../../helpers/mocks/component';
+import { renderComponent } from '../../../../helpers/testReactTestingUtils';
+import { Location } from '../../../../helpers/urls';
+import { byLabelText, byRole, byText } from '../../../../sonar-aligned/helpers/testSelector';
+import { ComponentQualifier } from '../../../../sonar-aligned/types/component';
+import { SettingsKey } from '../../../../types/settings';
+import ProjectBadges, { ProjectBadgesProps } from '../ProjectBadges';
+import { BadgeType } from '../utils';
+
+jest.mock('../../../../helpers/urls', () => ({
+  getHostUrl: () => 'host',
+  getPathUrlAsString: (l: Location) => l.pathname,
+  getProjectUrl: () => ({ pathname: '/dashboard' }) as Location,
+}));
+
+const badgesHandler = new ProjectBadgesServiceMock();
+const webApiHandler = new WebApiServiceMock();
+const settingsHandler = new SettingsServiceMock();
+
+afterEach(() => {
+  badgesHandler.reset();
+  webApiHandler.reset();
+  settingsHandler.reset();
+});
+
+it('should renew token', async () => {
+  const { user, ui } = getPageObjects();
+  jest.mocked(getProjectBadgesToken).mockResolvedValueOnce('foo').mockResolvedValueOnce('bar');
+  renderProjectBadges();
+  await ui.appLoaded();
+
+  expect(screen.getByAltText(`overview.badges.${BadgeType.measure}.alt`)).toHaveAttribute(
+    'src',
+    expect.stringContaining(
+      `host/api/project_badges/measure?branch=branch-6.7&project=my-project&metric=${MetricKey.alert_status}&token=foo`,
+    ),
+  );
+
+  await user.click(screen.getByText('overview.badges.renew'));
+
+  expect(
+    await screen.findByAltText(`overview.badges.${BadgeType.qualityGate}.alt`),
+  ).toHaveAttribute(
+    'src',
+    expect.stringContaining(
+      'host/api/project_badges/quality_gate?branch=branch-6.7&project=my-project&token=bar',
+    ),
+  );
+
+  expect(screen.getByAltText(`overview.badges.${BadgeType.measure}.alt`)).toHaveAttribute(
+    'src',
+    expect.stringContaining(
+      `host/api/project_badges/measure?branch=branch-6.7&project=my-project&metric=${MetricKey.alert_status}&token=bar`,
+    ),
+  );
+});
+
+it('can select badges in Standard Experience Mode', async () => {
+  const { user, ui } = getPageObjects();
+  settingsHandler.set(SettingsKey.MQRMode, 'false');
+
+  renderProjectBadges();
+  await ui.appLoaded();
+
+  expect(ui.markdownCode(MetricKey.alert_status).get()).toBeInTheDocument();
+
+  await ui.selectMetric(MetricKey.code_smells);
+  expect(ui.markdownCode(MetricKey.code_smells).get()).toBeInTheDocument();
+
+  await ui.selectMetric(MetricKey.security_rating);
+  expect(ui.markdownCode(MetricKey.security_rating).get()).toBeInTheDocument();
+
+  await user.click(ui.imageUrlRadio.get());
+  expect(ui.urlCode(MetricKey.security_rating).get()).toBeInTheDocument();
+
+  await user.click(ui.qualityGateBadge.get());
+  expect(ui.urlCode().get()).toBeInTheDocument();
+
+  await user.click(ui.mardownRadio.get());
+  expect(ui.markdownCode().get()).toBeInTheDocument();
+});
+
+it('can select badges in MQR Mode', async () => {
+  const { user, ui } = getPageObjects();
+
+  renderProjectBadges();
+  await ui.appLoaded();
+
+  expect(ui.markdownCode(MetricKey.alert_status).get()).toBeInTheDocument();
+
+  await ui.selectMetric(MetricKey.coverage);
+  expect(ui.markdownCode(MetricKey.coverage).get()).toBeInTheDocument();
+
+  await ui.selectMetric(MetricKey.software_quality_reliability_issues);
+  expect(ui.markdownCode(MetricKey.software_quality_reliability_issues).get()).toBeInTheDocument();
+
+  await ui.selectMetric(MetricKey.software_quality_maintainability_rating);
+  expect(
+    ui.markdownCode(MetricKey.software_quality_maintainability_rating).get(),
+  ).toBeInTheDocument();
+
+  await user.click(ui.imageUrlRadio.get());
+  expect(ui.urlCode(MetricKey.software_quality_maintainability_rating).get()).toBeInTheDocument();
+
+  await user.click(ui.qualityGateBadge.get());
+  expect(ui.urlCode().get()).toBeInTheDocument();
+
+  await user.click(ui.mardownRadio.get());
+  expect(ui.markdownCode().get()).toBeInTheDocument();
+});
+
+const getPageObjects = () => {
+  const user = userEvent.setup();
+
+  return {
+    user,
+    ui: {
+      qualityGateBadge: byRole('button', {
+        name: `overview.badges.${BadgeType.qualityGate}.alt overview.badges.${BadgeType.qualityGate}.description.${ComponentQualifier.Project}`,
+      }),
+      imageUrlRadio: byRole('radio', { name: 'overview.badges.options.formats.url' }),
+      mardownRadio: byRole('radio', { name: 'overview.badges.options.formats.md' }),
+      urlCode: (metric?: MetricKey) =>
+        byText(
+          metric
+            ? `host/api/project_badges/measure?branch=branch-6.7&project=my-project&metric=${metric}&token=${badgesHandler.token}`
+            : `host/api/project_badges/quality_gate?branch=branch-6.7&project=my-project&token=${badgesHandler.token}`,
+          { exact: false },
+        ),
+      markdownCode: (metric?: MetricKey) =>
+        byText(
+          metric
+            ? `[![${metric}](host/api/project_badges/measure?branch=branch-6.7&project=my-project&metric=${metric}&token=${badgesHandler.token}`
+            : `[![Quality gate](host/api/project_badges/quality_gate?branch=branch-6.7&project=my-project&token=${badgesHandler.token}`,
+          { exact: false },
+        ),
+
+      async selectMetric(metric: MetricKey) {
+        await user.click(byLabelText('overview.badges.metric').get());
+        await user.click(byText(`metric.${metric}.name`).get());
+      },
+      async appLoaded() {
+        await waitFor(() => expect(screen.queryByLabelText(`loading`)).not.toBeInTheDocument());
+      },
+    },
+  };
+};
+
+function renderProjectBadges(props: Partial<ProjectBadgesProps> = {}) {
+  return renderComponent(
+    <ProjectBadges
+      branchLike={mockBranch()}
+      component={mockComponent({ configuration: { showSettings: true } })}
+      {...props}
+    />,
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/projectInformation/badges/__tests__/ProjectBadges-test.tsx b/server/sonar-web/src/main/js/apps/projectInformation/badges/__tests__/ProjectBadges-test.tsx
deleted file mode 100644 (file)
index 294ff30..0000000
+++ /dev/null
@@ -1,177 +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 { screen, waitFor } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import { MetricKey } from '~sonar-aligned/types/metrics';
-import { getProjectBadgesToken } from '../../../../api/project-badges';
-import { mockBranch } from '../../../../helpers/mocks/branch-like';
-import { mockComponent } from '../../../../helpers/mocks/component';
-import { renderComponent } from '../../../../helpers/testReactTestingUtils';
-import { Location } from '../../../../helpers/urls';
-import { byRole } from '../../../../sonar-aligned/helpers/testSelector';
-import ProjectBadges, { ProjectBadgesProps } from '../ProjectBadges';
-import { BadgeType } from '../utils';
-
-jest.mock('../../../../helpers/urls', () => ({
-  getHostUrl: () => 'host',
-  getPathUrlAsString: (l: Location) => l.pathname,
-  getProjectUrl: () => ({ pathname: '/dashboard' }) as Location,
-}));
-
-jest.mock('../../../../api/project-badges', () => ({
-  getProjectBadgesToken: jest.fn().mockResolvedValue('foo'),
-  renewProjectBadgesToken: jest.fn().mockResolvedValue({}),
-}));
-
-jest.mock('../../../../api/web-api', () => ({
-  fetchWebApi: jest.fn().mockResolvedValue([
-    {
-      path: 'api/project_badges',
-      actions: [
-        {
-          key: 'measure',
-          // eslint-disable-next-line local-rules/use-metrickey-enum
-          params: [{ key: 'metric', possibleValues: ['alert_status', 'coverage', 'bugs'] }],
-        },
-      ],
-    },
-  ]),
-}));
-
-it('should renew token', async () => {
-  const user = userEvent.setup();
-  jest.mocked(getProjectBadgesToken).mockResolvedValueOnce('foo').mockResolvedValueOnce('bar');
-  renderProjectBadges();
-  await appLoaded();
-
-  expect(screen.getByAltText(`overview.badges.${BadgeType.measure}.alt`)).toHaveAttribute(
-    'src',
-    expect.stringContaining(
-      `host/api/project_badges/measure?branch=branch-6.7&project=my-project&metric=${MetricKey.alert_status}&token=foo`,
-    ),
-  );
-
-  await user.click(screen.getByText('overview.badges.renew'));
-
-  expect(
-    await screen.findByAltText(`overview.badges.${BadgeType.qualityGate}.alt`),
-  ).toHaveAttribute(
-    'src',
-    expect.stringContaining(
-      'host/api/project_badges/quality_gate?branch=branch-6.7&project=my-project&token=bar',
-    ),
-  );
-
-  expect(screen.getByAltText(`overview.badges.${BadgeType.measure}.alt`)).toHaveAttribute(
-    'src',
-    expect.stringContaining(
-      `host/api/project_badges/measure?branch=branch-6.7&project=my-project&metric=${MetricKey.alert_status}&token=bar`,
-    ),
-  );
-});
-
-it('should update params', async () => {
-  const user = userEvent.setup();
-  renderProjectBadges();
-  await appLoaded();
-
-  expect(
-    screen.getByText(
-      `[![${MetricKey.alert_status}](host/api/project_badges/measure?branch=branch-6.7&project=my-project&metric=${MetricKey.alert_status}&token=foo`,
-      { exact: false },
-    ),
-  ).toBeInTheDocument();
-
-  await user.click(byRole('radio', { name: 'overview.badges.options.formats.url' }).get());
-
-  expect(
-    screen.getByText(
-      'host/api/project_badges/measure?branch=branch-6.7&project=my-project&metric=alert_status&token=foo',
-      { exact: false },
-    ),
-  ).toBeInTheDocument();
-
-  await user.click(screen.getByLabelText('overview.badges.metric'));
-  await user.click(screen.getByText(`metric.${MetricKey.coverage}.name`));
-
-  expect(
-    screen.getByText(
-      'host/api/project_badges/measure?branch=branch-6.7&project=my-project&metric=coverage&token=foo',
-      { exact: false },
-    ),
-  ).toBeInTheDocument();
-
-  await user.click(
-    screen.getByRole('button', {
-      name: `overview.badges.${BadgeType.qualityGate}.alt overview.badges.${BadgeType.qualityGate}.description.${ComponentQualifier.Project}`,
-    }),
-  );
-
-  expect(
-    screen.getByText(
-      'host/api/project_badges/quality_gate?branch=branch-6.7&project=my-project&token=foo',
-      { exact: false },
-    ),
-  ).toBeInTheDocument();
-
-  await user.click(
-    screen.getByRole('button', {
-      name: `overview.badges.${BadgeType.measure}.alt overview.badges.${BadgeType.measure}.description.${ComponentQualifier.Project}`,
-    }),
-  );
-
-  expect(
-    screen.getByText(
-      'host/api/project_badges/measure?branch=branch-6.7&project=my-project&metric=coverage&token=foo',
-      { exact: false },
-    ),
-  ).toBeInTheDocument();
-});
-
-it('should warn about deprecated metrics', async () => {
-  const user = userEvent.setup();
-  renderProjectBadges();
-  await appLoaded();
-
-  await user.click(screen.getByLabelText('overview.badges.metric'));
-  await user.click(screen.getByText(`metric.${MetricKey.bugs}.name (deprecated)`));
-
-  expect(
-    screen.getByText(
-      `overview.badges.deprecated_badge_x_y.metric.${MetricKey.bugs}.name.qualifier.${ComponentQualifier.Project}`,
-    ),
-  ).toBeInTheDocument();
-});
-
-async function appLoaded() {
-  await waitFor(() => expect(screen.queryByLabelText(`loading`)).not.toBeInTheDocument());
-}
-
-function renderProjectBadges(props: Partial<ProjectBadgesProps> = {}) {
-  return renderComponent(
-    <ProjectBadges
-      branchLike={mockBranch()}
-      component={mockComponent({ configuration: { showSettings: true } })}
-      {...props}
-    />,
-  );
-}
index 823d16aa4ae5d2d7e6f90b3869c8cd4a818454c1..ffe3ba5d54f1f0b552675bda724b14c6c703683f 100644 (file)
@@ -37,7 +37,7 @@ it('should allow to browse the api', async () => {
   renderWebApi();
 
   expect(await ui.sidebarHeader.find()).toBeInTheDocument();
-  expect(await ui.domainMenuItems.findAll()).toHaveLength(1);
+  expect(await ui.domainMenuItems.findAll()).toHaveLength(2);
 
   await user.click(ui.domainMenuItemLink('foo/bar').get());
 
@@ -63,7 +63,7 @@ it('should allow to browse the api', async () => {
   // Show internal
   await user.click(ui.showInternalCheckbox.get());
 
-  expect(await ui.domainMenuItems.findAll()).toHaveLength(2);
+  expect(await ui.domainMenuItems.findAll()).toHaveLength(3);
 
   await user.click(ui.domainMenuItemLink('internal/thing1 internal').get());
   expect(await byText('get internal memos').find()).toBeInTheDocument();
index e3e74ad28dd07dcb82359d059a5600fa05816f0a..981b2f651a30a3034a9ca938d2d7331c5aae4e8e 100644 (file)
  */
 
 import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
+import { uniq } from 'lodash';
 import { MetricKey } from '~sonar-aligned/types/metrics';
 import { getProjectBadgesToken, renewProjectBadgesToken } from '../api/project-badges';
-import { translate } from '../helpers/l10n';
+import { MQR_CONDITIONS_MAP, STANDARD_CONDITIONS_MAP } from '../apps/quality-gates/utils';
 import { localizeMetric } from '../helpers/measures';
+import { useStandardExperienceMode } from './settings';
 import { useWebApiQuery } from './web-api';
 
 export function useRenewBagdeTokenMutation() {
@@ -37,34 +39,29 @@ export function useRenewBagdeTokenMutation() {
   });
 }
 
-// The same list of deprecated metric keys is maintained on the backend at org.sonar.server.badge.ws.MeasureAction.
-export const DEPRECATED_METRIC_KEYS = [
-  MetricKey.bugs,
-  MetricKey.code_smells,
-  MetricKey.security_hotspots,
-  MetricKey.vulnerabilities,
-];
-
-export function useBadgeMetricsQuery() {
-  const { data: webservices = [], ...rest } = useWebApiQuery();
+export function useBadgeMetrics() {
+  const { data: webservices = [], isLoading: isLoadingWebApi } = useWebApiQuery();
+  const { data: isStandardExperience, isLoading: isLoadingMode } = useStandardExperienceMode();
   const domain = webservices.find((d) => d.path === 'api/project_badges');
   const ws = domain?.actions.find((w) => w.key === 'measure');
   const param = ws?.params?.find((p) => p.key === 'metric');
-  if (param?.possibleValues) {
+  if (param?.possibleValues && !isLoadingMode) {
     return {
-      ...rest,
-      data: param.possibleValues.map((key: MetricKey) => {
-        const label = localizeMetric(key);
-        return {
-          value: key,
-          label: DEPRECATED_METRIC_KEYS.includes(key)
-            ? `${label} (${translate('deprecated')})`
-            : label,
-        };
-      }),
+      isLoading: false,
+      data: uniq(
+        param.possibleValues.map((metric: MetricKey) => {
+          return (
+            (isStandardExperience ? MQR_CONDITIONS_MAP[metric] : STANDARD_CONDITIONS_MAP[metric]) ??
+            metric
+          );
+        }),
+      ).map((metric) => ({
+        value: metric,
+        label: localizeMetric(metric),
+      })),
     };
   }
-  return { ...rest, data: [] };
+  return { isLoading: isLoadingWebApi || isLoadingMode, data: [] };
 }
 
 export function useBadgeTokenQuery(componentKey: string) {
index 36f8eb405ebe412cd09f7744adadeb6ad63effb5..c382b9ff75f035248d3ab3f478ce927facf1bda8 100644 (file)
@@ -4518,7 +4518,6 @@ overview.badges.ai_code_assurance.description.TRK=Displays the current status of
 overview.badges.leak_warning=Project badges can expose your security rating and other measures. Only use project badges in trusted environments.
 overview.badges.renew=Renew Token
 overview.badges.renew.description=If your project badge security token has leaked to an unsafe environment, you can renew it:
-overview.badges.deprecated_badge_x_y=Badges displaying {0} are deprecated and will be removed in a future version. Please choose another badge for your {1}.
 
 overview.quality_profiles_update_after_sq_upgrade.message=Upgrade to {productName} {sqVersion} has updated your Quality Profiles. Issues on your project may have been affected. {link}
 overview.quality_profiles_update_after_sq_upgrade.link=See more details