From: Revanshu Paliwal Date: Tue, 10 May 2022 10:02:41 +0000 (+0200) Subject: SONAR-16316 New place for regulatory report X-Git-Tag: 9.5.0.56709~96 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=c1a02f45496281a6a6ad7ab937531cc6004d9ca5;p=sonarqube.git SONAR-16316 New place for regulatory report --- diff --git a/server/sonar-web/src/main/js/api/mocks/BranchesServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/BranchesServiceMock.ts new file mode 100644 index 00000000000..d833cb22e70 --- /dev/null +++ b/server/sonar-web/src/main/js/api/mocks/BranchesServiceMock.ts @@ -0,0 +1,45 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 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 { cloneDeep } from 'lodash'; +import { mockBranch } from '../../helpers/mocks/branch-like'; +import { BranchLike } from '../../types/branch-like'; +import { getBranches } from '../branches'; + +export default class BranchesServiceMock { + branchLikes: BranchLike[]; + defaultBranchLikes: BranchLike[] = [ + mockBranch({ isMain: true, name: 'master' }), + mockBranch({ excludedFromPurge: false, name: 'delete-branch' }), + mockBranch({ name: 'normal-branch' }) + ]; + + constructor() { + this.branchLikes = cloneDeep(this.defaultBranchLikes); + (getBranches as jest.Mock).mockImplementation(this.getBranchesHandler); + } + + getBranchesHandler = () => { + return Promise.resolve(this.branchLikes); + }; + + resetBranches = () => { + this.branchLikes = cloneDeep(this.defaultBranchLikes); + }; +} diff --git a/server/sonar-web/src/main/js/app/components/nav/component/Menu.tsx b/server/sonar-web/src/main/js/app/components/nav/component/Menu.tsx index a3e13786bfd..7b33626b62a 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/Menu.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/Menu.tsx @@ -329,8 +329,7 @@ export class Menu extends React.PureComponent { this.renderBackgroundTasksLink(query), this.renderUpdateKeyLink(query), this.renderWebhooksLink(query, isProject), - this.renderDeletionLink(query), - this.renderRegulatoryReport(query) + this.renderDeletionLink(query) ]; }; @@ -542,19 +541,6 @@ export class Menu extends React.PureComponent { ); }; - renderRegulatoryReport = (query: Query) => { - if (!this.props.appState.regulatoryReportFeatureEnabled) { - return null; - } - return ( -
  • - - {translate('regulatory_report.page')} - -
  • - ); - }; - renderExtension = ({ key, name }: Extension, isAdmin: boolean, baseQuery: Query) => { const pathname = isAdmin ? `/project/admin/extension/${key}` : `/project/extension/${key}`; const query = { ...baseQuery, qualifier: this.props.component.qualifier }; diff --git a/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/ProjectInformation.tsx b/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/ProjectInformation.tsx index 952b65e7d1e..3010c8f5564 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/ProjectInformation.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/ProjectInformation.tsx @@ -97,6 +97,7 @@ export class ProjectInformation extends React.PureComponent { canConfigureNotifications={canConfigureNotifications} canUseBadges={canUseBadges} component={component} + branchLike={branchLike} measures={measures} onComponentChange={this.props.onComponentChange} onPageChange={this.setPage} diff --git a/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/ProjectInformationRenderer.tsx b/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/ProjectInformationRenderer.tsx index 547e84bf445..8c50d12e51c 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/ProjectInformationRenderer.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/ProjectInformationRenderer.tsx @@ -18,6 +18,8 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; +import { ButtonLink } from '../../../../../components/controls/buttons'; +import ModalButton from '../../../../../components/controls/ModalButton'; import PrivacyBadgeContainer from '../../../../../components/common/PrivacyBadgeContainer'; import { translate } from '../../../../../helpers/l10n'; import { ComponentQualifier } from '../../../../../types/component'; @@ -30,18 +32,31 @@ import MetaQualityProfiles from './meta/MetaQualityProfiles'; import MetaSize from './meta/MetaSize'; import MetaTags from './meta/MetaTags'; import { ProjectInformationPages } from './ProjectInformationPages'; +import RegulatoryReportModal from './projectRegulatoryReport/RegulatoryReportModal'; +import withAppStateContext from '../../../app-state/withAppStateContext'; +import { AppState } from '../../../../../types/appstate'; +import { BranchLike } from '../../../../../types/branch-like'; export interface ProjectInformationRendererProps { + appState: AppState; canConfigureNotifications: boolean; canUseBadges: boolean; component: Component; + branchLike?: BranchLike; measures?: Measure[]; onComponentChange: (changes: {}) => void; onPageChange: (page: ProjectInformationPages) => void; } export function ProjectInformationRenderer(props: ProjectInformationRendererProps) { - const { canConfigureNotifications, canUseBadges, component, measures = [] } = props; + const { + canConfigureNotifications, + canUseBadges, + component, + measures = [], + appState, + branchLike + } = props; const isApp = component.qualifier === ComponentQualifier.Application; @@ -113,9 +128,26 @@ export function ProjectInformationRenderer(props: ProjectInformationRendererProp to={ProjectInformationPages.notifications} /> )} + {component.qualifier === ComponentQualifier.Project && + appState.regulatoryReportFeatureEnabled && ( +
    + ( + + )}> + {({ onClick }) => ( + {translate('regulatory_report.page')} + )} + +
    + )} ); } -export default React.memo(ProjectInformationRenderer); +export default withAppStateContext(React.memo(ProjectInformationRenderer)); diff --git a/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/__tests__/ProjectInformationRenderer-test.tsx b/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/__tests__/ProjectInformationRenderer-test.tsx index 42ca7b25e95..33a4b340615 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/__tests__/ProjectInformationRenderer-test.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/__tests__/ProjectInformationRenderer-test.tsx @@ -19,6 +19,7 @@ */ import { shallow } from 'enzyme'; import * as React from 'react'; +import { mockAppState } from '../../../../../../helpers/testMocks'; import { mockComponent } from '../../../../../../helpers/mocks/component'; import { ProjectInformationRenderer, @@ -56,9 +57,22 @@ it('should handle missing quality profiles and quality gates', () => { ).toMatchSnapshot(); }); +it('should render app correctly when regulatoryReportFeatureEnabled is false', () => { + expect( + shallowRender({ + appState: mockAppState({ + regulatoryReportFeatureEnabled: false + }) + }) + ).toMatchSnapshot(); +}); + function shallowRender(props: Partial = {}) { return shallow( - - - - +
    + + + +
    `; @@ -246,6 +255,15 @@ exports[`should render a private project correctly 1`] = ` onPageChange={[MockFunction]} to={2} /> +
    + + + +
    `; @@ -351,6 +369,164 @@ exports[`should render an app correctly: default 1`] = ` `; +exports[`should render app correctly when regulatoryReportFeatureEnabled is false 1`] = ` + +
    +

    + project.info.title +

    +
    +
    +
    +
    +

    + project.info.description +

    + +
    + +
    +
    + +
    +
    + + +
    + +
    + +
    + + +
    +
    +`; + exports[`should render correctly: default 1`] = `
    @@ -505,6 +681,15 @@ exports[`should render correctly: default 1`] = ` onPageChange={[MockFunction]} to={2} /> +
    + + + +
    `; @@ -658,6 +843,15 @@ exports[`should render correctly: no badges 1`] = ` onPageChange={[MockFunction]} to={2} /> +
    + + + +
    `; @@ -806,6 +1000,15 @@ exports[`should render correctly: no badges, no notifications 1`] = ` qualifier="TRK" /> +
    + + + +
    `; @@ -959,6 +1162,15 @@ exports[`should render correctly: with notifications 1`] = ` onPageChange={[MockFunction]} to={1} /> +
    + + + +
    `; @@ -1118,6 +1330,15 @@ exports[`should render with description 1`] = ` onPageChange={[MockFunction]} to={2} /> +
    + + + +
    `; diff --git a/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/projectRegulatoryReport/RegulatoryReport.tsx b/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/projectRegulatoryReport/RegulatoryReport.tsx new file mode 100644 index 00000000000..aebf360d834 --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/projectRegulatoryReport/RegulatoryReport.tsx @@ -0,0 +1,153 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 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 classNames from 'classnames'; +import * as React from 'react'; +import { BranchLike } from '../../../../../../types/branch-like'; +import { getBranches } from '../../../../../../api/branches'; +import { getRegulatoryReportUrl } from '../../../../../../api/regulatory-report'; +import { ButtonLink } from '../../../../../../components/controls/buttons'; +import Select, { BasicSelectOption } from '../../../../../../components/controls/Select'; +import { + getBranchLikeDisplayName, + isBranch, + isMainBranch +} from '../../../../../../helpers/branch-like'; +import { translate } from '../../../../../../helpers/l10n'; +import { Component } from '../../../../../../types/types'; +import { orderBy } from 'lodash'; + +interface Props { + component: Pick; + branchLike?: BranchLike; + onClose: () => void; +} + +interface State { + downloadStarted: boolean; + selectedBranch: string; + branchLikesOptions: BasicSelectOption[]; +} + +export default class RegulatoryReport extends React.PureComponent { + constructor(props: Props) { + super(props); + this.state = { + downloadStarted: false, + selectedBranch: '', + branchLikesOptions: [] + }; + } + + componentDidMount() { + const { component, branchLike } = this.props; + getBranches(component.key) + .then(data => { + const mainBranch = data.find(isMainBranch); + const otherBranchSorted = orderBy( + data.filter(isBranch).filter(b => !isMainBranch(b)), + b => b.name + ); + const sortedBranch = mainBranch ? [mainBranch, ...otherBranchSorted] : otherBranchSorted; + const options = sortedBranch + .filter(br => br.excludedFromPurge) + .map(br => { + return { + value: getBranchLikeDisplayName(br), + label: getBranchLikeDisplayName(br) + }; + }); + + let selectedBranch = ''; + if (branchLike && isBranch(branchLike) && branchLike.excludedFromPurge) { + selectedBranch = getBranchLikeDisplayName(branchLike); + } else if (mainBranch) { + selectedBranch = getBranchLikeDisplayName(mainBranch); + } + this.setState({ selectedBranch, branchLikesOptions: options }); + }) + .catch(() => { + this.setState({ branchLikesOptions: [] }); + }); + } + + onBranchSelect = (newOption: BasicSelectOption) => { + this.setState({ selectedBranch: newOption.value, downloadStarted: false }); + }; + + render() { + const { component, onClose } = this.props; + const { downloadStarted, selectedBranch, branchLikesOptions } = this.state; + + return ( + <> +
    +

    {translate('regulatory_report.page')}

    +
    +
    +

    {translate('regulatory_report.description1')}

    +
    +
      +
    • {translate('regulatory_report.bullet_point1')}
    • +
    • {translate('regulatory_report.bullet_point2')}
    • +
    • {translate('regulatory_report.bullet_point3')}
    • +
    +
    +

    {translate('regulatory_report.description2')}

    +
    + +