diff options
author | David Cho-Lerat <david.cho-lerat@sonarsource.com> | 2024-01-31 14:49:53 +0100 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2024-02-08 20:02:46 +0000 |
commit | b1a7fcdccc111af237b2e0ce206df150a12ed3c4 (patch) | |
tree | c82ccd9b8a3c4492f57e6cd17859d9bf4ba2ade2 /server/sonar-web/src/main/js/apps/projectNewCode | |
parent | 9514512f38767dc9c09e0346ff6a9580d07be83a (diff) | |
download | sonarqube-b1a7fcdccc111af237b2e0ce206df150a12ed3c4.tar.gz sonarqube-b1a7fcdccc111af237b2e0ce206df150a12ed3c4.zip |
SONAR-20954 Improve project new code settings style
Diffstat (limited to 'server/sonar-web/src/main/js/apps/projectNewCode')
3 files changed, 40 insertions, 27 deletions
diff --git a/server/sonar-web/src/main/js/apps/projectNewCode/components/ProjectNewCodeDefinitionApp.tsx b/server/sonar-web/src/main/js/apps/projectNewCode/components/ProjectNewCodeDefinitionApp.tsx index 700a997d771..7f5dbca55af 100644 --- a/server/sonar-web/src/main/js/apps/projectNewCode/components/ProjectNewCodeDefinitionApp.tsx +++ b/server/sonar-web/src/main/js/apps/projectNewCode/components/ProjectNewCodeDefinitionApp.tsx @@ -17,6 +17,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + import { HeadingDark, LargeCenteredLayout, PageContentFontWrapper, Spinner } from 'design-system'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { Helmet } from 'react-helmet-async'; @@ -61,6 +62,7 @@ function ProjectNewCodeDefinitionApp(props: Readonly<ProjectNewCodeDefinitionApp const [numberOfDays, setNumberOfDays] = useState(getNumberOfDaysDefaultValue()); const [referenceBranch, setReferenceBranch] = useState<string | undefined>(undefined); const [specificAnalysis, setSpecificAnalysis] = useState<string | undefined>(undefined); + const [selectedNewCodeDefinitionType, setSelectedNewCodeDefinitionType] = useState<NewCodeDefinitionType>(DEFAULT_NEW_CODE_DEFINITION_TYPE); @@ -68,6 +70,7 @@ function ProjectNewCodeDefinitionApp(props: Readonly<ProjectNewCodeDefinitionApp data: globalNewCodeDefinition = { type: DEFAULT_NEW_CODE_DEFINITION_TYPE }, isLoading: isGlobalNCDLoading, } = useNewCodeDefinitionQuery(); + const { data: projectNewCodeDefinition, isLoading: isProjectNCDLoading } = useNewCodeDefinitionQuery({ branchName: hasFeature(Feature.BranchSupport) ? undefined : branchLike?.name, @@ -78,10 +81,12 @@ function ProjectNewCodeDefinitionApp(props: Readonly<ProjectNewCodeDefinitionApp const branchList = useMemo(() => { return sortBranches(branchLikes.filter(isBranch)); }, [branchLikes]); + const isFormTouched = useMemo(() => { if (isSpecificNewCodeDefinition === undefined) { return false; } + if (isSpecificNewCodeDefinition !== !projectNewCodeDefinition?.inherited) { return true; } @@ -97,10 +102,13 @@ function ProjectNewCodeDefinitionApp(props: Readonly<ProjectNewCodeDefinitionApp switch (selectedNewCodeDefinitionType) { case NewCodeDefinitionType.NumberOfDays: return numberOfDays !== String(projectNewCodeDefinition?.value); + case NewCodeDefinitionType.ReferenceBranch: return referenceBranch !== projectNewCodeDefinition?.value; + case NewCodeDefinitionType.SpecificAnalysis: return specificAnalysis !== projectNewCodeDefinition?.value; + default: return false; } @@ -121,15 +129,19 @@ function ProjectNewCodeDefinitionApp(props: Readonly<ProjectNewCodeDefinitionApp setIsSpecificNewCodeDefinition( projectNewCodeDefinition === undefined ? undefined : !projectNewCodeDefinition.inherited, ); + setSelectedNewCodeDefinitionType( projectNewCodeDefinition?.type ?? DEFAULT_NEW_CODE_DEFINITION_TYPE, ); + setNumberOfDays(getNumberOfDaysDefaultValue(globalNewCodeDefinition, projectNewCodeDefinition)); + setReferenceBranch( projectNewCodeDefinition?.type === NewCodeDefinitionType.ReferenceBranch ? projectNewCodeDefinition.value : defaultReferenceBranch, ); + setSpecificAnalysis( projectNewCodeDefinition?.type === NewCodeDefinitionType.SpecificAnalysis ? projectNewCodeDefinition.value @@ -180,19 +192,16 @@ function ProjectNewCodeDefinitionApp(props: Readonly<ProjectNewCodeDefinitionApp return ( <LargeCenteredLayout id="new-code-rules-page"> <Suggestions suggestions="project_baseline" /> + <Helmet defer={false} title={translate('project_baseline.page')} /> + <PageContentFontWrapper className="sw-my-8 sw-body-sm"> <AppHeader canAdmin={!!appState.canAdmin} /> + <Spinner loading={isLoading} /> {!isLoading && ( <div className="it__project-baseline"> - {branchSupportEnabled && ( - <HeadingDark as="h3" className="sw-mt-4"> - {translate('project_baseline.default_setting')} - </HeadingDark> - )} - {globalNewCodeDefinition && isSpecificNewCodeDefinition !== undefined && ( <ProjectNewCodeDefinitionSelector analysis={specificAnalysis} @@ -225,6 +234,7 @@ function ProjectNewCodeDefinitionApp(props: Readonly<ProjectNewCodeDefinitionApp <HeadingDark as="h3" className="sw-mb-4"> {translate('project_baseline.configure_branches')} </HeadingDark> + <BranchList branchList={branchList} component={component} diff --git a/server/sonar-web/src/main/js/apps/projectNewCode/components/ProjectNewCodeDefinitionSelector.tsx b/server/sonar-web/src/main/js/apps/projectNewCode/components/ProjectNewCodeDefinitionSelector.tsx index a3bbf303f1b..ced1729d12d 100644 --- a/server/sonar-web/src/main/js/apps/projectNewCode/components/ProjectNewCodeDefinitionSelector.tsx +++ b/server/sonar-web/src/main/js/apps/projectNewCode/components/ProjectNewCodeDefinitionSelector.tsx @@ -17,6 +17,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + import { ButtonPrimary, ButtonSecondary, FlagMessage, RadioButton, Spinner } from 'design-system'; import { noop } from 'lodash'; import * as React from 'react'; @@ -34,26 +35,26 @@ import NewCodeDefinitionSettingReferenceBranch from './NewCodeDefinitionSettingR export interface ProjectBaselineSelectorProps { analysis?: string; branch?: Branch; - branchList: Branch[]; branchesEnabled?: boolean; + branchList: Branch[]; component: string; - newCodeDefinitionType?: NewCodeDefinitionType; - newCodeDefinitionValue?: string; - previousNonCompliantValue?: string; - projectNcdUpdatedAt?: number; days: string; globalNewCodeDefinition: NewCodeDefinition; isChanged: boolean; + newCodeDefinitionType?: NewCodeDefinitionType; + newCodeDefinitionValue?: string; onCancel: () => void; onSelectDays: (value: string) => void; onSelectReferenceBranch: (value: string) => void; onSelectSetting: (value: NewCodeDefinitionType) => void; onSubmit: (e: React.SyntheticEvent<HTMLFormElement>) => void; onToggleSpecificSetting: (selection: boolean) => void; + overrideGlobalNewCodeDefinition: boolean; + previousNonCompliantValue?: string; + projectNcdUpdatedAt?: number; referenceBranch?: string; saving: boolean; selectedNewCodeDefinitionType?: NewCodeDefinitionType; - overrideGlobalNewCodeDefinition: boolean; } function branchToOption(b: Branch) { @@ -66,17 +67,17 @@ export default function ProjectNewCodeDefinitionSelector( const { analysis, branch, - branchList, branchesEnabled, + branchList, component, - newCodeDefinitionType, - newCodeDefinitionValue, - previousNonCompliantValue, - projectNcdUpdatedAt, days, globalNewCodeDefinition, isChanged, + newCodeDefinitionType, + newCodeDefinitionValue, overrideGlobalNewCodeDefinition, + previousNonCompliantValue, + projectNcdUpdatedAt, referenceBranch, saving, selectedNewCodeDefinitionType, @@ -105,7 +106,7 @@ export default function ProjectNewCodeDefinitionSelector( <span>{translate('project_baseline.global_setting')}</span> </RadioButton> - <div className="sw-ml-4"> + <div className="sw-ml-6"> <GlobalNewCodeDefinitionDescription globalNcd={globalNewCodeDefinition} /> </div> @@ -128,26 +129,28 @@ export default function ProjectNewCodeDefinitionSelector( selectedNewCodeDefinitionType === NewCodeDefinitionType.PreviousVersion } /> + <NewCodeDefinitionDaysOption - days={days} currentDaysValue={ newCodeDefinitionType === NewCodeDefinitionType.NumberOfDays ? newCodeDefinitionValue : undefined } - previousNonCompliantValue={previousNonCompliantValue} - updatedAt={projectNcdUpdatedAt} + days={days} disabled={!overrideGlobalNewCodeDefinition} isChanged={isChanged} isValid={isValid} onChangeDays={props.onSelectDays} onSelect={props.onSelectSetting} + previousNonCompliantValue={previousNonCompliantValue} selected={ overrideGlobalNewCodeDefinition && selectedNewCodeDefinitionType === NewCodeDefinitionType.NumberOfDays } settingLevel={NewCodeDefinitionLevels.Project} + updatedAt={projectNcdUpdatedAt} /> + {branchesEnabled && ( <NewCodeDefinitionSettingReferenceBranch branchList={branchList.map(branchToOption)} @@ -162,12 +165,13 @@ export default function ProjectNewCodeDefinitionSelector( settingLevel={NewCodeDefinitionLevels.Project} /> )} + {!branchesEnabled && newCodeDefinitionType === NewCodeDefinitionType.SpecificAnalysis && ( <NewCodeDefinitionSettingAnalysis - onSelect={noop} analysis={analysis ?? ''} branch={branch.name} component={component} + onSelect={noop} selected={ overrideGlobalNewCodeDefinition && selectedNewCodeDefinitionType === NewCodeDefinitionType.SpecificAnalysis @@ -175,16 +179,19 @@ export default function ProjectNewCodeDefinitionSelector( /> )} </div> + <div className="sw-mt-4"> {isChanged && ( <FlagMessage variant="info" className="sw-mb-4"> {translate('baseline.next_analysis_notice')} </FlagMessage> )} + <div className="sw-flex sw-items-center"> <ButtonPrimary type="submit" disabled={!isValid || !isChanged || saving}> {translate('save')} </ButtonPrimary> + <ButtonSecondary className="sw-ml-2" disabled={saving || !isChanged} @@ -192,6 +199,7 @@ export default function ProjectNewCodeDefinitionSelector( > {translate('cancel')} </ButtonSecondary> + <Spinner className="sw-ml-2" loading={saving} /> </div> </div> diff --git a/server/sonar-web/src/main/js/apps/projectNewCode/components/__tests__/ProjectNewCodeDefinitionApp-it.tsx b/server/sonar-web/src/main/js/apps/projectNewCode/components/__tests__/ProjectNewCodeDefinitionApp-it.tsx index 67ca5267991..f15b977a390 100644 --- a/server/sonar-web/src/main/js/apps/projectNewCode/components/__tests__/ProjectNewCodeDefinitionApp-it.tsx +++ b/server/sonar-web/src/main/js/apps/projectNewCode/components/__tests__/ProjectNewCodeDefinitionApp-it.tsx @@ -66,8 +66,6 @@ it('renders correctly without branch support feature', async () => { // User is not admin expect(ui.generalSettingsLink.query()).not.toBeInTheDocument(); - // Specific branch setting is not rendered without feature branch - expect(ui.branchListHeading.query()).not.toBeInTheDocument(); expect(ui.referenceBranchRadio.query()).not.toBeInTheDocument(); }); @@ -85,8 +83,6 @@ it('renders correctly with branch support feature', async () => { // User is admin expect(ui.generalSettingsLink.get()).toBeInTheDocument(); - // Specific branch setting is rendered with feature support branch - expect(ui.branchListHeading.get()).toBeInTheDocument(); expect(ui.referenceBranchRadio.get()).toBeInTheDocument(); }); @@ -381,7 +377,6 @@ function getPageObjects() { const ui = { pageHeading: byRole('heading', { name: 'project_baseline.page' }), branchTableHeading: byText('branch_list.branch'), - branchListHeading: byRole('heading', { name: 'project_baseline.default_setting' }), generalSettingsLink: byRole('link', { name: 'project_baseline.page.description2.link' }), generalSettingRadio: byRole('radio', { name: 'project_baseline.global_setting' }), specificSettingRadio: byRole('radio', { name: 'project_baseline.specific_setting' }), |