]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-13339 Disable component menu links when no analysis has been run yet
authorWouter Admiraal <wouter.admiraal@sonarsource.com>
Tue, 28 Apr 2020 13:47:44 +0000 (15:47 +0200)
committersonartech <sonartech@sonarsource.com>
Mon, 4 May 2020 20:03:53 +0000 (20:03 +0000)
server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.tsx
server/sonar-web/src/main/js/app/components/nav/component/Menu.css
server/sonar-web/src/main/js/app/components/nav/component/Menu.tsx
server/sonar-web/src/main/js/app/components/nav/component/__tests__/Menu-test.tsx
server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNav-test.tsx.snap
server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/Menu-test.tsx.snap
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index 29f8c5967857178ea3f17ac9b8e570b8015da4b7..ceeae0dbbf64e6479e9cd9b18a35bf0b68244b0d 100644 (file)
@@ -104,7 +104,10 @@ export default function ComponentNav(props: Props) {
       </div>
       <Menu
         branchLike={currentBranchLike}
+        branchLikes={branchLikes}
         component={component}
+        isInProgress={isInProgress}
+        isPending={isPending}
         onToggleProjectInfo={() => setDisplayProjectInfo(!displayProjectInfo)}
       />
       <InfoDrawer
index 3a62e30ca89f5578e34fd837505149a285726eab..83418b1b3f50770f6d9a48a74df090b59f50c134 100644 (file)
   color: var(--blue);
   border-bottom-color: transparent;
 }
+
+.navbar-tabs > li > a.disabled-link,
+.navbar-tabs > li > a.disabled-link:hover {
+  color: var(--gray71);
+  cursor: default;
+  border-bottom-color: transparent;
+}
index c1aea4a7bfa3c74a2c85d0184fb80f1432e89711..b217d44e23cf8daa2ea3d318fce21074bd9615cb 100644 (file)
@@ -19,8 +19,9 @@
  */
 import * as classNames from 'classnames';
 import * as React from 'react';
-import { Link } from 'react-router';
+import { Link, LinkProps } from 'react-router';
 import Dropdown from 'sonar-ui-common/components/controls/Dropdown';
+import Tooltip from 'sonar-ui-common/components/controls/Tooltip';
 import BulletListIcon from 'sonar-ui-common/components/icons/BulletListIcon';
 import DropdownIcon from 'sonar-ui-common/components/icons/DropdownIcon';
 import NavBarTabs from 'sonar-ui-common/components/ui/NavBarTabs';
@@ -28,7 +29,7 @@ import { hasMessage, translate } from 'sonar-ui-common/helpers/l10n';
 import { withAppState } from '../../../../components/hoc/withAppState';
 import { getBranchLikeQuery, isMainBranch, isPullRequest } from '../../../../helpers/branch-like';
 import { isSonarCloud } from '../../../../helpers/system';
-import { BranchLike } from '../../../../types/branch-like';
+import { BranchLike, BranchParameters } from '../../../../types/branch-like';
 import { ComponentQualifier } from '../../../../types/component';
 import './Menu.css';
 
