浏览代码

SONAR-16316 New place for regulatory report

tags/9.5.0.56709
Revanshu Paliwal 2 年前
父节点
当前提交
c1a02f4549
共有 13 个文件被更改,包括 543 次插入97 次删除
  1. 45
    0
      server/sonar-web/src/main/js/api/mocks/BranchesServiceMock.ts
  2. 1
    15
      server/sonar-web/src/main/js/app/components/nav/component/Menu.tsx
  3. 1
    0
      server/sonar-web/src/main/js/app/components/nav/component/projectInformation/ProjectInformation.tsx
  4. 34
    2
      server/sonar-web/src/main/js/app/components/nav/component/projectInformation/ProjectInformationRenderer.tsx
  5. 14
    0
      server/sonar-web/src/main/js/app/components/nav/component/projectInformation/__tests__/ProjectInformationRenderer-test.tsx
  6. 4
    4
      server/sonar-web/src/main/js/app/components/nav/component/projectInformation/__tests__/__snapshots__/ProjectInformation-test.tsx.snap
  7. 221
    0
      server/sonar-web/src/main/js/app/components/nav/component/projectInformation/__tests__/__snapshots__/ProjectInformationRenderer-test.tsx.snap
  8. 153
    0
      server/sonar-web/src/main/js/app/components/nav/component/projectInformation/projectRegulatoryReport/RegulatoryReport.tsx
  9. 45
    0
      server/sonar-web/src/main/js/app/components/nav/component/projectInformation/projectRegulatoryReport/RegulatoryReportModal.tsx
  10. 19
    2
      server/sonar-web/src/main/js/app/components/nav/component/projectInformation/projectRegulatoryReport/__tests__/RegulatoryReport-it.tsx
  11. 0
    6
      server/sonar-web/src/main/js/app/utils/startReactApp.tsx
  12. 0
    66
      server/sonar-web/src/main/js/apps/projectRegulatoryReport/RegulatoryReport.tsx
  13. 6
    2
      sonar-core/src/main/resources/org/sonar/l10n/core.properties

+ 45
- 0
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);
};
}

+ 1
- 15
server/sonar-web/src/main/js/app/components/nav/component/Menu.tsx 查看文件

@@ -329,8 +329,7 @@ export class Menu extends React.PureComponent<Props> {
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<Props> {
);
};

renderRegulatoryReport = (query: Query) => {
if (!this.props.appState.regulatoryReportFeatureEnabled) {
return null;
}
return (
<li key="project_regulatory_report">
<Link activeClassName="active" to={{ pathname: '/project/regulatory-report', query }}>
{translate('regulatory_report.page')}
</Link>
</li>
);
};

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 };

+ 1
- 0
server/sonar-web/src/main/js/app/components/nav/component/projectInformation/ProjectInformation.tsx 查看文件

@@ -97,6 +97,7 @@ export class ProjectInformation extends React.PureComponent<Props, State> {
canConfigureNotifications={canConfigureNotifications}
canUseBadges={canUseBadges}
component={component}
branchLike={branchLike}
measures={measures}
onComponentChange={this.props.onComponentChange}
onPageChange={this.setPage}

+ 34
- 2
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 && (
<div className="big-padded bordered-bottom">
<ModalButton
modal={({ onClose }) => (
<RegulatoryReportModal
component={component}
branchLike={branchLike}
onClose={onClose}
/>
)}>
{({ onClick }) => (
<ButtonLink onClick={onClick}>{translate('regulatory_report.page')}</ButtonLink>
)}
</ModalButton>
</div>
)}
</div>
</>
);
}

export default React.memo(ProjectInformationRenderer);
export default withAppStateContext(React.memo(ProjectInformationRenderer));

