Selaa lähdekoodia

SONAR-16316 New place for regulatory report

tags/9.5.0.56709
Revanshu Paliwal 2 vuotta sitten
vanhempi
commit
c1a02f4549
13 muutettua tiedostoa jossa 543 lisäystä ja 97 poistoa
  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 Näytä tiedosto

/*
* 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 Näytä tiedosto

this.renderBackgroundTasksLink(query), this.renderBackgroundTasksLink(query),
this.renderUpdateKeyLink(query), this.renderUpdateKeyLink(query),
this.renderWebhooksLink(query, isProject), this.renderWebhooksLink(query, isProject),
this.renderDeletionLink(query),
this.renderRegulatoryReport(query)
this.renderDeletionLink(query)
]; ];
}; };


); );
}; };


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) => { renderExtension = ({ key, name }: Extension, isAdmin: boolean, baseQuery: Query) => {
const pathname = isAdmin ? `/project/admin/extension/${key}` : `/project/extension/${key}`; const pathname = isAdmin ? `/project/admin/extension/${key}` : `/project/extension/${key}`;
const query = { ...baseQuery, qualifier: this.props.component.qualifier }; const query = { ...baseQuery, qualifier: this.props.component.qualifier };

+ 1
- 0
server/sonar-web/src/main/js/app/components/nav/component/projectInformation/ProjectInformation.tsx Näytä tiedosto

canConfigureNotifications={canConfigureNotifications} canConfigureNotifications={canConfigureNotifications}
canUseBadges={canUseBadges} canUseBadges={canUseBadges}
component={component} component={component}
branchLike={branchLike}
measures={measures} measures={measures}
onComponentChange={this.props.onComponentChange} onComponentChange={this.props.onComponentChange}
onPageChange={this.setPage} onPageChange={this.setPage}

+ 34
- 2
server/sonar-web/src/main/js/app/components/nav/component/projectInformation/ProjectInformationRenderer.tsx Näytä tiedosto

* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
import * as React from 'react'; import * as React from 'react';
import { ButtonLink } from '../../../../../components/controls/buttons';
import ModalButton from '../../../../../components/controls/ModalButton';
import PrivacyBadgeContainer from '../../../../../components/common/PrivacyBadgeContainer'; import PrivacyBadgeContainer from '../../../../../components/common/PrivacyBadgeContainer';
import { translate } from '../../../../../helpers/l10n'; import { translate } from '../../../../../helpers/l10n';
import { ComponentQualifier } from '../../../../../types/component'; import { ComponentQualifier } from '../../../../../types/component';
import MetaSize from './meta/MetaSize'; import MetaSize from './meta/MetaSize';
import MetaTags from './meta/MetaTags'; import MetaTags from './meta/MetaTags';
import { ProjectInformationPages } from './ProjectInformationPages'; 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 { export interface ProjectInformationRendererProps {
appState: AppState;
canConfigureNotifications: boolean; canConfigureNotifications: boolean;
canUseBadges: boolean; canUseBadges: boolean;
component: Component; component: Component;
branchLike?: BranchLike;
measures?: Measure[]; measures?: Measure[];
onComponentChange: (changes: {}) => void; onComponentChange: (changes: {}) => void;
onPageChange: (page: ProjectInformationPages) => void; onPageChange: (page: ProjectInformationPages) => void;
} }


export function ProjectInformationRenderer(props: ProjectInformationRendererProps) { 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; const isApp = component.qualifier === ComponentQualifier.Application;


to={ProjectInformationPages.notifications} 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> </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 Näytä tiedosto

*/ */
import { shallow } from 'enzyme'; import { shallow } from 'enzyme';
import * as React from 'react'; import * as React from 'react';
import { mockAppState } from '../../../../../../helpers/testMocks';
import { mockComponent } from '../../../../../../helpers/mocks/component'; import { mockComponent } from '../../../../../../helpers/mocks/component';
import { import {
ProjectInformationRenderer, ProjectInformationRenderer,
).toMatchSnapshot(); ).toMatchSnapshot();
}); });


it('should render app correctly when regulatoryReportFeatureEnabled is false', () => {
expect(
shallowRender({
appState: mockAppState({
regulatoryReportFeatureEnabled: false
})
})
).toMatchSnapshot();
});

