aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorDamien Urruty <damien.urruty@sonarsource.com>2024-11-07 11:40:57 +0100
committersonartech <sonartech@sonarsource.com>2024-11-19 20:02:53 +0000
commitae49ca686664b229b51b5f74299d45d87d663e30 (patch)
treee429325cb663fa48d4b9ada25438e2075ff0381e /server
parent778a9b293e71eef256a1b3bb90beb79d5b1c075e (diff)
downloadsonarqube-ae49ca686664b229b51b5f74299d45d87d663e30.tar.gz
sonarqube-ae49ca686664b229b51b5f74299d45d87d663e30.zip
CODEFIX-183 Check project enablement to show the 'Generate AI Fix' button
Diffstat (limited to 'server')
-rw-r--r--server/sonar-web/src/main/js/api/components.ts1
-rw-r--r--server/sonar-web/src/main/js/apps/issues/__tests__/IssueApp-it.tsx38
-rw-r--r--server/sonar-web/src/main/js/queries/fix-suggestions.tsx14
3 files changed, 39 insertions, 14 deletions
diff --git a/server/sonar-web/src/main/js/api/components.ts b/server/sonar-web/src/main/js/api/components.ts
index b98c6c1e0cf..05e518efa37 100644
--- a/server/sonar-web/src/main/js/api/components.ts
+++ b/server/sonar-web/src/main/js/api/components.ts
@@ -55,6 +55,7 @@ export interface ProjectBase {
export interface ComponentRaw {
analysisDate?: string;
isAiCodeAssured?: boolean;
+ isAiCodeFixEnabled?: boolean;
isFavorite?: boolean;
key: string;
leakPeriodDate?: string;
diff --git a/server/sonar-web/src/main/js/apps/issues/__tests__/IssueApp-it.tsx b/server/sonar-web/src/main/js/apps/issues/__tests__/IssueApp-it.tsx
index 1e03aaa26df..4b70147a63b 100644
--- a/server/sonar-web/src/main/js/apps/issues/__tests__/IssueApp-it.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/__tests__/IssueApp-it.tsx
@@ -23,10 +23,12 @@ import userEvent from '@testing-library/user-event';
import { range } from 'lodash';
import React from 'react';
import { byRole, byText } from '~sonar-aligned/helpers/testSelector';
-import { ISSUE_101, ISSUE_1101 } from '../../../api/mocks/data/ids';
+import { ISSUE_101, ISSUE_1101, ISSUE_2 } from '../../../api/mocks/data/ids';
import { TabKeys } from '../../../components/rules/RuleTabViewer';
+import { mockComponent } from '../../../helpers/mocks/component';
import { mockCurrentUser, mockCve, mockLoggedInUser } from '../../../helpers/testMocks';
import { Feature } from '../../../types/features';
+import { Component } from '../../../types/types';
import { RestUserDetailed } from '../../../types/users';
import {
branchHandler,
@@ -94,7 +96,10 @@ describe('issue app', () => {
});
it('should be able to trigger a fix when feature is available', async () => {
- settingsHandler.set('sonar.ai.suggestions.enabled', 'true');
+ componentsHandler.registerComponent({
+ ...mockComponent({ key: 'myproject' }),
+ isAiCodeFixEnabled: true,
+ } as Component);
sourcesHandler.setSource(
range(0, 1)
.map((n) => `line: ${n}`)
@@ -102,7 +107,7 @@ describe('issue app', () => {
);
const user = userEvent.setup();
renderProjectIssuesApp(
- 'project/issues?issueStatuses=CONFIRMED&open=issue2&id=myproject',
+ `project/issues?issueStatuses=CONFIRMED&open=${ISSUE_2}&id=myproject`,
{},
mockLoggedInUser(),
[Feature.BranchSupport, Feature.FixSuggestions],
@@ -130,6 +135,28 @@ describe('issue app', () => {
expect(ui.issueCodeFixTab.query()).not.toBeInTheDocument();
});
+ it('should not be able to trigger a fix when the feature is disabled', async () => {
+ componentsHandler.registerComponent({
+ ...mockComponent({ key: 'myproject' }),
+ isAiCodeFixEnabled: false,
+ } as Component);
+ sourcesHandler.setSource(
+ range(0, 1)
+ .map((n) => `line: ${n}`)
+ .join('\n'),
+ );
+ renderProjectIssuesApp(
+ `project/issues?issueStatuses=CONFIRMED&open=${ISSUE_2}&id=myproject`,
+ {},
+ mockLoggedInUser(),
+ [Feature.BranchSupport, Feature.FixSuggestions],
+ );
+
+ expect(await ui.issueCodeTab.find(undefined, { timeout: 10_000 })).toBeInTheDocument();
+ expect(ui.getFixSuggestion.query()).not.toBeInTheDocument();
+ expect(ui.issueCodeFixTab.query()).not.toBeInTheDocument();
+ });
+
it('should not be able to trigger a fix when issue is not eligible', async () => {
renderProjectIssuesApp(
`project/issues?issueStatuses=CONFIRMED&open=${ISSUE_1101}&id=myproject`,
@@ -143,7 +170,10 @@ describe('issue app', () => {
});
it('should show error when no fix is available', async () => {
- settingsHandler.set('sonar.ai.suggestions.enabled', 'true');
+ componentsHandler.registerComponent({
+ ...mockComponent({ key: 'myproject' }),
+ isAiCodeFixEnabled: true,
+ } as Component);
const user = userEvent.setup();
renderProjectIssuesApp(
`project/issues?issueStatuses=CONFIRMED&open=${ISSUE_101}&id=myproject`,
diff --git a/server/sonar-web/src/main/js/queries/fix-suggestions.tsx b/server/sonar-web/src/main/js/queries/fix-suggestions.tsx
index 8faafa97a5a..fc70ff12e2c 100644
--- a/server/sonar-web/src/main/js/queries/fix-suggestions.tsx
+++ b/server/sonar-web/src/main/js/queries/fix-suggestions.tsx
@@ -31,10 +31,9 @@ import {
import { useAvailableFeatures } from '../app/components/available-features/withAvailableFeatures';
import { CurrentUserContext } from '../app/components/current-user/CurrentUserContext';
import { Feature } from '../types/features';
-import { SettingsKey } from '../types/settings';
import { Issue } from '../types/types';
import { isLoggedIn } from '../types/users';
-import { useGetValueQuery } from './settings';
+import { useComponentDataQuery } from './component';
import { useRawSourceQuery } from './sources';
const UNKNOWN = -1;
@@ -151,14 +150,9 @@ export function useGetFixSuggestionsIssuesQuery(issue: Issue) {
const { currentUser } = useContext(CurrentUserContext);
const { hasFeature } = useAvailableFeatures();
- const { data: codeFixSetting } = useGetValueQuery(
- {
- key: SettingsKey.CodeSuggestion,
- },
- { staleTime: Infinity },
- );
-
- const isCodeFixEnabled = codeFixSetting?.value === 'true';
+ const isCodeFixEnabled =
+ useComponentDataQuery({ component: issue.project }).data?.component?.isAiCodeFixEnabled ||
+ false;
return useQuery({
queryKey: ['code-suggestions', 'issues', 'details', issue.key],