--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 { Alert } from '../../components/ui/Alert';
+import { translate } from '../../helpers/l10n';
+import { BranchLike } from '../../types/branch-like';
+import { isApplication } from '../../types/component';
+
+export interface NonAdminPagesContainerProps {
+ children: JSX.Element;
+ branchLike?: BranchLike;
+ branchLikes: BranchLike[];
+ component: T.Component;
+ isInProgress?: boolean;
+ isPending?: boolean;
+ onBranchesChange: () => void;
+ onComponentChange: (changes: {}) => void;
+}
+
+export default function NonAdminPagesContainer(props: NonAdminPagesContainerProps) {
+ const { children, component } = props;
+
+ /*
+ * Catch Applications for which the user does not have access to all child projects
+ * and prevent displaying whatever page was requested.
+ * This doesn't apply to admin pages (those are not within this container)
+ */
+ if (isApplication(component.qualifier) && !component.canBrowseAllChildProjects) {
+ return (
+ <div className="page page-limited display-flex-justify-center">
+ <Alert className="max-width-60 huge-spacer-top" display="block" variant="error">
+ <p>{translate('application.cannot_access_all_child_projects1')}</p>
+ <br />
+ <p>{translate('application.cannot_access_all_child_projects2')}</p>
+ </Alert>
+ </div>
+ );
+ }
+
+ return React.cloneElement(children, props);
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import { mockComponent } from '../../../helpers/mocks/component';
+import { ComponentQualifier } from '../../../types/component';
+import NonAdminPagesContainer, { NonAdminPagesContainerProps } from '../NonAdminPagesContainer';
+
+function Child() {
+ return <div />;
+}
+
+it('should render correctly', () => {
+ expect(
+ shallowRender()
+ .find(Child)
+ .exists()
+ ).toBe(true);
+
+ expect(
+ shallowRender({
+ component: mockComponent({
+ qualifier: ComponentQualifier.Application,
+ canBrowseAllChildProjects: true
+ })
+ })
+ .find(Child)
+ .exists()
+ ).toBe(true);
+
+ const wrapper = shallowRender({
+ component: mockComponent({
+ qualifier: ComponentQualifier.Application
+ })
+ });
+
+ expect(wrapper.find(Child).exists()).toBe(false);
+ expect(wrapper).toMatchSnapshot();
+});
+
+function shallowRender(props: Partial<NonAdminPagesContainerProps> = {}) {
+ return shallow<NonAdminPagesContainerProps>(
+ <NonAdminPagesContainer
+ branchLikes={[]}
+ component={mockComponent()}
+ onBranchesChange={jest.fn()}
+ onComponentChange={jest.fn()}
+ {...props}>
+ <Child />
+ </NonAdminPagesContainer>
+ );
+}
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<div
+ className="page page-limited display-flex-justify-center"
+>
+ <Alert
+ className="max-width-60 huge-spacer-top"
+ display="block"
+ variant="error"
+ >
+ <p>
+ application.cannot_access_all_child_projects1
+ </p>
+ <br />
+ <p>
+ application.cannot_access_all_child_projects2
+ </p>
+ </Alert>
+</div>
+`;
import GlobalContainer from '../components/GlobalContainer';
import { PageContext } from '../components/indexation/PageUnavailableDueToIndexation';
import MigrationContainer from '../components/MigrationContainer';
+import NonAdminPagesContainer from '../components/NonAdminPagesContainer';
import getStore from './getStore';
/*
function renderComponentRoutes() {
return (
<Route component={lazyLoadComponent(() => import('../components/ComponentContainer'))}>
- <RouteWithChildRoutes path="code" childRoutes={codeRoutes} />
- <RouteWithChildRoutes path="component_measures" childRoutes={componentMeasuresRoutes} />
- <RouteWithChildRoutes path="dashboard" childRoutes={overviewRoutes} />
- <RouteWithChildRoutes path="portfolio" childRoutes={portfolioRoutes} />
- <RouteWithChildRoutes path="project/activity" childRoutes={projectActivityRoutes} />
- <Route
- path="project/extension/:pluginKey/:extensionKey"
- component={lazyLoadComponent(() => import('../components/extensions/ProjectPageExtension'))}
- />
- <Route
- path="project/issues"
- component={Issues}
- onEnter={({ location: { query } }, replace) => {
- if (query.types) {
- if (query.types === 'SECURITY_HOTSPOT') {
- replace({
- pathname: '/security_hotspots',
- query: { ...pick(query, ['id', 'branch', 'pullRequest']), assignedToMe: false }
- });
- } else {
- query.types = query.types
- .split(',')
- .filter((type: string) => type !== 'SECURITY_HOTSPOT')
- .join(',');
+ {/* This container is a catch-all for all non-admin pages */}
+ <Route component={NonAdminPagesContainer}>
+ <RouteWithChildRoutes path="code" childRoutes={codeRoutes} />
+ <RouteWithChildRoutes path="component_measures" childRoutes={componentMeasuresRoutes} />
+ <RouteWithChildRoutes path="dashboard" childRoutes={overviewRoutes} />
+ <RouteWithChildRoutes path="portfolio" childRoutes={portfolioRoutes} />
+ <RouteWithChildRoutes path="project/activity" childRoutes={projectActivityRoutes} />
+ <Route
+ path="project/extension/:pluginKey/:extensionKey"
+ component={lazyLoadComponent(() =>
+ import('../components/extensions/ProjectPageExtension')
+ )}
+ />
+ <Route
+ path="project/issues"
+ component={Issues}
+ onEnter={({ location: { query } }, replace) => {
+ if (query.types) {
+ if (query.types === 'SECURITY_HOTSPOT') {
+ replace({
+ pathname: '/security_hotspots',
+ query: { ...pick(query, ['id', 'branch', 'pullRequest']), assignedToMe: false }
+ });
+ } else {
+ query.types = query.types
+ .split(',')
+ .filter((type: string) => type !== 'SECURITY_HOTSPOT')
+ .join(',');
+ }
}
- }
- }}
- />
- <Route
- path="security_hotspots"
- component={lazyLoadComponent(() =>
- import('../../apps/security-hotspots/SecurityHotspotsApp')
- )}
- />
- <RouteWithChildRoutes path="project/quality_gate" childRoutes={projectQualityGateRoutes} />
- <RouteWithChildRoutes
- path="project/quality_profiles"
- childRoutes={projectQualityProfilesRoutes}
- />
- <RouteWithChildRoutes path="tutorials" childRoutes={tutorialsRoutes} />
+ }}
+ />
+ <Route
+ path="security_hotspots"
+ component={lazyLoadComponent(() =>
+ import('../../apps/security-hotspots/SecurityHotspotsApp')
+ )}
+ />
+ <RouteWithChildRoutes path="project/quality_gate" childRoutes={projectQualityGateRoutes} />
+ <RouteWithChildRoutes
+ path="project/quality_profiles"
+ childRoutes={projectQualityProfilesRoutes}
+ />
+ <RouteWithChildRoutes path="tutorials" childRoutes={tutorialsRoutes} />
+ </Route>
<Route component={lazyLoadComponent(() => import('../components/ProjectAdminContainer'))}>
<Route
path="project/admin/extension/:pluginKey/:extensionKey"
branch_like_navigation.only_one_branch.pr_analysis=Pull Request analysis
branch_like_navigation.tutorial_for_ci=Show me how to set up my CI
+#------------------------------------------------------------------------------
+#
+# APPLICATIONS
+#
+#------------------------------------------------------------------------------
+application.cannot_access_all_child_projects1=You must have access to all the projects within this Application in order to browse it.
+application.cannot_access_all_child_projects2=Please contact your project administrator.
+
#------------------------------------------------------------------------------
#
# PORTFOLIOS