+ 14
- 0
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<ProjectInformationRendererProps> = {}) {
return shallow(
<ProjectInformationRenderer
appState={mockAppState({
regulatoryReportFeatureEnabled: true
})}
canConfigureNotifications={true}
canUseBadges={true}
component={mockComponent({ qualifier: 'TRK', visibility: 'public' })}

+ 4
- 4
server/sonar-web/src/main/js/app/components/nav/component/projectInformation/__tests__/__snapshots__/ProjectInformation-test.tsx.snap 查看文件

@@ -2,7 +2,7 @@

exports[`should render correctly: default 1`] = `
<Fragment>
<Memo(ProjectInformationRenderer)
<withAppStateContext(Component)
canConfigureNotifications={false}
canUseBadges={true}
component={
@@ -64,7 +64,7 @@ exports[`should render correctly: default 1`] = `

exports[`should render correctly: logged in user 1`] = `
<Fragment>
<Memo(ProjectInformationRenderer)
<withAppStateContext(Component)
canConfigureNotifications={true}
canUseBadges={true}
component={
@@ -155,7 +155,7 @@ exports[`should render correctly: logged in user 1`] = `

exports[`should render correctly: measures loaded 1`] = `
<Fragment>
<Memo(ProjectInformationRenderer)
<withAppStateContext(Component)
canConfigureNotifications={false}
canUseBadges={true}
component={
@@ -231,7 +231,7 @@ exports[`should render correctly: measures loaded 1`] = `

exports[`should render correctly: private 1`] = `
<Fragment>
<Memo(ProjectInformationRenderer)
<withAppStateContext(Component)
canConfigureNotifications={false}
canUseBadges={true}
component={

+ 221
- 0
server/sonar-web/src/main/js/app/components/nav/component/projectInformation/__tests__/__snapshots__/ProjectInformationRenderer-test.tsx.snap 查看文件

@@ -88,6 +88,15 @@ exports[`should handle missing quality profiles and quality gates 1`] = `
onPageChange={[MockFunction]}
to={2}
/>
<div
className="big-padded bordered-bottom"
>
<ModalButton
modal={[Function]}
>
<Component />
</ModalButton>
</div>
</div>
</Fragment>
`;
@@ -246,6 +255,15 @@ exports[`should render a private project correctly 1`] = `
onPageChange={[MockFunction]}
to={2}
/>
<div
className="big-padded bordered-bottom"
>
<ModalButton
modal={[Function]}
>
<Component />
</ModalButton>
</div>
</div>
</Fragment>
`;
@@ -351,6 +369,164 @@ exports[`should render an app correctly: default 1`] = `
</Fragment>
`;

exports[`should render app correctly when regulatoryReportFeatureEnabled is false 1`] = `
<Fragment>
<div>
<h2
className="big-padded bordered-bottom"
>
project.info.title
</h2>
</div>
<div
className="overflow-y-auto"
>
<div
className="big-padded bordered-bottom"
>
<div
className="display-flex-center"
>
<h3
className="spacer-right"
>
project.info.description
</h3>
<PrivacyBadgeContainer
qualifier="TRK"
visibility="public"
/>
</div>
<MetaTags
component={
Object {
"breadcrumbs": Array [],
"key": "my-project",
"name": "MyProject",
"qualifier": "TRK",
"qualityGate": Object {
"isDefault": true,
"key": "30",
"name": "Sonar way",
},
"qualityProfiles": Array [
Object {
"deleted": false,
"key": "my-qp",
"language": "ts",
"name": "Sonar way",
},
],
"tags": Array [],
"visibility": "public",
}
}
onComponentChange={[MockFunction]}
/>
</div>
<div
className="big-padded bordered-bottom it__project-loc-value"
>
<MetaSize
component={
Object {
"breadcrumbs": Array [],
"key": "my-project",
"name": "MyProject",
"qualifier": "TRK",
"qualityGate": Object {
"isDefault": true,
"key": "30",
"name": "Sonar way",
},
"qualityProfiles": Array [
Object {
"deleted": false,
"key": "my-qp",
"language": "ts",
"name": "Sonar way",
},
],
"tags": Array [],
"visibility": "public",
}
}
measures={Array []}
/>
</div>
<div
className="big-padded bordered-bottom"
>
<MetaQualityGate
qualityGate={
Object {
"isDefault": true,
"key": "30",
"name": "Sonar way",
}
}
/>
<withLanguagesContext(MetaQualityProfiles)
headerClassName="big-spacer-top"
profiles={
Array [
Object {
"deleted": false,
"key": "my-qp",
"language": "ts",
"name": "Sonar way",
},
]
}
/>
</div>
<MetaLinks
component={
Object {
"breadcrumbs": Array [],
"key": "my-project",
"name": "MyProject",
"qualifier": "TRK",
"qualityGate": Object {
"isDefault": true,
"key": "30",
"name": "Sonar way",
},
"qualityProfiles": Array [
Object {
"deleted": false,
"key": "my-qp",
"language": "ts",
"name": "Sonar way",
},
],
"tags": Array [],
"visibility": "public",
}
}
/>
<div
className="big-padded bordered-bottom"
>
<MetaKey
componentKey="my-project"
qualifier="TRK"
/>
</div>
<Memo(DrawerLink)
label="overview.badges.get_badge.TRK"
onPageChange={[MockFunction]}
to={1}
/>
<Memo(DrawerLink)
label="project.info.to_notifications"
onPageChange={[MockFunction]}
to={2}
/>
</div>
</Fragment>
`;

exports[`should render correctly: default 1`] = `
<Fragment>
<div>
@@ -505,6 +681,15 @@ exports[`should render correctly: default 1`] = `
onPageChange={[MockFunction]}
to={2}
/>
<div
className="big-padded bordered-bottom"
>
<ModalButton
modal={[Function]}
>
<Component />
</ModalButton>
</div>
</div>
</Fragment>
`;
@@ -658,6 +843,15 @@ exports[`should render correctly: no badges 1`] = `
onPageChange={[MockFunction]}
to={2}
/>
<div
className="big-padded bordered-bottom"
>
<ModalButton
modal={[Function]}
>
<Component />
</ModalButton>
</div>
</div>
</Fragment>
`;
@@ -806,6 +1000,15 @@ exports[`should render correctly: no badges, no notifications 1`] = `
qualifier="TRK"
/>
</div>
<div
className="big-padded bordered-bottom"
>
<ModalButton
modal={[Function]}
>
<Component />
</ModalButton>
</div>
</div>
</Fragment>
`;
@@ -959,6 +1162,15 @@ exports[`should render correctly: with notifications 1`] = `
onPageChange={[MockFunction]}
to={1}
/>
<div
className="big-padded bordered-bottom"
>
<ModalButton
modal={[Function]}
>
<Component />
</ModalButton>
</div>
</div>
</Fragment>
`;
@@ -1118,6 +1330,15 @@ exports[`should render with description 1`] = `
onPageChange={[MockFunction]}
to={2}
/>
<div
className="big-padded bordered-bottom"
>
<ModalButton
modal={[Function]}
>
<Component />
</ModalButton>
</div>
</div>
</Fragment>
`;

+ 153
- 0
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<Component, 'key' | 'name'>;
branchLike?: BranchLike;
onClose: () => void;
}

interface State {
downloadStarted: boolean;
selectedBranch: string;
branchLikesOptions: BasicSelectOption[];
}

export default class RegulatoryReport extends React.PureComponent<Props, State> {
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 (
<>
<div className="modal-head">
<h2>{translate('regulatory_report.page')}</h2>
</div>
<div className="modal-body">
<p>{translate('regulatory_report.description1')}</p>
<div className="markdown">
<ul>
<li>{translate('regulatory_report.bullet_point1')}</li>
<li>{translate('regulatory_report.bullet_point2')}</li>
<li>{translate('regulatory_report.bullet_point3')}</li>
</ul>
</div>
<p>{translate('regulatory_report.description2')}</p>
<div className="modal-field big-spacer-top">
<label htmlFor="regulatory-report-branch-select">
{translate('regulatory_page.select_branch')}
</label>
<Select
className="width-100"
inputId="regulatory-report-branch-select"
id="regulatory-report-branch-select-input"
onChange={this.onBranchSelect}
options={branchLikesOptions}
value={branchLikesOptions.find(o => o.value === selectedBranch)}
/>
</div>
<div className="modal-field big-spacer-top">
{downloadStarted && (
<div>
<p>{translate('regulatory_page.download_start.sentence')}</p>
</div>
)}
</div>
</div>
<div className="modal-foot">
<a
className={classNames('button button-primary big-spacer-right', {
disabled: downloadStarted
})}
download={[component.name, selectedBranch, 'PDF Report.zip']
.filter(s => !!s)
.join(' - ')}
onClick={() => this.setState({ downloadStarted: true })}
href={getRegulatoryReportUrl(component.key, selectedBranch)}
target="_blank"
rel="noopener noreferrer">
{translate('download_verb')}
</a>
<ButtonLink onClick={onClose}>{translate('cancel')}</ButtonLink>
</div>
</>
);
}
}

