return getComponentData(data).catch(throwGlobalError);
}
-export function getParents(component: string): Promise<any> {
- return getComponentShow({ component }).then((r) => r.ancestors);
-}
-
export function getBreadcrumbs(
data: { component: string } & BranchParameters
): Promise<Array<Omit<ComponentRaw, 'tags'>>> {
export function getComponentNavigation(
data: { component: string } & BranchParameters
): Promise<NavigationComponent> {
- return getJSON('/api/navigation/component', data).catch(throwGlobalError);
+ return getJSON('/api/navigation/component', data);
}
export function getMarketplaceNavigation(): Promise<{ serverId: string; ncloc: number }> {
import { HttpStatus } from '../../helpers/request';
import { getPortfolioUrl, getProjectUrl } from '../../helpers/urls';
import { ProjectAlmBindingConfigurationErrors } from '../../types/alm-settings';
-import { ComponentQualifier, isPortfolioLike } from '../../types/component';
+import { ComponentQualifier, isFile, isPortfolioLike } from '../../types/component';
import { Feature } from '../../types/features';
import { Task, TaskStatuses, TaskTypes } from '../../types/tasks';
import { Component } from '../../types/types';
* This is a fail-safe in case there are still some faulty links remaining.
*/
if (
- this.props.location.pathname.match('dashboard') &&
+ this.props.location.pathname.includes('dashboard') &&
isPortfolioLike(componentWithQualifier.qualifier)
) {
this.props.router.replace(getPortfolioUrl(componentWithQualifier.key));
loading: false,
},
() => {
- if (shouldRedirectToDashboard && this.props.location.pathname.match('tutorials')) {
+ if (shouldRedirectToDashboard && this.props.location.pathname.includes('tutorials')) {
this.props.router.replace(getProjectUrl(key));
}
}
const { component, loading } = this.state;
if (!loading && !component) {
- return <ComponentContainerNotFound />;
+ return (
+ <ComponentContainerNotFound
+ isPortfolioLike={this.props.location.pathname.includes('portfolio')}
+ />
+ );
}
const { currentTask, isPending, projectBindingErrors, tasksInProgress } = this.state;
component?.name ?? ''
)}
/>
-
{component &&
- !([ComponentQualifier.File, ComponentQualifier.TestFile] as string[]).includes(
- component.qualifier
- ) &&
+ !isFile(component.qualifier) &&
this.portalAnchor &&
/* Use a portal to fix positioning until we can fully review the layout */
createPortal(
/>,
this.portalAnchor
)}
-
{loading ? (
<div className="page page-limited">
<i className="spinner" />
import Link from '../../components/common/Link';
import { translate } from '../../helpers/l10n';
-export default function ComponentContainerNotFound() {
+export interface ComponentContainerNotFoundProps {
+ isPortfolioLike: boolean;
+}
+
+export default function ComponentContainerNotFound({
+ isPortfolioLike,
+}: ComponentContainerNotFoundProps) {
+ const componentType = isPortfolioLike ? 'portfolio' : 'project';
+
return (
<>
<Helmet defaultTitle={translate('404_not_found')} defer={false} />
<div className="page-wrapper-simple" id="bd">
<div className="page-simple" id="nonav">
- <h2 className="big-spacer-bottom">{translate('dashboard.project_not_found')}</h2>
- <p className="spacer-bottom">{translate('dashboard.project_not_found.2')}</p>
+ <h2 className="big-spacer-bottom">
+ {translate('dashboard', componentType, 'not_found')}
+ </h2>
+ <p className="spacer-bottom">{translate('dashboard', componentType, 'not_found.2')}</p>
<p>
<Link to="/">{translate('go_back_to_homepage')}</Link>
</p>
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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 * as React from 'react';
+import { renderComponent } from '../../../helpers/testReactTestingUtils';
+import ComponentContainerNotFound from '../ComponentContainerNotFound';
+
+it('should render portfolio 404 correctly', () => {
+ renderComponentContainerNotFound(true);
+
+ expect(screen.getByText('dashboard.portfolio.not_found')).toBeInTheDocument();
+ expect(screen.getByText('dashboard.portfolio.not_found.2')).toBeInTheDocument();
+});
+
+it('should render project 404 correctly', () => {
+ renderComponentContainerNotFound(false);
+
+ expect(screen.getByText('dashboard.project.not_found')).toBeInTheDocument();
+ expect(screen.getByText('dashboard.project.not_found.2')).toBeInTheDocument();
+});
+
+function renderComponentContainerNotFound(isPortfolioLike: boolean) {
+ return renderComponent(<ComponentContainerNotFound isPortfolioLike={isPortfolioLike} />);
+}
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`should show component not found if it does not exist 1`] = `<ComponentContainerNotFound />`;
+exports[`should show component not found if it does not exist 1`] = `
+<ComponentContainerNotFound
+ isPortfolioLike={false}
+/>
+`;
import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext';
import CreateApplicationForm from '../../../app/components/extensions/CreateApplicationForm';
import { Router, withRouter } from '../../../components/hoc/withRouter';
+import { throwGlobalError } from '../../../helpers/error';
import { translate } from '../../../helpers/l10n';
import { getComponentAdminUrl, getComponentOverviewUrl } from '../../../helpers/urls';
import { hasGlobalPermission } from '../../../helpers/users';
key: string;
qualifier: ComponentQualifier;
}) => {
- return getComponentNavigation({ component: key }).then(({ configuration }) => {
- if (configuration && configuration.showSettings) {
- router.push(getComponentAdminUrl(key, qualifier));
- } else {
- router.push(getComponentOverviewUrl(key, qualifier));
- }
- setShowForm(false);
- });
+ return getComponentNavigation({ component: key })
+ .then(({ configuration }) => {
+ if (configuration?.showSettings) {
+ router.push(getComponentAdminUrl(key, qualifier));
+ } else {
+ router.push(getComponentOverviewUrl(key, qualifier));
+ }
+ setShowForm(false);
+ })
+ .catch(throwGlobalError);
};
return (
import { Project } from '../../api/project-management';
import ActionsDropdown, { ActionsDropdownItem } from '../../components/controls/ActionsDropdown';
import Spinner from '../../components/ui/Spinner';
+import { throwGlobalError } from '../../helpers/error';
import { translate, translateWithParameters } from '../../helpers/l10n';
import { getComponentPermissionsUrl } from '../../helpers/urls';
import { useGithubProvisioningEnabledQuery } from '../../queries/identity-provider';
const [restoreAccessModal, setRestoreAccessModal] = useState(false);
const { data: githubProvisioningEnabled } = useGithubProvisioningEnabledQuery();
- const fetchPermissions = () => {
+ const fetchPermissions = async () => {
setLoading(true);
- getComponentNavigation({ component: project.key }).then(
- ({ configuration }) => {
- const hasAccess = Boolean(
- configuration && configuration.showPermissions && configuration.canBrowseProject
- );
- setHasAccess(hasAccess);
- setLoading(false);
- },
- () => {
- setLoading(false);
- }
- );
+
+ try {
+ const { configuration } = await getComponentNavigation({ component: project.key });
+ const hasAccess = Boolean(configuration?.showPermissions && configuration?.canBrowseProject);
+ setHasAccess(hasAccess);
+ setLoading(false);
+ } catch (error) {
+ throwGlobalError(error);
+ } finally {
+ setLoading(false);
+ }
};
const handleDropdownOpen = () => {
#
#------------------------------------------------------------------------------
-dashboard.project_not_found=The requested project does not exist.
-dashboard.project_not_found.2=Either it has never been analyzed successfully or it has been deleted.
+dashboard.project.not_found=The requested project could not be found.
+dashboard.project.not_found.2=Either it has never been analyzed successfully or it has been deleted.
+dashboard.portfolio.not_found=The requested portfolio could not be found.
+dashboard.portfolio.not_found.2=Either its parent has not been recomputed or it has been deleted.
#------------------------------------------------------------------------------