aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorstanislavh <stanislav.honcharov@sonarsource.com>2024-11-13 11:50:50 +0100
committersonartech <sonartech@sonarsource.com>2024-11-14 20:02:49 +0000
commit35f65c3c6204a1d3bbe5ed0670a716a61f06e126 (patch)
treef1dcfc040bf341b74b67cc59199f865e127dd492 /server
parent04d38e931b0aa44cfb3d228205b9d907bd0cf194 (diff)
downloadsonarqube-35f65c3c6204a1d3bbe5ed0670a716a61f06e126.tar.gz
sonarqube-35f65c3c6204a1d3bbe5ed0670a716a61f06e126.zip
SONAR-23536 Project badges page supports MQR mode
Diffstat (limited to 'server')
-rw-r--r--server/sonar-web/src/main/js/api/mocks/WebApiServiceMock.ts39
-rw-r--r--server/sonar-web/src/main/js/apps/projectInformation/__tests__/ProjectInformationApp-it.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/projectInformation/badges/ProjectBadges.tsx46
-rw-r--r--server/sonar-web/src/main/js/apps/projectInformation/badges/__tests__/ProjectBadges-it.tsx185
-rw-r--r--server/sonar-web/src/main/js/apps/projectInformation/badges/__tests__/ProjectBadges-test.tsx177
-rw-r--r--server/sonar-web/src/main/js/apps/web-api/__tests__/WebApi-it.tsx4
-rw-r--r--server/sonar-web/src/main/js/queries/badges.ts43
7 files changed, 265 insertions, 232 deletions
diff --git a/server/sonar-web/src/main/js/api/mocks/WebApiServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/WebApiServiceMock.ts
index 11e32e2a0b9..b2ea2630e11 100644
--- a/server/sonar-web/src/main/js/api/mocks/WebApiServiceMock.ts
+++ b/server/sonar-web/src/main/js/api/mocks/WebApiServiceMock.ts
@@ -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 {
diff --git a/server/sonar-web/src/main/js/apps/projectInformation/__tests__/ProjectInformationApp-it.tsx b/server/sonar-web/src/main/js/apps/projectInformation/__tests__/ProjectInformationApp-it.tsx
index 473923080d8..0d7ba65ab3a 100644
--- a/server/sonar-web/src/main/js/apps/projectInformation/__tests__/ProjectInformationApp-it.tsx
+++ b/server/sonar-web/src/main/js/apps/projectInformation/__tests__/ProjectInformationApp-it.tsx
@@ -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 () => {
diff --git a/server/sonar-web/src/main/js/apps/projectInformation/badges/ProjectBadges.tsx b/server/sonar-web/src/main/js/apps/projectInformation/badges/ProjectBadges.tsx
index 247e5e68d7b..28cdc20e5d8 100644
--- a/server/sonar-web/src/main/js/apps/projectInformation/badges/ProjectBadges.tsx
+++ b/server/sonar-web/src/main/js/apps/projectInformation/badges/ProjectBadges.tsx
@@ -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
index 00000000000..c79d23a4496
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/projectInformation/badges/__tests__/ProjectBadges-it.tsx
@@ -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
index 294ff302f0c..00000000000
--- a/server/sonar-web/src/main/js/apps/projectInformation/badges/__tests__/ProjectBadges-test.tsx
+++ /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}
- />,
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/web-api/__tests__/WebApi-it.tsx b/server/sonar-web/src/main/js/apps/web-api/__tests__/WebApi-it.tsx
index 823d16aa4ae..ffe3ba5d54f 100644
--- a/server/sonar-web/src/main/js/apps/web-api/__tests__/WebApi-it.tsx
+++ b/server/sonar-web/src/main/js/apps/web-api/__tests__/WebApi-it.tsx
@@ -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();
diff --git a/server/sonar-web/src/main/js/queries/badges.ts b/server/sonar-web/src/main/js/queries/badges.ts
index e3e74ad28dd..981b2f651a3 100644
--- a/server/sonar-web/src/main/js/queries/badges.ts
+++ b/server/sonar-web/src/main/js/queries/badges.ts
@@ -19,10 +19,12 @@
*/
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) {