+ 45
- 0
server/sonar-web/src/main/js/app/components/nav/component/projectInformation/projectRegulatoryReport/RegulatoryReportModal.tsx 查看文件

@@ -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 * as React from 'react';
import { translate } from '../../../../../../helpers/l10n';
import { Component } from '../../../../../../types/types';
import Modal from '../../../../../../components/controls/Modal';
import RegulatoryReport from './RegulatoryReport';
import ClickEventBoundary from '../../../../../../components/controls/ClickEventBoundary';
import { BranchLike } from '../../../../../../types/branch-like';

interface Props {
component: Component;
branchLike?: BranchLike;
onClose: () => void;
}

export default function RegulatoryReportModal(props: Props) {
const { component, branchLike } = props;
return (
<Modal contentLabel={translate('regulatory_report.page')} onRequestClose={props.onClose}>
<ClickEventBoundary>
<form>
<RegulatoryReport component={component} branchLike={branchLike} onClose={props.onClose} />
</form>
</ClickEventBoundary>
</Modal>
);
}

server/sonar-web/src/main/js/apps/projectRegulatoryReport/__tests__/RegulatoryReport-it.tsx → server/sonar-web/src/main/js/app/components/nav/component/projectInformation/projectRegulatoryReport/__tests__/RegulatoryReport-it.tsx 查看文件