@@ -52,66 +53,101 @@ const SETTINGS_URLS = [
 interface Props {
   appState: Pick<T.AppState, 'branchesEnabled'>;
   branchLike: BranchLike | undefined;
+  branchLikes: BranchLike[] | undefined;
   component: T.Component;
+  isInProgress?: boolean;
+  isPending?: boolean;
   onToggleProjectInfo: () => void;
 }
 
+type Query = BranchParameters & { id: string };
+
+function MenuLink({
+  hasAnalysis,
+  label,
+  ...props
+}: LinkProps & { hasAnalysis: boolean; label: React.ReactNode }) {
+  return hasAnalysis ? (
+    <Link {...props}>{label}</Link>
+  ) : (
+    <Tooltip overlay={translate('layout.must_be_configured')}>
+      <a aria-disabled="true" className="disabled-link">
+        {label}
+      </a>
+    </Tooltip>
+  );
+}
+
 export class Menu extends React.PureComponent<Props> {
-  isProject() {
+  hasAnalysis = () => {
+    const { branchLikes = [], component, isInProgress, isPending } = this.props;
+    const hasBranches = branchLikes.length > 1;
+    return hasBranches || isInProgress || isPending || component.analysisDate !== undefined;
+  };
+
+  isProject = () => {
     return this.props.component.qualifier === ComponentQualifier.Project;
-  }
+  };
 
-  isDeveloper() {
+  isDeveloper = () => {
     return this.props.component.qualifier === ComponentQualifier.Developper;
-  }
+  };
 
-  isPortfolio() {
+  isPortfolio = () => {
     const { qualifier } = this.props.component;
     return (
       qualifier === ComponentQualifier.Portfolio || qualifier === ComponentQualifier.SubPortfolio
     );
-  }
+  };
 
-  isApplication() {
+  isApplication = () => {
     return this.props.component.qualifier === ComponentQualifier.Application;
-  }
+  };
 
-  getConfiguration() {
+  getConfiguration = () => {
     return this.props.component.configuration || {};
-  }
+  };
 
-  getQuery = () => {
+  getQuery = (): Query => {
     return { id: this.props.component.key, ...getBranchLikeQuery(this.props.branchLike) };
   };
 
-  renderDashboardLink() {
-    const pathname = this.isPortfolio() ? '/portfolio' : '/dashboard';
+  renderDashboardLink = (query: Query, isPortfolio: boolean) => {
+    const pathname = isPortfolio ? '/portfolio' : '/dashboard';
     return (
       <li>
-        <Link activeClassName="active" to={{ pathname, query: this.getQuery() }}>
+        <Link activeClassName="active" to={{ pathname, query }}>
           {translate('overview.page')}
         </Link>
       </li>
     );
-  }
+  };
 
-  renderCodeLink() {
+  renderCodeLink = (
+    hasAnalysis: boolean,
+    query: Query,
+    isApplication: boolean,
+    isPortfolio: boolean
+  ) => {
     if (this.isDeveloper()) {
       return null;
     }
 
     return (
       <li>
-        <Link activeClassName="active" to={{ pathname: '/code', query: this.getQuery() }}>
-          {this.isPortfolio() || this.isApplication()
-            ? translate('view_projects.page')
-            : translate('code.page')}
-        </Link>
+        <MenuLink
+          activeClassName="active"
+          hasAnalysis={hasAnalysis}
+          label={
+            isPortfolio || isApplication ? translate('view_projects.page') : translate('code.page')
+          }
+          to={{ pathname: '/code', query }}
+        />
       </li>
     );
-  }
+  };
 
-  renderActivityLink() {
+  renderActivityLink = (hasAnalysis: boolean, query: Query) => {
     const { branchLike } = this.props;
 
     if (isPullRequest(branchLike)) {
@@ -120,54 +156,58 @@ export class Menu extends React.PureComponent<Props> {
 
     return (
       <li>
-        <Link
+        <MenuLink
           activeClassName="active"
-          to={{ pathname: '/project/activity', query: this.getQuery() }}>
-          {translate('project_activity.page')}
-        </Link>
+          hasAnalysis={hasAnalysis}
+          label={translate('project_activity.page')}
+          to={{ pathname: '/project/activity', query }}
+        />
       </li>
     );
-  }
+  };
 
-  renderIssuesLink() {
+  renderIssuesLink = (hasAnalysis: boolean, query: Query) => {
     return (
       <li>
-        <Link
+        <MenuLink
           activeClassName="active"
-          to={{ pathname: '/project/issues', query: { ...this.getQuery(), resolved: 'false' } }}>
-          {translate('issues.page')}
-        </Link>
+          hasAnalysis={hasAnalysis}
+          label={translate('issues.page')}
+          to={{ pathname: '/project/issues', query: { ...query, resolved: 'false' } }}
+        />
       </li>
     );
-  }
+  };
 
-  renderComponentMeasuresLink() {
+  renderComponentMeasuresLink = (hasAnalysis: boolean, query: Query) => {
     return (
       <li>
-        <Link
+        <MenuLink
           activeClassName="active"
-          to={{ pathname: '/component_measures', query: this.getQuery() }}>
-          {translate('layout.measures')}
-        </Link>
+          hasAnalysis={hasAnalysis}
+          label={translate('layout.measures')}
+          to={{ pathname: '/component_measures', query }}
+        />
       </li>
     );
-  }
+  };
 
-  renderSecurityHotspotsLink() {
+  renderSecurityHotspotsLink = (hasAnalysis: boolean, query: Query, isPortfolio: boolean) => {
     return (
-      !this.isPortfolio() && (
+      !isPortfolio && (
         <li>
-          <Link
+          <MenuLink
             activeClassName="active"
-            to={{ pathname: '/security_hotspots', query: this.getQuery() }}>
-            {translate('layout.security_hotspots')}
-          </Link>
+            hasAnalysis={hasAnalysis}
+            label={translate('layout.security_hotspots')}
+            to={{ pathname: '/security_hotspots', query }}
+          />
         </li>
       )
     );
-  }
+  };
 
-  renderSecurityReports() {
+  renderSecurityReports = (hasAnalysis: boolean, query: Query) => {
     const { branchLike, component } = this.props;
     const { extensions = [] } = component;
 
@@ -185,19 +225,25 @@ export class Menu extends React.PureComponent<Props> {
 
     return (
       <li>
-        <Link
+        <MenuLink
           activeClassName="active"
+          hasAnalysis={hasAnalysis}
+          label={translate('layout.security_reports')}
           to={{
             pathname: '/project/extension/securityreport/securityreport',
-            query: this.getQuery()
-          }}>
-          {translate('layout.security_reports')}
-        </Link>
+            query
+          }}
+        />
       </li>
     );
-  }
+  };
 
-  renderAdministration() {
+  renderAdministration = (
+    query: Query,
+    isProject: boolean,
+    isApplication: boolean,
+    isPortfolio: boolean
+  ) => {
     const { branchLike, component } = this.props;
 
     if (!this.getConfiguration().showSettings || isPullRequest(branchLike)) {
@@ -206,7 +252,7 @@ export class Menu extends React.PureComponent<Props> {
 
     const isSettingsActive = SETTINGS_URLS.some(url => window.location.href.indexOf(url) !== -1);
 
-    const adminLinks = this.renderAdministrationLinks();
+    const adminLinks = this.renderAdministrationLinks(query, isProject, isApplication, isPortfolio);
     if (!adminLinks.some(link => link != null)) {
       return null;
     }
@@ -232,33 +278,38 @@ export class Menu extends React.PureComponent<Props> {
         )}
       </Dropdown>
     );
-  }
+  };
 
-  renderAdministrationLinks() {
+  renderAdministrationLinks = (
+    query: Query,
+    isProject: boolean,
+    isApplication: boolean,
+    isPortfolio: boolean
+  ) => {
     return [
-      this.renderSettingsLink(),
-      this.renderBranchesLink(),
-      this.renderBaselineLink(),
-      this.renderProfilesLink(),
-      this.renderQualityGateLink(),
-      this.renderCustomMeasuresLink(),
-      this.renderLinksLink(),
-      this.renderPermissionsLink(),
-      this.renderBackgroundTasksLink(),
-      this.renderUpdateKeyLink(),
-      this.renderWebhooksLink(),
-      ...this.renderAdminExtensions(),
-      this.renderDeletionLink()
+      this.renderSettingsLink(query, isApplication, isPortfolio),
+      this.renderBranchesLink(query, isProject),
+      this.renderBaselineLink(query, isApplication, isPortfolio),
+      this.renderProfilesLink(query),
+      this.renderQualityGateLink(query),
+      this.renderCustomMeasuresLink(query),
+      this.renderLinksLink(query),
+      this.renderPermissionsLink(query),
+      this.renderBackgroundTasksLink(query),
+      this.renderUpdateKeyLink(query),
+      this.renderWebhooksLink(query, isProject),
+      ...this.renderAdminExtensions(query),
+      this.renderDeletionLink(query)
     ];
-  }
+  };
 
-  renderProjectInformationButton() {
+  renderProjectInformationButton = (isProject: boolean, isApplication: boolean) => {
     if (isPullRequest(this.props.branchLike)) {
       return null;
     }
 
     return (
-      (this.isProject() || this.isApplication()) && (
+      (isProject || isApplication) && (
         <li>
           <a
             className="menu-button"
@@ -270,32 +321,30 @@ export class Menu extends React.PureComponent<Props> {
             role="button"
             tabIndex={0}>
             <BulletListIcon className="little-spacer-right" />
-            {translate(this.isProject() ? 'project' : 'application', 'info.title')}
+            {translate(isProject ? 'project' : 'application', 'info.title')}
           </a>
         </li>
       )
     );
-  }
+  };
 
-  renderSettingsLink() {
-    if (!this.getConfiguration().showSettings || this.isApplication() || this.isPortfolio()) {
+  renderSettingsLink = (query: Query, isApplication: boolean, isPortfolio: boolean) => {
+    if (!this.getConfiguration().showSettings || isApplication || isPortfolio) {
       return null;
     }
     return (
       <li key="settings">
-        <Link
-          activeClassName="active"
-          to={{ pathname: '/project/settings', query: this.getQuery() }}>
+        <Link activeClassName="active" to={{ pathname: '/project/settings', query }}>
           {translate('project_settings.page')}
         </Link>
       </li>
     );
-  }
+  };
 
-  renderBranchesLink() {
+  renderBranchesLink = (query: Query, isProject: boolean) => {
     if (
       !this.props.appState.branchesEnabled ||
-      !this.isProject() ||
+      !isProject ||
       !this.getConfiguration().showSettings
     ) {
       return null;
@@ -303,145 +352,131 @@ export class Menu extends React.PureComponent<Props> {
 
     return (
       <li key="branches">
-        <Link
-          activeClassName="active"
-          to={{ pathname: '/project/branches', query: this.getQuery() }}>
+        <Link activeClassName="active" to={{ pathname: '/project/branches', query }}>
           {translate('project_branch_pull_request.page')}
         </Link>
       </li>
     );
-  }
+  };
 
-  renderBaselineLink() {
-    if (!this.getConfiguration().showSettings || this.isApplication() || this.isPortfolio()) {
+  renderBaselineLink = (query: Query, isApplication: boolean, isPortfolio: boolean) => {
+    if (!this.getConfiguration().showSettings || isApplication || isPortfolio) {
       return null;
     }
     return (
       <li key="baseline">
-        <Link
-          activeClassName="active"
-          to={{ pathname: '/project/baseline', query: this.getQuery() }}>
+        <Link activeClassName="active" to={{ pathname: '/project/baseline', query }}>
           {translate('project_baseline.page')}
         </Link>
       </li>
     );
-  }
+  };
 
-  renderProfilesLink() {
+  renderProfilesLink = (query: Query) => {
     if (!this.getConfiguration().showQualityProfiles) {
       return null;
     }
     return (
       <li key="profiles">
-        <Link
-          activeClassName="active"
-          to={{ pathname: '/project/quality_profiles', query: this.getQuery() }}>
+        <Link activeClassName="active" to={{ pathname: '/project/quality_profiles', query }}>
           {translate('project_quality_profiles.page')}
         </Link>
       </li>
     );
-  }
+  };
 
-  renderQualityGateLink() {
+  renderQualityGateLink = (query: Query) => {
     if (!this.getConfiguration().showQualityGates) {
       return null;
     }
     return (
       <li key="quality_gate">
-        <Link
-          activeClassName="active"
-          to={{ pathname: '/project/quality_gate', query: this.getQuery() }}>
+        <Link activeClassName="active" to={{ pathname: '/project/quality_gate', query }}>
           {translate('project_quality_gate.page')}
         </Link>
       </li>
     );
-  }
+  };
 
-  renderCustomMeasuresLink() {
+  renderCustomMeasuresLink = (query: Query) => {
     if (isSonarCloud() || !this.getConfiguration().showManualMeasures) {
       return null;
     }
     return (
       <li key="custom_measures">
-        <Link
-          activeClassName="active"
-          to={{ pathname: '/custom_measures', query: this.getQuery() }}>
+        <Link activeClassName="active" to={{ pathname: '/custom_measures', query }}>
           {translate('custom_measures.page')}
         </Link>
       </li>
     );
-  }
+  };
 
-  renderLinksLink() {
+  renderLinksLink = (query: Query) => {
     if (!this.getConfiguration().showLinks) {
       return null;
     }
     return (
       <li key="links">
-        <Link activeClassName="active" to={{ pathname: '/project/links', query: this.getQuery() }}>
+        <Link activeClassName="active" to={{ pathname: '/project/links', query }}>
           {translate('project_links.page')}
         </Link>
       </li>
     );
-  }
+  };
 
-  renderPermissionsLink() {
+  renderPermissionsLink = (query: Query) => {
     if (!this.getConfiguration().showPermissions) {
       return null;
     }
     return (
       <li key="permissions">
-        <Link activeClassName="active" to={{ pathname: '/project_roles', query: this.getQuery() }}>
+        <Link activeClassName="active" to={{ pathname: '/project_roles', query }}>
           {translate('permissions.page')}
         </Link>
       </li>
     );
-  }
+  };
 
-  renderBackgroundTasksLink() {
+  renderBackgroundTasksLink = (query: Query) => {
     if (!this.getConfiguration().showBackgroundTasks) {
       return null;
     }
     return (
       <li key="background_tasks">
-        <Link
-          activeClassName="active"
-          to={{ pathname: '/project/background_tasks', query: this.getQuery() }}>
+        <Link activeClassName="active" to={{ pathname: '/project/background_tasks', query }}>
           {translate('background_tasks.page')}
         </Link>
       </li>
     );
-  }
+  };
 
-  renderUpdateKeyLink() {
+  renderUpdateKeyLink = (query: Query) => {
     if (!this.getConfiguration().showUpdateKey) {
       return null;
     }
     return (
       <li key="update_key">
-        <Link activeClassName="active" to={{ pathname: '/project/key', query: this.getQuery() }}>
+        <Link activeClassName="active" to={{ pathname: '/project/key', query }}>
           {translate('update_key.page')}
         </Link>
       </li>
     );
-  }
+  };
 
-  renderWebhooksLink() {
-    if (!this.getConfiguration().showSettings || !this.isProject()) {
+  renderWebhooksLink = (query: Query, isProject: boolean) => {
+    if (!this.getConfiguration().showSettings || !isProject) {
       return null;
     }
     return (
       <li key="webhooks">
-        <Link
-          activeClassName="active"
-          to={{ pathname: '/project/webhooks', query: this.getQuery() }}>
+        <Link activeClassName="active" to={{ pathname: '/project/webhooks', query }}>
           {translate('webhooks.page')}
         </Link>
       </li>
     );
-  }
+  };
 
-  renderDeletionLink() {
+  renderDeletionLink = (query: Query) => {
     const { qualifier } = this.props.component;
 
     if (!this.getConfiguration().showSettings) {
@@ -460,18 +495,16 @@ export class Menu extends React.PureComponent<Props> {
 
     return (
       <li key="project_delete">
-        <Link
-          activeClassName="active"
-          to={{ pathname: '/project/deletion', query: this.getQuery() }}>
+        <Link activeClassName="active" to={{ pathname: '/project/deletion', query }}>
           {translate('deletion.page')}
         </Link>
       </li>
     );
-  }
+  };
 
-  renderExtension = ({ key, name }: T.Extension, isAdmin: boolean) => {
+  renderExtension = ({ key, name }: T.Extension, isAdmin: boolean, baseQuery: Query) => {
     const pathname = isAdmin ? `/project/admin/extension/${key}` : `/project/extension/${key}`;
-    const query = { ...this.getQuery(), qualifier: this.props.component.qualifier };
+    const query = { ...baseQuery, qualifier: this.props.component.qualifier };
     return (
       <li key={key}>
         <Link activeClassName="active" to={{ pathname, query }}>
@@ -481,15 +514,15 @@ export class Menu extends React.PureComponent<Props> {
     );
   };
 
-  renderAdminExtensions() {
+  renderAdminExtensions = (query: Query) => {
     if (this.props.branchLike && !isMainBranch(this.props.branchLike)) {
       return [];
     }
     const extensions = this.getConfiguration().extensions || [];
-    return extensions.map(e => this.renderExtension(e, true));
-  }
+    return extensions.map(e => this.renderExtension(e, true, query));
+  };
 
-  renderExtensions() {
+  renderExtensions = (query: Query) => {
     const extensions = this.props.component.extensions || [];
     const withoutSecurityExtension = extensions.filter(
       extension => !extension.key.startsWith('securityreport/')
@@ -506,7 +539,7 @@ export class Menu extends React.PureComponent<Props> {
         data-test="extensions"
         overlay={
           <ul className="menu">
-            {withoutSecurityExtension.map(e => this.renderExtension(e, false))}
+            {withoutSecurityExtension.map(e => this.renderExtension(e, false, query))}
           </ul>
         }
         tagName="li">
@@ -524,24 +557,29 @@ export class Menu extends React.PureComponent<Props> {
         )}
       </Dropdown>
     );
-  }
+  };
 
   render() {
+    const isProject = this.isProject();
+    const isApplication = this.isApplication();
+    const isPortfolio = this.isPortfolio();
+    const hasAnalysis = this.hasAnalysis();
+    const query = this.getQuery();
     return (
       <div className="display-flex-center display-flex-space-between">
         <NavBarTabs>
-          {this.renderDashboardLink()}
-          {this.renderIssuesLink()}
-          {this.renderSecurityHotspotsLink()}
-          {this.renderSecurityReports()}
-          {this.renderComponentMeasuresLink()}
-          {this.renderCodeLink()}
-          {this.renderActivityLink()}
-          {this.renderExtensions()}
+          {this.renderDashboardLink(query, isPortfolio)}
+          {this.renderIssuesLink(hasAnalysis, query)}
+          {this.renderSecurityHotspotsLink(hasAnalysis, query, isPortfolio)}
+          {this.renderSecurityReports(hasAnalysis, query)}
+          {this.renderComponentMeasuresLink(hasAnalysis, query)}
+          {this.renderCodeLink(hasAnalysis, query, isApplication, isPortfolio)}
+          {this.renderActivityLink(hasAnalysis, query)}
+          {this.renderExtensions(query)}
         </NavBarTabs>
         <NavBarTabs>
-          {this.renderAdministration()}
-          {this.renderProjectInformationButton()}
+          {this.renderAdministration(query, isProject, isApplication, isPortfolio)}
+          {this.renderProjectInformationButton(isProject, isApplication)}
         </NavBarTabs>
       </div>
     );
index 7f825a0c9ef6a57da1c92312508c3573054a83de..041f3c3d8fa9a928ac29cc93d77159d5e80db572 100644 (file)
@@ -25,18 +25,17 @@ import {
   mockMainBranch,
   mockPullRequest
 } from '../../../../../helpers/mocks/branch-like';
+import { mockComponent } from '../../../../../helpers/testMocks';
 import { ComponentQualifier } from '../../../../../types/component';
 import { Menu } from '../Menu';
 
 const mainBranch = mockMainBranch();
 
-const baseComponent = {
-  breadcrumbs: [],
+const baseComponent = mockComponent({
+  analysisDate: '2019-12-01',
   key: 'foo',
-  name: 'foo',
-  organization: 'org',
-  qualifier: 'TRK'
-};
+  name: 'foo'
+});
 
 it('should work with extensions', () => {
   const component = {
@@ -137,12 +136,26 @@ it('should work for all qualifiers', () => {
   }
 });
 
+it('should disable links if no analysis has been done', () => {
+  expect(
+    shallowRender({
+      component: {
+        ...baseComponent,
+        analysisDate: undefined
+      }
+    })
+  ).toMatchSnapshot();
+});
+
 function shallowRender(props: Partial<Menu['props']>) {
   return shallow<Menu>(
     <Menu
       appState={{ branchesEnabled: true }}
       branchLike={mainBranch}
+      branchLikes={[mainBranch]}
       component={baseComponent}
+      isInProgress={false}
+      isPending={false}
       onToggleProjectInfo={jest.fn()}
       {...props}
     />
index e4bd6ee6c20607f7fc98572d87cd05e6e95ae95f..e311796c90bd33a651d5dbe8d1f427bafd239614 100644 (file)
@@ -67,6 +67,7 @@ exports[`renders 1`] = `
     />
   </div>
   <Connect(withAppState(Menu))
+    branchLikes={Array []}
     component={
       Object {
         "breadcrumbs": Array [
@@ -82,6 +83,8 @@ exports[`renders 1`] = `
         "qualifier": "TRK",
       }
     }
+    isInProgress={true}
+    isPending={true}
     onToggleProjectInfo={[Function]}
   />
   <InfoDrawer
index ddb2ec883ebcfaf6f2a8462c7ecbea40e32a48b2..e57b7935e4b50eb75cff091aa7036b0e83524d83 100644 (file)
@@ -1,5 +1,122 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
+exports[`should disable links if no analysis has been done 1`] = `
+<div
+  className="display-flex-center display-flex-space-between"
+>
+  <NavBarTabs>
+    <li>
+      <Link
+        activeClassName="active"
+        onlyActiveOnIndex={false}
+        style={Object {}}
+        to={
+          Object {
+            "pathname": "/dashboard",
+            "query": Object {
+              "id": "foo",
+            },
+          }
+        }
+      >
+        overview.page
+      </Link>
+    </li>
+    <li>
+      <MenuLink
+        activeClassName="active"
+        hasAnalysis={false}
+        label="issues.page"
+        to={
+          Object {
+            "pathname": "/project/issues",
+            "query": Object {
+              "id": "foo",
+              "resolved": "false",
+            },
+          }
+        }
+      />
+    </li>
+    <li>
+      <MenuLink
+        activeClassName="active"
+        hasAnalysis={false}
+        label="layout.security_hotspots"
+        to={
+          Object {
+            "pathname": "/security_hotspots",
+            "query": Object {
+              "id": "foo",
+            },
+          }
+        }
+      />
+    </li>
+    <li>
+      <MenuLink
+        activeClassName="active"
+        hasAnalysis={false}
+        label="layout.measures"
+        to={
+          Object {
+            "pathname": "/component_measures",
+            "query": Object {
+              "id": "foo",
+            },
+          }
+        }
+      />
+    </li>
+    <li>
+      <MenuLink
+        activeClassName="active"
+        hasAnalysis={false}
+        label="code.page"
+        to={
+          Object {
+            "pathname": "/code",
+            "query": Object {
+              "id": "foo",
+            },
+          }
+        }
+      />
+    </li>
+    <li>
+      <MenuLink
+        activeClassName="active"
+        hasAnalysis={false}
+        label="project_activity.page"
+        to={
+          Object {
+            "pathname": "/project/activity",
+            "query": Object {
+              "id": "foo",
+            },
+          }
+        }
+      />
+    </li>
+  </NavBarTabs>
+  <NavBarTabs>
+    <li>
+      <a
+        className="menu-button"
+        onClick={[Function]}
+        role="button"
+        tabIndex={0}
+      >
+        <BulletListIcon
+          className="little-spacer-right"
+        />
+        project.info.title
+      </a>
+    </li>
+  </NavBarTabs>
+</div>
+`;
+
 exports[`should render correctly for security extensions 1`] = `
 <Dropdown
   data-test="extensions"
@@ -59,10 +176,10 @@ exports[`should work for a branch 1`] = `
       </Link>
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="issues.page"
         to={
           Object {
             "pathname": "/project/issues",
@@ -73,15 +190,13 @@ exports[`should work for a branch 1`] = `
             },
           }
         }
-      >
-        issues.page
-      </Link>
+      />
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="layout.security_hotspots"
         to={
           Object {
             "pathname": "/security_hotspots",
@@ -91,15 +206,13 @@ exports[`should work for a branch 1`] = `
             },
           }
         }
-      >
-        layout.security_hotspots
-      </Link>
+      />
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="layout.measures"
         to={
           Object {
             "pathname": "/component_measures",
@@ -109,15 +222,13 @@ exports[`should work for a branch 1`] = `
             },
           }
         }
-      >
-        layout.measures
-      </Link>
+      />
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="code.page"
         to={
           Object {
             "pathname": "/code",
@@ -127,15 +238,13 @@ exports[`should work for a branch 1`] = `
             },
           }
         }
-      >
-        code.page
-      </Link>
+      />
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="project_activity.page"
         to={
           Object {
             "pathname": "/project/activity",
@@ -145,9 +254,7 @@ exports[`should work for a branch 1`] = `
             },
           }
         }
-      >
-        project_activity.page
-      </Link>
+      />
     </li>
   </NavBarTabs>
   <NavBarTabs>
@@ -294,10 +401,10 @@ exports[`should work for a branch 2`] = `
       </Link>
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="issues.page"
         to={
           Object {
             "pathname": "/project/issues",
@@ -308,15 +415,13 @@ exports[`should work for a branch 2`] = `
             },
           }
         }
-      >
-        issues.page
-      </Link>
+      />
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="layout.security_hotspots"
         to={
           Object {
             "pathname": "/security_hotspots",
@@ -326,15 +431,13 @@ exports[`should work for a branch 2`] = `
             },
           }
         }
-      >
-        layout.security_hotspots
-      </Link>
+      />
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="layout.measures"
         to={
           Object {
             "pathname": "/component_measures",
@@ -344,15 +447,13 @@ exports[`should work for a branch 2`] = `
             },
           }
         }
-      >
-        layout.measures
-      </Link>
+      />
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="code.page"
         to={
           Object {
             "pathname": "/code",
@@ -362,15 +463,13 @@ exports[`should work for a branch 2`] = `
             },
           }
         }
-      >
-        code.page
-      </Link>
+      />
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="project_activity.page"
         to={
           Object {
             "pathname": "/project/activity",
@@ -380,9 +479,7 @@ exports[`should work for a branch 2`] = `
             },
           }
         }
-      >
-        project_activity.page
-      </Link>
+      />
     </li>
   </NavBarTabs>
   <NavBarTabs>
@@ -426,10 +523,10 @@ exports[`should work for all qualifiers 1`] = `
       </Link>
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="issues.page"
         to={
           Object {
             "pathname": "/project/issues",
@@ -439,15 +536,13 @@ exports[`should work for all qualifiers 1`] = `
             },
           }
         }
-      >
-        issues.page
-      </Link>
+      />
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="layout.security_hotspots"
         to={
           Object {
             "pathname": "/security_hotspots",
@@ -456,15 +551,13 @@ exports[`should work for all qualifiers 1`] = `
             },
           }
         }
-      >
-        layout.security_hotspots
-      </Link>
+      />
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="layout.measures"
         to={
           Object {
             "pathname": "/component_measures",
@@ -473,15 +566,13 @@ exports[`should work for all qualifiers 1`] = `
             },
           }
         }
-      >
-        layout.measures
-      </Link>
+      />
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="code.page"
         to={
           Object {
             "pathname": "/code",
@@ -490,15 +581,13 @@ exports[`should work for all qualifiers 1`] = `
             },
           }
         }
-      >
-        code.page
-      </Link>
+      />
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="project_activity.page"
         to={
           Object {
             "pathname": "/project/activity",
@@ -507,9 +596,7 @@ exports[`should work for all qualifiers 1`] = `
             },
           }
         }
-      >
-        project_activity.page
-      </Link>
+      />
     </li>
   </NavBarTabs>
   <NavBarTabs>
@@ -650,10 +737,10 @@ exports[`should work for all qualifiers 2`] = `
       </Link>
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="issues.page"
         to={
           Object {
             "pathname": "/project/issues",
@@ -663,15 +750,13 @@ exports[`should work for all qualifiers 2`] = `
             },
           }
         }
-      >
-        issues.page
-      </Link>
+      />
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="layout.measures"
         to={
           Object {
             "pathname": "/component_measures",
@@ -680,15 +765,13 @@ exports[`should work for all qualifiers 2`] = `
             },
           }
         }
-      >
-        layout.measures
-      </Link>
+      />
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="view_projects.page"
         to={
           Object {
             "pathname": "/code",
@@ -697,15 +780,13 @@ exports[`should work for all qualifiers 2`] = `
             },
           }
         }
-      >
-        view_projects.page
-      </Link>
+      />
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="project_activity.page"
         to={
           Object {
             "pathname": "/project/activity",
@@ -714,9 +795,7 @@ exports[`should work for all qualifiers 2`] = `
             },
           }
         }
-      >
-        project_activity.page
-      </Link>
+      />
     </li>
   </NavBarTabs>
   <NavBarTabs>
@@ -776,10 +855,10 @@ exports[`should work for all qualifiers 3`] = `
       </Link>
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="issues.page"
         to={
           Object {
             "pathname": "/project/issues",
@@ -789,15 +868,13 @@ exports[`should work for all qualifiers 3`] = `
             },
           }
         }
-      >
-        issues.page
-      </Link>
+      />
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="layout.measures"
         to={
           Object {
             "pathname": "/component_measures",
@@ -806,15 +883,13 @@ exports[`should work for all qualifiers 3`] = `
             },
           }
         }
-      >
-        layout.measures
-      </Link>
+      />
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="view_projects.page"
         to={
           Object {
             "pathname": "/code",
@@ -823,15 +898,13 @@ exports[`should work for all qualifiers 3`] = `
             },
           }
         }
-      >
-        view_projects.page
-      </Link>
+      />
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="project_activity.page"
         to={
           Object {
             "pathname": "/project/activity",
@@ -840,9 +913,7 @@ exports[`should work for all qualifiers 3`] = `
             },
           }
         }
-      >
-        project_activity.page
-      </Link>
+      />
     </li>
   </NavBarTabs>
   <NavBarTabs />
@@ -872,10 +943,10 @@ exports[`should work for all qualifiers 4`] = `
       </Link>
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="issues.page"
         to={
           Object {
             "pathname": "/project/issues",
@@ -885,15 +956,13 @@ exports[`should work for all qualifiers 4`] = `
             },
           }
         }
-      >
-        issues.page
-      </Link>
+      />
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="layout.security_hotspots"
         to={
           Object {
             "pathname": "/security_hotspots",
@@ -902,15 +971,13 @@ exports[`should work for all qualifiers 4`] = `
             },
           }
         }
-      >
-        layout.security_hotspots
-      </Link>
+      />
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="layout.measures"
         to={
           Object {
             "pathname": "/component_measures",
@@ -919,15 +986,13 @@ exports[`should work for all qualifiers 4`] = `
             },
           }
         }
-      >
-        layout.measures
-      </Link>
+      />
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="view_projects.page"
         to={
           Object {
             "pathname": "/code",
@@ -936,15 +1001,13 @@ exports[`should work for all qualifiers 4`] = `
             },
           }
         }
-      >
-        view_projects.page
-      </Link>
+      />
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="project_activity.page"
         to={
           Object {
             "pathname": "/project/activity",
@@ -953,9 +1016,7 @@ exports[`should work for all qualifiers 4`] = `
             },
           }
         }
-      >
-        project_activity.page
-      </Link>
+      />
     </li>
   </NavBarTabs>
   <NavBarTabs>
@@ -1029,10 +1090,10 @@ exports[`should work for pull requests 1`] = `
       </Link>
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="issues.page"
         to={
           Object {
             "pathname": "/project/issues",
@@ -1043,15 +1104,13 @@ exports[`should work for pull requests 1`] = `
             },
           }
         }
-      >
-        issues.page
-      </Link>
+      />
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="layout.security_hotspots"
         to={
           Object {
             "pathname": "/security_hotspots",
@@ -1061,15 +1120,13 @@ exports[`should work for pull requests 1`] = `
             },
           }
         }
-      >
-        layout.security_hotspots
-      </Link>
+      />
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="layout.measures"
         to={
           Object {
             "pathname": "/component_measures",
@@ -1079,15 +1136,13 @@ exports[`should work for pull requests 1`] = `
             },
           }
         }
-      >
-        layout.measures
-      </Link>
+      />
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="code.page"
         to={
           Object {
             "pathname": "/code",
@@ -1097,9 +1152,7 @@ exports[`should work for pull requests 1`] = `
             },
           }
         }
-      >
-        code.page
-      </Link>
+      />
     </li>
   </NavBarTabs>
   <NavBarTabs />
@@ -1130,10 +1183,10 @@ exports[`should work for pull requests 2`] = `
       </Link>
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="issues.page"
         to={
           Object {
             "pathname": "/project/issues",
@@ -1144,15 +1197,13 @@ exports[`should work for pull requests 2`] = `
             },
           }
         }
-      >
-        issues.page
-      </Link>
+      />
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="layout.security_hotspots"
         to={
           Object {
             "pathname": "/security_hotspots",
@@ -1162,15 +1213,13 @@ exports[`should work for pull requests 2`] = `
             },
           }
         }
-      >
-        layout.security_hotspots
-      </Link>
+      />
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="layout.measures"
         to={
           Object {
             "pathname": "/component_measures",
@@ -1180,15 +1229,13 @@ exports[`should work for pull requests 2`] = `
             },
           }
         }
-      >
-        layout.measures
-      </Link>
+      />
     </li>
     <li>
-      <Link
+      <MenuLink
         activeClassName="active"
-        onlyActiveOnIndex={false}
-        style={Object {}}
+        hasAnalysis={true}
+        label="code.page"
         to={
           Object {
             "pathname": "/code",
@@ -1198,9 +1245,7 @@ exports[`should work for pull requests 2`] = `
             },
           }
         }
-      >
-        code.page
-      </Link>
+      />
     </li>
   </NavBarTabs>
   <NavBarTabs />
index 54e43cc737870f7a66cba4d811d731ebab48c75b..1a059e1664a8b6f533d0202c995f15427d19d0e7 100644 (file)
@@ -483,6 +483,7 @@ layout.settings.VW=Portfolio Settings
 layout.settings.SVW=Portfolio Settings
 layout.security_reports=Security Reports
 layout.sonar.slogan=Continuous Code Quality
+layout.must_be_configured=This will be available once your project is configured and analyzed.
 
 sidebar.projects=Projects
 sidebar.project_settings=Configuration