--- /dev/null
+/*
+ * 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 { getBaseUrl } from '../helpers/system';
+
+export function getRegulatoryReportUrl(project: string, branch?: string): string {
+ const params = new URLSearchParams({ project });
+ if (branch) {
+ params.append('branch', branch);
+ }
+ return `${getBaseUrl()}/api/regulatory_reports/download?${params.toString()}`;
+}
this.renderBackgroundTasksLink(query),
this.renderUpdateKeyLink(query),
this.renderWebhooksLink(query, isProject),
- this.renderDeletionLink(query)
+ this.renderDeletionLink(query),
+ this.renderRegulatoryReport(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) => {
const pathname = isAdmin ? `/project/admin/extension/${key}` : `/project/extension/${key}`;
const query = { ...baseQuery, qualifier: this.props.component.qualifier };
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'))}
--- /dev/null
+/*
+ * 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.pdf'].filter(s => !!s).join(' - ')}
+ onClick={() => setDownloadStarted(true)}
+ href={downloadStarted ? '#' : 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;
--- /dev/null
+/*
+ * 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 { screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import * as React from 'react';
+import { renderComponent } from '../../../helpers/testReactTestingUtils';
+import RegulatoryReport from '../RegulatoryReport';
+
+it('should open the regulatory report page', async () => {
+ const user = userEvent.setup();
+ renderRegulatoryReportApp();
+ expect(await screen.findByText('regulatory_report.page')).toBeInTheDocument();
+ expect(screen.getByText('regulatory_report.description1')).toBeInTheDocument();
+ expect(screen.getByText('regulatory_report.description2')).toBeInTheDocument();
+
+ const downloadButton = screen.getByText('download_verb');
+ expect(downloadButton).toBeInTheDocument();
+
+ expect(screen.queryByText('regulatory_page.download_start.sentence')).not.toBeInTheDocument();
+ await user.click(downloadButton);
+ expect(screen.getByText('regulatory_page.download_start.sentence')).toBeInTheDocument();
+});
+
+function renderRegulatoryReportApp() {
+ renderComponent(<RegulatoryReport branchLike={undefined} component={{ key: '', name: '' }} />);
+}
.no-select {
user-select: none !important;
}
+
+a[download].button.disabled {
+ pointer-events: none;
+}
standalone?: boolean;
version: string;
webAnalyticsJsPath?: string;
+ regulatoryReportFeatureEnabled?: boolean;
}
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_page.download_start.sentence=Your download should start shortly. This may take some time.
+
#------------------------------------------------------------------------------
#
# OTHER PAGE TITLES
portfolio_breakdown.page=Portfolio Breakdown
project_activity.page=Activity
-
#------------------------------------------------------------------------------
#
# ASYNC PROCESS