@@ -20,9 +20,20 @@
import { screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import * as React from 'react';
import { renderComponent } from '../../../helpers/testReactTestingUtils';
import BranchesServiceMock from '../../../../../../../api/mocks/BranchesServiceMock';
import { renderComponent } from '../../../../../../../helpers/testReactTestingUtils';
import RegulatoryReport from '../RegulatoryReport';

jest.mock('../../../../../../../api/branches');

let handler: BranchesServiceMock;

beforeAll(() => {
handler = new BranchesServiceMock();
});

afterEach(() => handler.resetBranches());

it('should open the regulatory report page', async () => {
const user = userEvent.setup();
renderRegulatoryReportApp();
@@ -30,6 +41,12 @@ it('should open the regulatory report page', async () => {
expect(screen.getByText('regulatory_report.description1')).toBeInTheDocument();
expect(screen.getByText('regulatory_report.description2')).toBeInTheDocument();

const branchSelect = screen.getByRole('textbox');
expect(branchSelect).toBeInTheDocument();

await user.click(branchSelect);
await user.keyboard('[ArrowDown][Enter]');

const downloadButton = screen.getByText('download_verb');
expect(downloadButton).toBeInTheDocument();

@@ -39,5 +56,5 @@ it('should open the regulatory report page', async () => {
});

function renderRegulatoryReportApp() {
renderComponent(<RegulatoryReport branchLike={undefined} component={{ key: '', name: '' }} />);
renderComponent(<RegulatoryReport component={{ key: '', name: '' }} onClose={() => {}} />);
}

+ 0
- 6
server/sonar-web/src/main/js/app/utils/startReactApp.tsx 查看文件

@@ -239,12 +239,6 @@ function renderComponentRoutes() {
path="project/deletion"
component={lazyLoadComponent(() => import('../../apps/projectDeletion/App'))}
/>
<Route
path="project/regulatory-report"
component={lazyLoadComponent(() =>
import('../../apps/projectRegulatoryReport/RegulatoryReport')
)}
/>
<Route
path="project/links"
component={lazyLoadComponent(() => import('../../apps/projectLinks/App'))}

+ 0
- 66
server/sonar-web/src/main/js/apps/projectRegulatoryReport/RegulatoryReport.tsx 查看文件

@@ -1,66 +0,0 @@
/*
* 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 { getRegulatoryReportUrl } from '../../api/regulatory-report';
import { isBranch } from '../../helpers/branch-like';
import { translate } from '../../helpers/l10n';
import { BranchLike } from '../../types/branch-like';
import { Component } from '../../types/types';

interface Props {
component: Pick<Component, 'key' | 'name'>;
branchLike?: BranchLike;
}

function RegulatoryReport(props: Props) {
const { component, branchLike } = props;
const branchName = branchLike && isBranch(branchLike) ? branchLike.name : undefined;
const [downloadStarted, setDownloadStarted] = React.useState(false);
return (
<div className="page page-limited">
<header className="page-header">
<h1 className="page-title">{translate('regulatory_report.page')}</h1>
</header>
<div className="page-description">
<p>{translate('regulatory_report.description1')}</p>
<p>{translate('regulatory_report.description2')}</p>
<div className="big-spacer-top">
<a
className={classNames('button button-primary', { disabled: downloadStarted })}
download={[component.name, branchName, 'PDF Report'].filter(s => !!s).join(' - ')}
onClick={() => setDownloadStarted(true)}
href={getRegulatoryReportUrl(component.key, branchName)}
target="_blank"
rel="noopener noreferrer">
{translate('download_verb')}
</a>
{downloadStarted && (
<div className="spacer-top">
<p>{translate('regulatory_page.download_start.sentence')}</p>
</div>
)}
</div>
</div>
</div>
);
}

export default RegulatoryReport;

+ 6
- 2
sonar-core/src/main/resources/org/sonar/l10n/core.properties 查看文件

@@ -647,9 +647,13 @@ baseline.branch_analyses.ranges.allTime=All time
baseline.no_analyses=No analyses

regulatory_report.page=Regulatory Report
regulatory_report.description1=The regulatory report is a zip file containing a snapshot of the branch you selected. It contains an overview of the project, the configuration items relevant to its quality (quality profile, quality gate and analysis exclusions), as well as lists of findings for both new code and overall code.
regulatory_report.description2=The file is created on demand when you download it. This may take some time.
regulatory_report.description1=The regulatory report is a zip file containing a snapshot of the selected branch. It contains:
regulatory_report.bullet_point1=An overview of the selected branch of the project.
regulatory_report.bullet_point2=The configuration items relevant to the project's quality (quality profile, quality gate, and analysis exclusions).
regulatory_report.bullet_point3=Lists of findings for both new and overall code on the selected branch.
regulatory_report.description2=The generation and download of the report may take a few minutes.
regulatory_page.download_start.sentence=Your download should start shortly. This may take some time.
regulatory_page.select_branch=Select Branch

#------------------------------------------------------------------------------
#

正在加载...
取消
保存