From b3aeb358e883989c9f4f20bd0419631d2c8cefcc Mon Sep 17 00:00:00 2001 From: Revanshu Paliwal Date: Wed, 18 Sep 2024 14:56:38 +0200 Subject: [PATCH] SONAR-23064 Disable the projects row which has disabled field as true --- .../js/api/mocks/QualityGatesServiceMock.ts | 10 +++-- .../src/main/js/api/quality-gates.ts | 2 +- .../quality-gates/components/Projects.tsx | 9 ++++ .../components/__tests__/QualityGate-it.tsx | 42 +++++++++++++++---- .../resources/org/sonar/l10n/core.properties | 1 + 5 files changed, 52 insertions(+), 12 deletions(-) diff --git a/server/sonar-web/src/main/js/api/mocks/QualityGatesServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/QualityGatesServiceMock.ts index d82a794672c..50db7db263f 100644 --- a/server/sonar-web/src/main/js/api/mocks/QualityGatesServiceMock.ts +++ b/server/sonar-web/src/main/js/api/mocks/QualityGatesServiceMock.ts @@ -257,10 +257,12 @@ export class QualityGatesServiceMock { this.list = cloneDeep(this.readOnlyList); this.projects = [ - { key: 'test1', name: 'test1', selected: false }, - { key: 'test2', name: 'test2', selected: false }, - { key: 'test3', name: 'test3', selected: true }, - { key: 'test4', name: 'test4', selected: true }, + { key: 'test1', name: 'test1', selected: false, isAiCodeAssured: false }, + { key: 'test2', name: 'test2', selected: false, isAiCodeAssured: false }, + { key: 'test3', name: 'test3', selected: true, isAiCodeAssured: false }, + { key: 'test4', name: 'test4', selected: true, isAiCodeAssured: false }, + { key: 'test5', name: 'test5', selected: true, isAiCodeAssured: true }, + { key: 'test6', name: 'test6', selected: false, isAiCodeAssured: true }, ]; this.getGateForProjectGateName = 'SonarSource way'; diff --git a/server/sonar-web/src/main/js/api/quality-gates.ts b/server/sonar-web/src/main/js/api/quality-gates.ts index a7bad22b443..257e45f64f2 100644 --- a/server/sonar-web/src/main/js/api/quality-gates.ts +++ b/server/sonar-web/src/main/js/api/quality-gates.ts @@ -100,7 +100,7 @@ export function searchProjects(data: { selected?: string; }): Promise<{ paging: Paging; - results: Array<{ key: string; name: string; selected: boolean }>; + results: Array<{ isAiCodeAssured: boolean; key: string; name: string; selected: boolean }>; }> { return getJSON('/api/qualitygates/search', data).catch(throwGlobalError); } diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/Projects.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/Projects.tsx index 3eaf42adf06..095ddb2f006 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/Projects.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/Projects.tsx @@ -47,6 +47,7 @@ interface State { // exported for testing export interface Project { + isAiCodeAssured: boolean; key: string; name: string; selected: boolean; @@ -140,6 +141,11 @@ export default class Projects extends React.PureComponent { {project.name}
{project.key} + {project.isAiCodeAssured && ( +

+ {translate('quality_gates.projects.ai_assured_message')} +

+ )} )} @@ -158,6 +164,9 @@ export default class Projects extends React.PureComponent { return ( project.key)} + disabledElements={this.state.projects + .filter((project) => project.isAiCodeAssured) + .map((project) => project.key)} elementsTotalCount={this.state.projectsTotalCount} labelAll={translate('quality_gates.projects.all')} labelSelected={translate('quality_gates.projects.with')} diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/QualityGate-it.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/QualityGate-it.tsx index 132ec6528cf..61c35ff8e3e 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/QualityGate-it.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/QualityGate-it.tsx @@ -653,15 +653,15 @@ describe('The Project section', () => { await user.click(notDefaultQualityGate); // by default it shows "selected" values - expect(await screen.findAllByRole('checkbox')).toHaveLength(2); + expect(await screen.findAllByRole('checkbox')).toHaveLength(3); // change tabs to show deselected projects await user.click(screen.getByRole('radio', { name: 'quality_gates.projects.without' })); - expect(screen.getAllByRole('checkbox')).toHaveLength(2); + expect(screen.getAllByRole('checkbox')).toHaveLength(3); // change tabs to show all projects await user.click(screen.getByRole('radio', { name: 'quality_gates.projects.all' })); - expect(screen.getAllByRole('checkbox')).toHaveLength(4); + expect(screen.getAllByRole('checkbox')).toHaveLength(6); }); it('should handle select and deselect correctly', async () => { @@ -673,7 +673,7 @@ describe('The Project section', () => { await user.click(notDefaultQualityGate); - expect(await screen.findAllByRole('checkbox')).toHaveLength(2); + expect(await screen.findAllByRole('checkbox')).toHaveLength(3); const checkedProjects = screen.getAllByRole('checkbox')[0]; await user.click(checkedProjects); const reloadButton = screen.getByRole('button', { name: 'reload' }); @@ -682,17 +682,45 @@ describe('The Project section', () => { // FP // eslint-disable-next-line jest-dom/prefer-in-document - expect(screen.getAllByRole('checkbox')).toHaveLength(1); + expect(screen.getAllByRole('checkbox')).toHaveLength(2); + + // projects with disabled as true are not selectable + // last checked project in mock service is disabled + const disabledCheckedProjects = screen.getByRole('checkbox', { + name: 'test5 test5 quality_gates.projects.ai_assured_message', + }); + expect(disabledCheckedProjects).toBeDisabled(); // change tabs to show deselected projects await user.click(screen.getByRole('radio', { name: 'quality_gates.projects.without' })); const uncheckedProjects = screen.getAllByRole('checkbox')[0]; - expect(screen.getAllByRole('checkbox')).toHaveLength(3); + expect(screen.getAllByRole('checkbox')).toHaveLength(4); await user.click(uncheckedProjects); expect(reloadButton).toBeInTheDocument(); await user.click(reloadButton); - expect(screen.getAllByRole('checkbox')).toHaveLength(2); + expect(screen.getAllByRole('checkbox')).toHaveLength(3); + + // projects with disabled as true are not selectable + // last unchecked project in mock service is disabled + const disabledUncheckedProjects = screen.getByRole('checkbox', { + name: 'test6 test6 quality_gates.projects.ai_assured_message', + }); + expect(disabledUncheckedProjects).toBeDisabled(); + + // change tabs to show all projects + await user.click(screen.getByRole('radio', { name: 'quality_gates.projects.all' })); + expect(screen.getAllByRole('checkbox')).toHaveLength(6); + + const disabledCheckedProjectsAll = screen.getByRole('checkbox', { + name: 'test5 test5 quality_gates.projects.ai_assured_message', + }); + expect(disabledCheckedProjectsAll).toBeDisabled(); + + const disabledUncheckedProjectsAll = screen.getByRole('checkbox', { + name: 'test6 test6 quality_gates.projects.ai_assured_message', + }); + expect(disabledUncheckedProjectsAll).toBeDisabled(); }); it('should handle the search of projects', async () => { diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index 14d8068bdb2..365dd5d9c02 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -2385,6 +2385,7 @@ quality_gates.projects.noResults=No Projects quality_gates.projects.select_hint=Click to associate this project with the quality gate quality_gates.projects.deselect_hint=Click to remove association between this project and the quality gate quality_gates.projects.cannot_associate_projects_no_conditions=You must configure at least 1 condition before you can assign projects to this quality gate. +quality_gates.projects.ai_assured_message=This project contains AI-generated code. It must use Sonar way. quality_gates.operator.LT=is less than quality_gates.operator.inverted.LT=greather than or equal quality_gates.operator.GT=is greater than -- 2.39.5