function shallowRender(props: Partial<ProjectInformationRendererProps> = {}) { function shallowRender(props: Partial<ProjectInformationRendererProps> = {}) {
return shallow( return shallow(
<ProjectInformationRenderer <ProjectInformationRenderer
appState={mockAppState({
regulatoryReportFeatureEnabled: true
})}
canConfigureNotifications={true} canConfigureNotifications={true}
canUseBadges={true} canUseBadges={true}
component={mockComponent({ qualifier: 'TRK', visibility: 'public' })} 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 Näytä tiedosto



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


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


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


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

+ 221
- 0
server/sonar-web/src/main/js/app/components/nav/component/projectInformation/__tests__/__snapshots__/ProjectInformationRenderer-test.tsx.snap Näytä tiedosto

onPageChange={[MockFunction]} onPageChange={[MockFunction]}
to={2} to={2}
/> />
<div
className="big-padded bordered-bottom"
>
<ModalButton
modal={[Function]}
>
<Component />
</ModalButton>
</div>
</div> </div>
</Fragment> </Fragment>
`; `;
onPageChange={[MockFunction]} onPageChange={[MockFunction]}
to={2} to={2}
/> />
<div
className="big-padded bordered-bottom"
>
<ModalButton
modal={[Function]}
>
<Component />
</ModalButton>
</div>
</div> </div>
</Fragment> </Fragment>
`; `;
</Fragment> </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`] = ` exports[`should render correctly: default 1`] = `
<Fragment> <Fragment>
<div> <div>
onPageChange={[MockFunction]} onPageChange={[MockFunction]}
to={2} to={2}
/> />
<div
className="big-padded bordered-bottom"
>
<ModalButton
modal={[Function]}
>
<Component />
</ModalButton>
</div>
</div> </div>
</Fragment> </Fragment>
`; `;
onPageChange={[MockFunction]} onPageChange={[MockFunction]}
to={2} to={2}
/> />
<div
className="big-padded bordered-bottom"
>
<ModalButton
modal={[Function]}
>
<Component />
</ModalButton>
</div>
</div> </div>
</Fragment> </Fragment>
`; `;
qualifier="TRK" qualifier="TRK"
/> />
</div> </div>
<div
className="big-padded bordered-bottom"
>
<ModalButton
modal={[Function]}
>
<Component />
</ModalButton>
</div>
</div> </div>
</Fragment> </Fragment>
`; `;
onPageChange={[MockFunction]} onPageChange={[MockFunction]}
to={1} to={1}
/> />
<div
className="big-padded bordered-bottom"
>
<ModalButton
modal={[Function]}
>
<Component />
</ModalButton>
</div>
</div> </div>
</Fragment> </Fragment>
`; `;
onPageChange={[MockFunction]} onPageChange={[MockFunction]}
to={2} to={2}
/> />
<div
className="big-padded bordered-bottom"
>
<ModalButton
modal={[Function]}
>
<Component />
</ModalButton>
</div>
</div> </div>
</Fragment> </Fragment>
`; `;

+ 153
- 0
server/sonar-web/src/main/js/app/components/nav/component/projectInformation/projectRegulatoryReport/RegulatoryReport.tsx Näytä tiedosto

/*
* 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 Näytä tiedosto

/*
* 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 Näytä tiedosto

import { screen } from '@testing-library/react'; import { screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event'; import userEvent from '@testing-library/user-event';
import * as React from 'react'; 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'; 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 () => { it('should open the regulatory report page', async () => {
const user = userEvent.setup(); const user = userEvent.setup();
renderRegulatoryReportApp(); renderRegulatoryReportApp();
expect(screen.getByText('regulatory_report.description1')).toBeInTheDocument(); expect(screen.getByText('regulatory_report.description1')).toBeInTheDocument();
expect(screen.getByText('regulatory_report.description2')).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'); const downloadButton = screen.getByText('download_verb');
expect(downloadButton).toBeInTheDocument(); expect(downloadButton).toBeInTheDocument();


}); });


function renderRegulatoryReportApp() { 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 Näytä tiedosto

path="project/deletion" path="project/deletion"
component={lazyLoadComponent(() => import('../../apps/projectDeletion/App'))} component={lazyLoadComponent(() => import('../../apps/projectDeletion/App'))}
/> />
<Route
path="project/regulatory-report"
component={lazyLoadComponent(() =>
import('../../apps/projectRegulatoryReport/RegulatoryReport')
)}
/>
<Route <Route
path="project/links" path="project/links"
component={lazyLoadComponent(() => import('../../apps/projectLinks/App'))} component={lazyLoadComponent(() => import('../../apps/projectLinks/App'))}

+ 0
- 66
server/sonar-web/src/main/js/apps/projectRegulatoryReport/RegulatoryReport.tsx Näytä tiedosto

/*
* 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 Näytä tiedosto

baseline.no_analyses=No analyses baseline.no_analyses=No analyses


regulatory_report.page=Regulatory Report 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.download_start.sentence=Your download should start shortly. This may take some time.
regulatory_page.select_branch=Select Branch


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

Loading…
Peruuta
Tallenna