]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-11476 Stop supporting homepage and other space pages for modules and directorie...
authorStas Vilchik <stas.vilchik@sonarsource.com>
Thu, 15 Nov 2018 12:53:30 +0000 (13:53 +0100)
committersonartech <sonartech@sonarsource.com>
Wed, 16 Jan 2019 08:43:00 +0000 (09:43 +0100)
25 files changed:
server/sonar-web/src/main/js/app/components/ComponentContainer.tsx
server/sonar-web/src/main/js/app/components/__tests__/ComponentContainer-test.tsx
server/sonar-web/src/main/js/app/components/nav/component/ComponentNavHeader.tsx
server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMenu.tsx
server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavMenu-test.tsx
server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMenu-test.tsx.snap
server/sonar-web/src/main/js/app/components/search/Search.tsx
server/sonar-web/src/main/js/app/components/search/SearchResult.tsx
server/sonar-web/src/main/js/apps/code/components/Component.tsx
server/sonar-web/src/main/js/apps/code/components/ComponentLink.tsx [deleted file]
server/sonar-web/src/main/js/apps/component-measures/drilldown/TreeMapView.tsx
server/sonar-web/src/main/js/apps/issues/components/App.tsx
server/sonar-web/src/main/js/apps/issues/components/ComponentBreadcrumbs.tsx
server/sonar-web/src/main/js/apps/issues/components/ListItem.tsx
server/sonar-web/src/main/js/apps/issues/components/__tests__/ComponentBreadcrumbs-test.tsx
server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/ComponentBreadcrumbs-test.tsx.snap
server/sonar-web/src/main/js/apps/overview/components/App.tsx
server/sonar-web/src/main/js/apps/overview/components/__tests__/App-test.tsx
server/sonar-web/src/main/js/components/SourceViewer/SourceViewerHeader.tsx
server/sonar-web/src/main/js/components/SourceViewer/components/DuplicationPopup.tsx
server/sonar-web/src/main/js/components/SourceViewer/components/MeasuresOverlay.tsx
server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/MeasuresOverlay-test.tsx.snap
server/sonar-web/src/main/js/components/SourceViewer/styles.css
server/sonar-web/src/main/js/store/rootActions.ts
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index 1a930674094e921feec98006d01c9cf6f935630c..2defb5847f90b6bfe84bf7f7e742a4b729ce90c6 100644 (file)
@@ -23,13 +23,12 @@ import { differenceBy } from 'lodash';
 import { ComponentContext } from './ComponentContext';
 import ComponentContainerNotFound from './ComponentContainerNotFound';
 import ComponentNav from './nav/component/ComponentNav';
-import handleRequiredAuthorization from '../utils/handleRequiredAuthorization';
 import { getBranches, getPullRequests } from '../../api/branches';
 import { getTasksForComponent, getAnalysisStatus } from '../../api/ce';
 import { getComponentData } from '../../api/components';
 import { getMeasures } from '../../api/measures';
 import { getComponentNavigation } from '../../api/nav';
-import { fetchOrganization } from '../../store/rootActions';
+import { fetchOrganization, requireAuthorization } from '../../store/rootActions';
 import { STATUSES } from '../../apps/background-tasks/constants';
 import {
   isPullRequest,
@@ -39,15 +38,15 @@ import {
   isShortLivingBranch,
   getBranchLikeQuery
 } from '../../helpers/branches';
-import { Store, getAppState } from '../../store/rootReducer';
+import { isSonarCloud } from '../../helpers/system';
+import { withRouter, Router, Location } from '../../components/hoc/withRouter';
 
 interface Props {
-  appState: Pick<T.AppState, 'organizationsEnabled'>;
-  children: any;
+  children: React.ReactElement<any>;
   fetchOrganization: (organization: string) => void;
-  location: {
-    query: { branch?: string; id: string; pullRequest?: string };
-  };
+  location: Pick<Location, 'query'>;
+  requireAuthorization: (router: Pick<Router, 'replace'>) => void;
+  router: Pick<Router, 'replace'>;
 }
 
 interface State {
@@ -74,13 +73,13 @@ export class ComponentContainer extends React.PureComponent<Props, State> {
     this.fetchComponent();
   }
 
-  componentWillReceiveProps(nextProps: Props) {
+  componentDidUpdate(prevProps: Props) {
     if (
-      nextProps.location.query.id !== this.props.location.query.id ||
-      nextProps.location.query.branch !== this.props.location.query.branch ||
-      nextProps.location.query.pullRequest !== this.props.location.query.pullRequest
+      prevProps.location.query.id !== this.props.location.query.id ||
+      prevProps.location.query.branch !== this.props.location.query.branch ||
+      prevProps.location.query.pullRequest !== this.props.location.query.pullRequest
     ) {
-      this.fetchComponent(nextProps);
+      this.fetchComponent();
     }
   }
 
@@ -94,16 +93,16 @@ export class ComponentContainer extends React.PureComponent<Props, State> {
     qualifier: component.breadcrumbs[component.breadcrumbs.length - 1].qualifier
   });
 
-  fetchComponent(props = this.props) {
-    const { branch, id: key, pullRequest } = props.location.query;
+  fetchComponent() {
+    const { branch, id: key, pullRequest } = this.props.location.query;
     this.setState({ loading: true });
 
     const onError = (response?: Response) => {
       if (this.mounted) {
         if (response && response.status === 403) {
-          handleRequiredAuthorization();
+          this.props.requireAuthorization(this.props.router);
         } else {
-          this.setState({ loading: false });
+          this.setState({ component: undefined, loading: false });
         }
       }
     };
@@ -115,7 +114,7 @@ export class ComponentContainer extends React.PureComponent<Props, State> {
       .then(([nav, data]) => {
         const component = this.addQualifier({ ...nav, ...data });
 
-        if (this.props.appState.organizationsEnabled) {
+        if (isSonarCloud()) {
           this.props.fetchOrganization(component.organization);
         }
         return component;
@@ -375,13 +374,11 @@ export class ComponentContainer extends React.PureComponent<Props, State> {
   }
 }
 
-const mapStateToProps = (state: Store) => ({
-  appState: getAppState(state)
-});
-
-const mapDispatchToProps = { fetchOrganization };
+const mapDispatchToProps = { fetchOrganization, requireAuthorization };
 
-export default connect(
-  mapStateToProps,
-  mapDispatchToProps
-)(ComponentContainer);
+export default withRouter(
+  connect(
+    null,
+    mapDispatchToProps
+  )(ComponentContainer)
+);
index 9ff0b296b62f65773b7801fd439be1ee7e8541a4..8a4f6a2afacf011340cdffeb190720b6c32c032e 100644 (file)
@@ -18,7 +18,8 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
-import { shallow, mount } from 'enzyme';
+import { shallow } from 'enzyme';
+import { Location } from 'history';
 import { ComponentContainer } from '../ComponentContainer';
 import { getBranches, getPullRequests } from '../../../api/branches';
 import { getTasksForComponent } from '../../../api/ce';
@@ -27,6 +28,7 @@ import { getComponentNavigation } from '../../../api/nav';
 import { STATUSES } from '../../../apps/background-tasks/constants';
 import { waitAndUpdate } from '../../../helpers/testUtils';
 import { getMeasures } from '../../../api/measures';
+import { isSonarCloud } from '../../../helpers/system';
 
 jest.mock('../../../api/branches', () => ({
   getBranches: jest.fn().mockResolvedValue([]),
@@ -58,6 +60,10 @@ jest.mock('../../../api/nav', () => ({
   })
 }));
 
+jest.mock('../../../helpers/system', () => ({
+  isSonarCloud: jest.fn()
+}));
+
 // mock this, because some of its children are using redux store
 jest.mock('../nav/component/ComponentNav', () => ({
   default: () => null
@@ -65,6 +71,8 @@ jest.mock('../nav/component/ComponentNav', () => ({
 
 const Inner = () => <div />;
 
+const mainBranch: T.MainBranch = { isMain: true, name: 'master' };
+
 beforeEach(() => {
   (getBranches as jest.Mock).mockClear();
   (getPullRequests as jest.Mock).mockClear();
@@ -72,18 +80,11 @@ beforeEach(() => {
   (getComponentNavigation as jest.Mock).mockClear();
   (getTasksForComponent as jest.Mock).mockClear();
   (getMeasures as jest.Mock).mockClear();
+  (isSonarCloud as jest.Mock).mockReturnValue(false).mockClear();
 });
 
 it('changes component', () => {
-  const wrapper = shallow<ComponentContainer>(
-    <ComponentContainer
-      appState={{ organizationsEnabled: false }}
-      fetchOrganization={jest.fn()}
-      location={{ query: { id: 'foo' } }}>
-      <Inner />
-    </ComponentContainer>
-  );
-  wrapper.instance().mounted = true;
+  const wrapper = shallowRender();
   wrapper.setState({
     branchLikes: [{ isMain: true, name: 'master' }],
     component: { qualifier: 'TRK', visibility: 'public' } as T.Component,
@@ -94,40 +95,8 @@ it('changes component', () => {
   expect(wrapper.state().component).toEqual({ qualifier: 'TRK', visibility: 'private' });
 });
 
-it("loads branches for module's project", async () => {
-  (getComponentNavigation as jest.Mock<any>).mockResolvedValueOnce({
-    breadcrumbs: [
-      { key: 'projectKey', name: 'project', qualifier: 'TRK' },
-      { key: 'moduleKey', name: 'module', qualifier: 'BRC' }
-    ]
-  });
-
-  mount(
-    <ComponentContainer
-      appState={{ organizationsEnabled: false }}
-      fetchOrganization={jest.fn()}
-      location={{ query: { id: 'moduleKey' } }}>
-      <Inner />
-    </ComponentContainer>
-  );
-
-  await new Promise(setImmediate);
-  expect(getBranches).toBeCalledWith('projectKey');
-  expect(getPullRequests).toBeCalledWith('projectKey');
-  expect(getComponentData).toBeCalledWith({ component: 'moduleKey', branch: undefined });
-  expect(getComponentNavigation).toBeCalledWith({ component: 'moduleKey', branch: undefined });
-});
-
 it("doesn't load branches portfolio", async () => {
-  const wrapper = mount(
-    <ComponentContainer
-      appState={{ organizationsEnabled: false }}
-      fetchOrganization={jest.fn()}
-      location={{ query: { id: 'portfolioKey' } }}>
-      <Inner />
-    </ComponentContainer>
-  );
-
+  const wrapper = shallowRender({ location: { query: { id: 'portfolioKey' } } as Location });
   await new Promise(setImmediate);
   expect(getBranches).not.toBeCalled();
   expect(getPullRequests).not.toBeCalled();
@@ -138,21 +107,15 @@ it("doesn't load branches portfolio", async () => {
 });
 
 it('updates branches on change', () => {
-  const wrapper = shallow(
-    <ComponentContainer
-      appState={{ organizationsEnabled: false }}
-      fetchOrganization={jest.fn()}
-      location={{ query: { id: 'portfolioKey' } }}>
-      <Inner />
-    </ComponentContainer>
-  );
-  (wrapper.instance() as ComponentContainer).mounted = true;
+  const wrapper = shallowRender({ location: { query: { id: 'portfolioKey' } } as Location });
   wrapper.setState({
-    branches: [{ isMain: true }],
-    component: { breadcrumbs: [{ key: 'projectKey', name: 'project', qualifier: 'TRK' }] },
+    branchLikes: [mainBranch],
+    component: {
+      breadcrumbs: [{ key: 'projectKey', name: 'project', qualifier: 'TRK' }]
+    } as T.Component,
     loading: false
   });
-  (wrapper.find(Inner).prop('onBranchesChange') as Function)();
+  wrapper.find(Inner).prop<Function>('onBranchesChange')();
   expect(getBranches).toBeCalledWith('projectKey');
   expect(getPullRequests).toBeCalledWith('projectKey');
 });
@@ -166,18 +129,12 @@ it('updates the branch measures', async () => {
     { isMain: false, mergeBranch: 'master', name: 'feature', type: 'SHORT' }
   ]);
   (getPullRequests as jest.Mock<any>).mockResolvedValueOnce([]);
-  const wrapper = shallow(
-    <ComponentContainer
-      appState={{ organizationsEnabled: false }}
-      fetchOrganization={jest.fn()}
-      location={{ query: { id: 'foo', branch: 'feature' } }}>
-      <Inner />
-    </ComponentContainer>
-  );
-  (wrapper.instance() as ComponentContainer).mounted = true;
+  const wrapper = shallowRender({
+    location: { query: { id: 'foo', branch: 'feature' } } as Location
+  });
   wrapper.setState({
-    branches: [{ isMain: true }],
-    component: { breadcrumbs: [{ key: 'foo', name: 'Foo', qualifier: 'TRK' }] },
+    branchLikes: [mainBranch],
+    component: { breadcrumbs: [{ key: 'foo', name: 'Foo', qualifier: 'TRK' }] } as T.Component,
     loading: false
   });
 
@@ -193,18 +150,11 @@ it('updates the branch measures', async () => {
 });
 
 it('loads organization', async () => {
+  (isSonarCloud as jest.Mock).mockReturnValue(true);
   (getComponentData as jest.Mock<any>).mockResolvedValueOnce({ organization: 'org' });
 
   const fetchOrganization = jest.fn();
-  mount(
-    <ComponentContainer
-      appState={{ organizationsEnabled: true }}
-      fetchOrganization={fetchOrganization}
-      location={{ query: { id: 'foo' } }}>
-      <Inner />
-    </ComponentContainer>
-  );
-
+  shallowRender({ fetchOrganization });
   await new Promise(setImmediate);
   expect(fetchOrganization).toBeCalledWith('org');
 });
@@ -212,30 +162,14 @@ it('loads organization', async () => {
 it('fetches status', async () => {
   (getComponentData as jest.Mock<any>).mockResolvedValueOnce({ organization: 'org' });
 
-  mount(
-    <ComponentContainer
-      appState={{ organizationsEnabled: true }}
-      fetchOrganization={jest.fn()}
-      location={{ query: { id: 'foo' } }}>
-      <Inner />
-    </ComponentContainer>
-  );
-
+  shallowRender();
   await new Promise(setImmediate);
   expect(getTasksForComponent).toBeCalledWith('portfolioKey');
 });
 
 it('filters correctly the pending tasks for a main branch', () => {
-  const wrapper = shallow(
-    <ComponentContainer
-      appState={{ organizationsEnabled: false }}
-      fetchOrganization={jest.fn()}
-      location={{ query: { id: 'foo' } }}>
-      <Inner />
-    </ComponentContainer>
-  );
-
-  const component = wrapper.instance() as ComponentContainer;
+  const wrapper = shallowRender();
+  const component = wrapper.instance();
   const mainBranch: T.MainBranch = { isMain: true, name: 'master' };
   const shortBranch: T.ShortLivingBranch = {
     isMain: false,
@@ -294,14 +228,7 @@ it('reload component after task progress finished', async () => {
   jest.useFakeTimers();
   const inProgressTask = { id: 'foo', status: STATUSES.IN_PROGRESS } as T.Task;
   (getTasksForComponent as jest.Mock<any>).mockResolvedValueOnce({ queue: [inProgressTask] });
-  const wrapper = shallow(
-    <ComponentContainer
-      appState={{ organizationsEnabled: false }}
-      fetchOrganization={jest.fn()}
-      location={{ query: { id: 'foo' } }}>
-      <Inner />
-    </ComponentContainer>
-  );
+  const wrapper = shallowRender();
   await waitAndUpdate(wrapper);
   expect(getComponentNavigation).toHaveBeenCalledTimes(1);
   expect(getTasksForComponent).toHaveBeenCalledTimes(1);
@@ -317,3 +244,16 @@ it('reload component after task progress finished', async () => {
   expect(getComponentNavigation).toHaveBeenCalledTimes(2);
   expect(getTasksForComponent).toHaveBeenCalledTimes(3);
 });
+
+function shallowRender(props: Partial<ComponentContainer['props']> = {}) {
+  return shallow<ComponentContainer>(
+    <ComponentContainer
+      fetchOrganization={jest.fn()}
+      location={{ query: { id: 'foo' } }}
+      requireAuthorization={jest.fn()}
+      router={{ replace: jest.fn() }}
+      {...props}>
+      <Inner />
+    </ComponentContainer>
+  );
+}
index f4b2edf188134c7da7172e411333a3c7008db15a..045c005f322cf338310191c6b61d6a79ddf92df5 100644 (file)
@@ -27,7 +27,6 @@ import OrganizationAvatar from '../../../../components/common/OrganizationAvatar
 import OrganizationHelmet from '../../../../components/common/OrganizationHelmet';
 import OrganizationLink from '../../../../components/ui/OrganizationLink';
 import { sanitizeAlmId } from '../../../../helpers/almIntegrations';
-import { collapsePath } from '../../../../helpers/path';
 import { getProjectUrl, getBaseUrl } from '../../../../helpers/urls';
 import { isSonarCloud } from '../../../../helpers/system';
 import { isMainBranch } from '../../../../helpers/branches';
@@ -102,9 +101,6 @@ export function ComponentNavHeader(props: Props) {
 function renderBreadcrumbs(breadcrumbs: T.Breadcrumb[], shouldLinkLast: boolean) {
   const lastItem = breadcrumbs[breadcrumbs.length - 1];
   return breadcrumbs.map((item, index) => {
-    const isPath = item.qualifier === 'DIR';
-    const itemName = isPath ? collapsePath(item.name, 15) : item.name;
-
     return (
       <React.Fragment key={item.key}>
         {index === 0 && <QualifierIcon className="spacer-right" qualifier={lastItem.qualifier} />}
@@ -113,11 +109,11 @@ function renderBreadcrumbs(breadcrumbs: T.Breadcrumb[], shouldLinkLast: boolean)
             className="navbar-context-header-breadcrumb-link link-base-color link-no-underline"
             title={item.name}
             to={getProjectUrl(item.key)}>
-            {itemName}
+            {item.name}
           </Link>
         ) : (
           <span className="navbar-context-header-breadcrumb-link" title={item.name}>
-            {itemName}
+            {item.name}
           </span>
         )}
         {index < breadcrumbs.length - 1 && <span className="slash-separator" />}
index d32dadeaf72a2ad3f94fb084369a08d78e0b98a1..7779297d2f5058cfe0f29089f58b023a70ec5b04 100644 (file)
@@ -182,11 +182,7 @@ export class ComponentNavMenu extends React.PureComponent<Props> {
   }
 
   renderSecurityReports() {
-    const { branchLike, component } = this.props;
-
-    if (component.qualifier === 'BRC' || component.qualifier === 'DIR') {
-      return null;
-    }
+    const { branchLike } = this.props;
 
     if (isShortLivingBranch(branchLike) || isPullRequest(branchLike)) {
       return null;
index 56bbe2cf6776054a4928fa7ac19fa2dd8662f485..f0a4ea8a71fa3b63cd4a230da6d1dc56ed635e1a 100644 (file)
@@ -114,8 +114,8 @@ it('should work for long-living branches', () => {
 });
 
 it('should work for all qualifiers', () => {
-  ['TRK', 'BRC', 'VW', 'SVW', 'APP'].forEach(checkWithQualifier);
-  expect.assertions(5);
+  ['TRK', 'VW', 'SVW', 'APP'].forEach(checkWithQualifier);
+  expect.assertions(4);
 
   function checkWithQualifier(qualifier: string) {
     const component = { ...baseComponent, configuration: { showSettings: true }, qualifier };
index 8be105789fb6c01f160fdf50eb2f6a740611216e..8d1984cd7ebce6db5d6977baa25e0503a5a7dd9a 100644 (file)
@@ -218,127 +218,6 @@ exports[`should work for all qualifiers 1`] = `
 `;
 
 exports[`should work for all qualifiers 2`] = `
-<NavBarTabs>
-  <li>
-    <Link
-      activeClassName="active"
-      onlyActiveOnIndex={false}
-      style={Object {}}
-      to={
-        Object {
-          "pathname": "/dashboard",
-          "query": Object {
-            "id": "foo",
-          },
-        }
-      }
-    >
-      overview.page
-    </Link>
-  </li>
-  <li>
-    <Link
-      activeClassName="active"
-      className=""
-      onlyActiveOnIndex={false}
-      style={Object {}}
-      to={
-        Object {
-          "pathname": "/project/issues",
-          "query": Object {
-            "id": "foo",
-            "resolved": "false",
-          },
-        }
-      }
-    >
-      issues.page
-    </Link>
-  </li>
-  <li>
-    <Link
-      activeClassName="active"
-      onlyActiveOnIndex={false}
-      style={Object {}}
-      to={
-        Object {
-          "pathname": "/component_measures",
-          "query": Object {
-            "id": "foo",
-          },
-        }
-      }
-    >
-      layout.measures
-    </Link>
-  </li>
-  <li>
-    <Link
-      activeClassName="active"
-      onlyActiveOnIndex={false}
-      style={Object {}}
-      to={
-        Object {
-          "pathname": "/code",
-          "query": Object {
-            "id": "foo",
-          },
-        }
-      }
-    >
-      code.page
-    </Link>
-  </li>
-  <li>
-    <Link
-      activeClassName="active"
-      onlyActiveOnIndex={false}
-      style={Object {}}
-      to={
-        Object {
-          "pathname": "/project/activity",
-          "query": Object {
-            "id": "foo",
-          },
-        }
-      }
-    >
-      project_activity.page
-    </Link>
-  </li>
-  <Dropdown
-    data-test="administration"
-    overlay={
-      <ul
-        className="menu"
-      >
-        <li>
-          <Link
-            activeClassName="active"
-            onlyActiveOnIndex={false}
-            style={Object {}}
-            to={
-              Object {
-                "pathname": "/project/settings",
-                "query": Object {
-                  "id": "foo",
-                },
-              }
-            }
-          >
-            project_settings.page
-          </Link>
-        </li>
-      </ul>
-    }
-    tagName="li"
-  >
-    <Component />
-  </Dropdown>
-</NavBarTabs>
-`;
-
-exports[`should work for all qualifiers 3`] = `
 <NavBarTabs>
   <li>
     <Link
@@ -504,7 +383,7 @@ exports[`should work for all qualifiers 3`] = `
 </NavBarTabs>
 `;
 
-exports[`should work for all qualifiers 4`] = `
+exports[`should work for all qualifiers 3`] = `
 <NavBarTabs>
   <li>
     <Link
@@ -641,7 +520,7 @@ exports[`should work for all qualifiers 4`] = `
 </NavBarTabs>
 `;
 
-exports[`should work for all qualifiers 5`] = `
+exports[`should work for all qualifiers 4`] = `
 <NavBarTabs>
   <li>
     <Link
index 7c748507d82039019ab0fbe62fc40c16a4f2c8fc..8fa9aa71747615c00dc8daf5a3a1bad76bbb5b4d 100644 (file)
@@ -33,7 +33,7 @@ import { lazyLoad } from '../../../components/lazyLoad';
 import { getSuggestions } from '../../../api/components';
 import { translate, translateWithParameters } from '../../../helpers/l10n';
 import { scrollToElement } from '../../../helpers/scrolling';
-import { getProjectUrl } from '../../../helpers/urls';
+import { getProjectUrl, getCodeUrl } from '../../../helpers/urls';
 import './Search.css';
 
 const SearchResults = lazyLoad(() => import('./SearchResults'));
@@ -162,13 +162,21 @@ export class Search extends React.PureComponent<Props, State> {
       return next;
     }, []);
 
-  mergeWithRecentlyBrowsed = (components: ComponentResult[]) => {
-    const recentlyBrowsed = RecentHistory.get().map(component => ({
-      ...component,
-      isRecentlyBrowsed: true,
-      qualifier: component.icon.toUpperCase()
-    }));
-    return uniqBy([...components, ...recentlyBrowsed], 'key');
+  findFile = (key: string) => {
+    const findInResults = (results: ComponentResult[] | undefined) =>
+      results && results.find(r => r.key === key);
+
+    const file = findInResults(this.state.results['FIL']);
+    if (file) {
+      return file;
+    }
+
+    const test = findInResults(this.state.results['UTS']);
+    if (test) {
+      return test;
+    }
+
+    return undefined;
   };
 
   stopLoading = () => {
@@ -268,11 +276,17 @@ export class Search extends React.PureComponent<Props, State> {
 
   openSelected = () => {
     const { selected } = this.state;
+
     if (selected) {
       if (selected.startsWith('qualifier###')) {
         this.searchMore(selected.substr(12));
       } else {
-        this.props.router.push(getProjectUrl(selected));
+        const file = this.findFile(selected);
+        if (file) {
+          this.props.router.push(getCodeUrl(file.project!, undefined, file.key));
+        } else {
+          this.props.router.push(getProjectUrl(selected));
+        }
         this.closeSearch();
       }
     }
index a4448fba9eb0e8d632725bf0c972504a12bbad0d..b68ebdceeb4be77d680430ed6ec6a3fc224ec7d3 100644 (file)
@@ -24,7 +24,7 @@ import FavoriteIcon from '../../../components/icons-components/FavoriteIcon';
 import QualifierIcon from '../../../components/icons-components/QualifierIcon';
 import ClockIcon from '../../../components/icons-components/ClockIcon';
 import Tooltip from '../../../components/controls/Tooltip';
-import { getProjectUrl } from '../../../helpers/urls';
+import { getProjectUrl, getCodeUrl } from '../../../helpers/urls';
 
 interface Props {
   appState: Pick<T.AppState, 'organizationsEnabled'>;
@@ -111,6 +111,11 @@ export default class SearchResult extends React.PureComponent<Props, State> {
   render() {
     const { component } = this.props;
 
+    const isFile = component.qualifier === 'FIL' || component.qualifier === 'UTS';
+    const to = isFile
+      ? getCodeUrl(component.project!, undefined, component.key)
+      : getProjectUrl(component.key);
+
     return (
       <li
         className={this.props.selected ? 'active' : undefined}
@@ -121,10 +126,7 @@ export default class SearchResult extends React.PureComponent<Props, State> {
           overlay={component.key}
           placement="left"
           visible={this.state.tooltipVisible}>
-          <Link
-            data-key={component.key}
-            onClick={this.props.onClose}
-            to={getProjectUrl(component.key)}>
+          <Link data-key={component.key} onClick={this.props.onClose} to={to}>
             <span className="navbar-search-item-link" onMouseEnter={this.handleMouseEnter}>
               <span className="navbar-search-item-icons little-spacer-right">
                 {component.isFavorite && <FavoriteIcon favorite={true} size={12} />}
index d6f169868fc9fafe0befd709c67f4de2b4e4981e..e0d9d559e96cea1ee9d8e6465976de6cc2d0aa1d 100644 (file)
@@ -21,7 +21,6 @@ import * as classNames from 'classnames';
 import * as React from 'react';
 import ComponentName from './ComponentName';
 import ComponentMeasure from './ComponentMeasure';
-import ComponentLink from './ComponentLink';
 import ComponentPin from './ComponentPin';
 import { WorkspaceContext } from '../../../components/workspace/context';
 
@@ -85,34 +84,25 @@ export default class Component extends React.PureComponent<Props> {
       selected = false
     } = this.props;
 
-    let componentAction = null;
-
-    if (!component.refKey || component.qualifier === 'SVW') {
-      switch (component.qualifier) {
-        case 'FIL':
-        case 'UTS':
-          componentAction = (
-            <WorkspaceContext.Consumer>
-              {({ openComponent }) => (
-                <ComponentPin
-                  branchLike={branchLike}
-                  component={component}
-                  openComponent={openComponent}
-                />
-              )}
-            </WorkspaceContext.Consumer>
-          );
-          break;
-        default:
-          componentAction = <ComponentLink branchLike={branchLike} component={component} />;
-      }
-    }
+    const isFile = component.qualifier === 'FIL' || component.qualifier === 'UTS';
 
     return (
       <tr className={classNames({ selected })} ref={node => (this.node = node)}>
         <td className="blank" />
         <td className="thin nowrap">
-          <span className="spacer-right">{componentAction}</span>
+          <span className="spacer-right">
+            {isFile && (
+              <WorkspaceContext.Consumer>
+                {({ openComponent }) => (
+                  <ComponentPin
+                    branchLike={branchLike}
+                    component={component}
+                    openComponent={openComponent}
+                  />
+                )}
+              </WorkspaceContext.Consumer>
+            )}
+          </span>
         </td>
         <td className="code-name-cell">
           <ComponentName
diff --git a/server/sonar-web/src/main/js/apps/code/components/ComponentLink.tsx b/server/sonar-web/src/main/js/apps/code/components/ComponentLink.tsx
deleted file mode 100644 (file)
index a876df4..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 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 { Link } from 'react-router';
-import LinkIcon from '../../../components/icons-components/LinkIcon';
-import { translate } from '../../../helpers/l10n';
-import { getBranchLikeUrl } from '../../../helpers/urls';
-
-interface Props {
-  branchLike?: T.BranchLike;
-  component: T.ComponentMeasure;
-}
-
-export default function ComponentLink({ component, branchLike }: Props) {
-  return (
-    <Link
-      className="link-no-underline"
-      title={translate('code.open_component_page')}
-      to={getBranchLikeUrl(component.refKey || component.key, branchLike)}>
-      <LinkIcon />
-    </Link>
-  );
-}
index 2f3328cc2df0c02acc47ecfc00cd7d891e3e0b5e..8993417c32e6e2b00f900182fb294a5b84afd3f2 100644 (file)
@@ -28,7 +28,6 @@ import QualifierIcon from '../../../components/icons-components/QualifierIcon';
 import TreeMap, { TreeMapItem } from '../../../components/charts/TreeMap';
 import { translate, translateWithParameters, getLocalizedMetricName } from '../../../helpers/l10n';
 import { formatMeasure, isDiffMetric } from '../../../helpers/measures';
-import { getBranchLikeUrl } from '../../../helpers/urls';
 import { isDefined } from '../../../helpers/types';
 
 interface Props {
@@ -54,13 +53,13 @@ export default class TreeMapView extends React.PureComponent<Props, State> {
     this.state = { treemapItems: this.getTreemapComponents(props) };
   }
 
-  componentWillReceiveProps(nextProps: Props) {
-    if (nextProps.components !== this.props.components || nextProps.metric !== this.props.metric) {
-      this.setState({ treemapItems: this.getTreemapComponents(nextProps) });
+  componentDidUpdate(prevProps: Props) {
+    if (prevProps.components !== this.props.components || prevProps.metric !== this.props.metric) {
+      this.setState({ treemapItems: this.getTreemapComponents(this.props) });
     }
   }
 
-  getTreemapComponents = ({ branchLike, components, metric }: Props) => {
+  getTreemapComponents = ({ components, metric }: Props) => {
     const colorScale = this.getColorScale(metric);
     return components
       .map(component => {
@@ -85,7 +84,6 @@ export default class TreeMapView extends React.PureComponent<Props, State> {
           icon: <QualifierIcon fill={theme.baseFontColor} qualifier={component.qualifier} />,
           key: component.refKey || component.key,
           label: component.name,
-          link: getBranchLikeUrl(component.refKey || component.key, branchLike),
           size: sizeValue,
           tooltip: this.getTooltip({
             colorMetric: metric,
index c4b7daf7ad923b5f22a44b71ae217cab456a3a31..1bf52ed354b6e25afab1467d00e5e184d6241291 100644 (file)
@@ -1110,7 +1110,6 @@ export class App extends React.PureComponent<Props, State> {
                 {openIssue ? (
                   <div className="pull-left width-60">
                     <ComponentBreadcrumbs
-                      branchLike={this.props.branchLike}
                       component={component}
                       issue={openIssue}
                       organization={this.props.organization}
index 89f45ff96360142efb2ae78ecb9a576235d58e24..7700efb6cf199b0849b6e115ef42d3c88f5f2a51 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
-import { Link } from 'react-router';
 import { getSelectedLocation } from '../utils';
 import Organization from '../../../components/shared/Organization';
 import { collapsePath, limitComponentName } from '../../../helpers/path';
-import { getBranchLikeUrl, getCodeUrl } from '../../../helpers/urls';
 
 interface Props {
-  branchLike?: T.BranchLike;
   component?: T.Component;
   issue: Pick<
     T.Issue,
@@ -46,9 +43,7 @@ interface Props {
 }
 
 export default function ComponentBreadcrumbs({
-  branchLike,
   component,
-  link = true,
   issue,
   organization,
   selectedFlowIndex,
@@ -60,28 +55,15 @@ export default function ComponentBreadcrumbs({
   const displaySubProject = !component || !['BRC', 'DIR'].includes(component.qualifier);
 
   const selectedLocation = getSelectedLocation(issue, selectedFlowIndex, selectedLocationIndex);
-  const componentKey = selectedLocation ? selectedLocation.component : issue.component;
   const componentName = selectedLocation ? selectedLocation.componentName : issue.componentLongName;
 
   return (
     <div className="component-name text-ellipsis">
-      {displayOrganization && (
-        <Organization
-          link={link}
-          linkClassName="link-no-underline"
-          organizationKey={issue.organization}
-        />
-      )}
+      {displayOrganization && <Organization link={false} organizationKey={issue.organization} />}
 
       {displayProject && (
         <span title={issue.projectName}>
-          {link ? (
-            <Link className="link-no-underline" to={getBranchLikeUrl(issue.project, branchLike)}>
-              {limitComponentName(issue.projectName)}
-            </Link>
-          ) : (
-            limitComponentName(issue.projectName)
-          )}
+          {limitComponentName(issue.projectName)}
           <span className="slash-separator" />
         </span>
       )}
@@ -90,28 +72,12 @@ export default function ComponentBreadcrumbs({
         issue.subProject !== undefined &&
         issue.subProjectName !== undefined && (
           <span title={issue.subProjectName}>
-            {link ? (
-              <Link
-                className="link-no-underline"
-                to={getBranchLikeUrl(issue.subProject, branchLike)}>
-                {limitComponentName(issue.subProjectName)}
-              </Link>
-            ) : (
-              limitComponentName(issue.subProjectName)
-            )}
+            {limitComponentName(issue.subProjectName)}
             <span className="slash-separator" />
           </span>
         )}
 
-      {link ? (
-        <Link
-          className="link-no-underline"
-          to={getCodeUrl(issue.project, branchLike, componentKey)}>
-          <span title={componentName}>{collapsePath(componentName || '')}</span>
-        </Link>
-      ) : (
-        collapsePath(componentName || '')
-      )}
+      {collapsePath(componentName || '')}
     </div>
   );
 }
index f9e9eebf2e395a6cb9495451191def34d31bbab9..10c9984972b6f8b2a0b8383d0bebf824dbef12f8 100644 (file)
@@ -105,10 +105,8 @@ export default class ListItem extends React.PureComponent<Props, State> {
         {displayComponent && (
           <div className="issues-workspace-list-component note">
             <ComponentBreadcrumbs
-              branchLike={branchLike}
               component={component}
               issue={this.props.issue}
-              link={false}
               organization={this.props.organization}
             />
           </div>
index e5d36ef83da0df246a11aefe0d2a742d10d7c12f..c5500568c95afbb33646a8fbc5f35c2d133b14ca 100644 (file)
@@ -34,12 +34,7 @@ const baseIssue = {
 it('renders', () => {
   expect(
     shallow(
-      <ComponentBreadcrumbs
-        branchLike={undefined}
-        component={undefined}
-        issue={baseIssue}
-        organization={undefined}
-      />
+      <ComponentBreadcrumbs component={undefined} issue={baseIssue} organization={undefined} />
     )
   ).toMatchSnapshot();
 });
@@ -47,33 +42,6 @@ it('renders', () => {
 it('renders with sub-project', () => {
   const issue = { ...baseIssue, subProject: 'sub-proj', subProjectName: 'sub-proj-name' };
   expect(
-    shallow(
-      <ComponentBreadcrumbs
-        branchLike={undefined}
-        component={undefined}
-        issue={issue}
-        organization={undefined}
-      />
-    )
-  ).toMatchSnapshot();
-});
-
-it('renders with branch', () => {
-  const issue = { ...baseIssue, subProject: 'sub-proj', subProjectName: 'sub-proj-name' };
-  const shortBranch: T.ShortLivingBranch = {
-    isMain: false,
-    mergeBranch: '',
-    name: 'feature',
-    type: 'SHORT'
-  };
-  expect(
-    shallow(
-      <ComponentBreadcrumbs
-        branchLike={shortBranch}
-        component={undefined}
-        issue={issue}
-        organization={undefined}
-      />
-    )
+    shallow(<ComponentBreadcrumbs component={undefined} issue={issue} organization={undefined} />)
   ).toMatchSnapshot();
 });
index dea3a478dcbaa4f0a66c507b544e31a4d77b3967..cdcbc76af08432d322c612c334e59eb1c69b442b 100644 (file)
@@ -5,136 +5,18 @@ exports[`renders 1`] = `
   className="component-name text-ellipsis"
 >
   <Connect(Organization)
-    link={true}
-    linkClassName="link-no-underline"
+    link={false}
     organizationKey="org"
   />
   <span
     title="proj-name"
   >
-    <Link
-      className="link-no-underline"
-      onlyActiveOnIndex={false}
-      style={Object {}}
-      to={
-        Object {
-          "pathname": "/dashboard",
-          "query": Object {
-            "branch": undefined,
-            "id": "proj",
-          },
-        }
-      }
-    >
-      proj-name
-    </Link>
+    proj-name
     <span
       className="slash-separator"
     />
   </span>
-  <Link
-    className="link-no-underline"
-    onlyActiveOnIndex={false}
-    style={Object {}}
-    to={
-      Object {
-        "pathname": "/code",
-        "query": Object {
-          "id": "proj",
-          "line": undefined,
-          "selected": "comp",
-        },
-      }
-    }
-  >
-    <span
-      title="comp-name"
-    >
-      comp-name
-    </span>
-  </Link>
-</div>
-`;
-
-exports[`renders with branch 1`] = `
-<div
-  className="component-name text-ellipsis"
->
-  <Connect(Organization)
-    link={true}
-    linkClassName="link-no-underline"
-    organizationKey="org"
-  />
-  <span
-    title="proj-name"
-  >
-    <Link
-      className="link-no-underline"
-      onlyActiveOnIndex={false}
-      style={Object {}}
-      to={
-        Object {
-          "pathname": "/project/issues",
-          "query": Object {
-            "branch": "feature",
-            "id": "proj",
-            "resolved": "false",
-          },
-        }
-      }
-    >
-      proj-name
-    </Link>
-    <span
-      className="slash-separator"
-    />
-  </span>
-  <span
-    title="sub-proj-name"
-  >
-    <Link
-      className="link-no-underline"
-      onlyActiveOnIndex={false}
-      style={Object {}}
-      to={
-        Object {
-          "pathname": "/project/issues",
-          "query": Object {
-            "branch": "feature",
-            "id": "sub-proj",
-            "resolved": "false",
-          },
-        }
-      }
-    >
-      sub-proj-name
-    </Link>
-    <span
-      className="slash-separator"
-    />
-  </span>
-  <Link
-    className="link-no-underline"
-    onlyActiveOnIndex={false}
-    style={Object {}}
-    to={
-      Object {
-        "pathname": "/code",
-        "query": Object {
-          "branch": "feature",
-          "id": "proj",
-          "line": undefined,
-          "selected": "comp",
-        },
-      }
-    }
-  >
-    <span
-      title="comp-name"
-    >
-      comp-name
-    </span>
-  </Link>
+  comp-name
 </div>
 `;
 
@@ -143,29 +25,13 @@ exports[`renders with sub-project 1`] = `
   className="component-name text-ellipsis"
 >
   <Connect(Organization)
-    link={true}
-    linkClassName="link-no-underline"
+    link={false}
     organizationKey="org"
   />
   <span
     title="proj-name"
   >
-    <Link
-      className="link-no-underline"
-      onlyActiveOnIndex={false}
-      style={Object {}}
-      to={
-        Object {
-          "pathname": "/dashboard",
-          "query": Object {
-            "branch": undefined,
-            "id": "proj",
-          },
-        }
-      }
-    >
-      proj-name
-    </Link>
+    proj-name
     <span
       className="slash-separator"
     />
@@ -173,46 +39,11 @@ exports[`renders with sub-project 1`] = `
   <span
     title="sub-proj-name"
   >
-    <Link
-      className="link-no-underline"
-      onlyActiveOnIndex={false}
-      style={Object {}}
-      to={
-        Object {
-          "pathname": "/dashboard",
-          "query": Object {
-            "branch": undefined,
-            "id": "sub-proj",
-          },
-        }
-      }
-    >
-      sub-proj-name
-    </Link>
+    sub-proj-name
     <span
       className="slash-separator"
     />
   </span>
-  <Link
-    className="link-no-underline"
-    onlyActiveOnIndex={false}
-    style={Object {}}
-    to={
-      Object {
-        "pathname": "/code",
-        "query": Object {
-          "id": "proj",
-          "line": undefined,
-          "selected": "comp",
-        },
-      }
-    }
-  >
-    <span
-      title="comp-name"
-    >
-      comp-name
-    </span>
-  </Link>
+  comp-name
 </div>
 `;
index cb512ab988db870d40ca062b0c0a27b0c1698919..91200b7823b7a16e942043ce127dfb06cdeff365 100644 (file)
@@ -26,7 +26,6 @@ import Suggestions from '../../../app/components/embed-docs-modal/Suggestions';
 import { isShortLivingBranch } from '../../../helpers/branches';
 import {
   getShortLivingBranchUrl,
-  getCodeUrl,
   getProjectUrl,
   getBaseUrl,
   getPathUrlAsString
@@ -53,10 +52,6 @@ export class App extends React.PureComponent<Props> {
         pathname: '/portfolio',
         query: { id: component.key }
       });
-    } else if (this.isFile()) {
-      this.props.router.replace(
-        getCodeUrl(component.breadcrumbs[0].key, branchLike, component.key)
-      );
     } else if (isShortLivingBranch(branchLike)) {
       this.props.router.replace(getShortLivingBranchUrl(component.key, branchLike.name));
     }
@@ -64,12 +59,10 @@ export class App extends React.PureComponent<Props> {
 
   isPortfolio = () => ['VW', 'SVW'].includes(this.props.component.qualifier);
 
-  isFile = () => ['FIL', 'UTS'].includes(this.props.component.qualifier);
-
   render() {
     const { branchLike, branchLikes, component } = this.props;
 
-    if (this.isPortfolio() || this.isFile() || isShortLivingBranch(branchLike)) {
+    if (this.isPortfolio() || isShortLivingBranch(branchLike)) {
       return null;
     }
 
index fae3599fdb2e3fc2476ce9ae79833ccd3c8326f4..82ff84e04708a572b310b7048ff4bb0cf4356e04 100644 (file)
@@ -18,7 +18,7 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
-import { mount, shallow } from 'enzyme';
+import { shallow } from 'enzyme';
 import { App } from '../App';
 import { isSonarCloud } from '../../../../helpers/system';
 
@@ -64,33 +64,7 @@ it('should render SonarCloudEmptyOverview', () => {
   ).toBeTruthy();
 });
 
-it('redirects on Code page for files', () => {
-  const branch: T.LongLivingBranch = { isMain: false, name: 'b', type: 'LONG' };
-  const newComponent = {
-    ...component,
-    breadcrumbs: [
-      { key: 'project', name: 'Project', qualifier: 'TRK' },
-      { key: 'foo', name: 'Foo', qualifier: 'DIR' }
-    ],
-    qualifier: 'FIL'
-  };
-  const replace = jest.fn();
-  mount(
-    <App
-      branchLike={branch}
-      branchLikes={[branch]}
-      component={newComponent}
-      onComponentChange={jest.fn()}
-      router={{ replace }}
-    />
-  );
-  expect(replace).toBeCalledWith({
-    pathname: '/code',
-    query: { branch: 'b', id: 'project', selected: 'foo' }
-  });
-});
-
-function getWrapper(props: Partial<App['props']> = {}) {
+function getWrapper(props = {}) {
   return shallow(
     <App
       branchLikes={[]}
index bd11c8c615d075fa6db6a83b33470bd855cb7a39..385312ac53d0554d08ca08f6886ed9e15c78dec9 100644 (file)
@@ -103,11 +103,7 @@ export default class SourceViewerHeader extends React.PureComponent<Props, State
 
             {subProject != null && (
               <div className="component-name-parent">
-                <a
-                  className="link-with-icon"
-                  href={getPathUrlAsString(getBranchLikeUrl(subProject, this.props.branchLike))}>
-                  <QualifierIcon qualifier="BRC" /> <span>{subProjectName}</span>
-                </a>
+                <QualifierIcon qualifier="BRC" /> <span>{subProjectName}</span>
               </div>
             )}
 
index a2dcfde6996c6043ec5b41d325e9a5502ae7e032..295ce16edc75dc83463a44b035209c9d6209ba46 100644 (file)
@@ -132,9 +132,7 @@ export default class DuplicationPopup extends React.PureComponent<Props> {
                           duplication.file.subProjectName && (
                             <div className="component-name-parent">
                               <QualifierIcon className="little-spacer-right" qualifier="BRC" />
-                              <Link to={getProjectUrl(duplication.file.subProject)}>
-                                {duplication.file.subProjectName}
-                              </Link>
+                              {duplication.file.subProjectName}
                             </div>
                           )}
                       </>
index e21e975f1ff1e21708d1bd21dfc8cfe42452781e..4f078bda1e82b4c2ada9bd469dba8f5fe1a9ef28 100644 (file)
@@ -400,14 +400,12 @@ export default class MeasuresOverlay extends React.PureComponent<Props, State> {
               {sourceViewerFile.subProject && (
                 <>
                   <QualifierIcon className="big-spacer-left little-spacer-right" qualifier="BRC" />
-                  <Link to={getBranchLikeUrl(sourceViewerFile.subProject, branchLike)}>
-                    {sourceViewerFile.subProjectName}
-                  </Link>
+                  {sourceViewerFile.subProjectName}
                 </>
               )}
             </div>
 
-            <div className="source-viewer-header-component-name">
+            <div className="source-viewer-header-component-name display-flex-center little-spacer-top">
               <QualifierIcon className="little-spacer-right" qualifier={sourceViewerFile.q} />
               {sourceViewerFile.path}
             </div>
index 46c32fbc0ce35c0a227b8b76fbf32a5dad685d68..a6b23d821770e1ab2510bf3880d533ff4e298d7d 100644 (file)
@@ -39,25 +39,10 @@ exports[`should render source file 1`] = `
           className="big-spacer-left little-spacer-right"
           qualifier="BRC"
         />
-        <Link
-          onlyActiveOnIndex={false}
-          style={Object {}}
-          to={
-            Object {
-              "pathname": "/project/issues",
-              "query": Object {
-                "branch": "feature",
-                "id": "sub-project-key",
-                "resolved": "false",
-              },
-            }
-          }
-        >
-          Sub-Project Name
-        </Link>
+        Sub-Project Name
       </div>
       <div
-        className="source-viewer-header-component-name"
+        className="source-viewer-header-component-name display-flex-center little-spacer-top"
       >
         <QualifierIcon
           className="little-spacer-right"
@@ -414,25 +399,10 @@ exports[`should render source file 2`] = `
           className="big-spacer-left little-spacer-right"
           qualifier="BRC"
         />
-        <Link
-          onlyActiveOnIndex={false}
-          style={Object {}}
-          to={
-            Object {
-              "pathname": "/project/issues",
-              "query": Object {
-                "branch": "feature",
-                "id": "sub-project-key",
-                "resolved": "false",
-              },
-            }
-          }
-        >
-          Sub-Project Name
-        </Link>
+        Sub-Project Name
       </div>
       <div
-        className="source-viewer-header-component-name"
+        className="source-viewer-header-component-name display-flex-center little-spacer-top"
       >
         <QualifierIcon
           className="little-spacer-right"
@@ -1395,25 +1365,10 @@ exports[`should render test file 1`] = `
           className="big-spacer-left little-spacer-right"
           qualifier="BRC"
         />
-        <Link
-          onlyActiveOnIndex={false}
-          style={Object {}}
-          to={
-            Object {
-              "pathname": "/project/issues",
-              "query": Object {
-                "branch": "feature",
-                "id": "sub-project-key",
-                "resolved": "false",
-              },
-            }
-          }
-        >
-          Sub-Project Name
-        </Link>
+        Sub-Project Name
       </div>
       <div
-        className="source-viewer-header-component-name"
+        className="source-viewer-header-component-name display-flex-center little-spacer-top"
       >
         <QualifierIcon
           className="little-spacer-right"
index 8947388c6fc291c2fc2443d58c429143be5dd2bd..6999c412acdf2821ef99e91a139491312cdd2534 100644 (file)
 }
 
 .source-viewer-header-component-project {
-  color: var(--secondFontColor);
   font-size: var(--smallFontSize);
 }
 
 .source-viewer-header-component-name {
-  font-weight: 600;
+  font-size: var(--smallFontSize);
 }
 
 .source-viewer-header-favorite {
index bcbda497bf4f508d13d0b1e78bd310f7ccfaafa3..6bab84e7335b6101d737ff1a31fdf1e349497c81 100644 (file)
@@ -18,6 +18,8 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import { Dispatch } from 'redux';
+import { InjectedRouter } from 'react-router';
+import { requireAuthorization as requireAuthorizationAction } from './appState';
 import { addGlobalErrorMessage } from './globalMessages';
 import { receiveLanguages } from './languages';
 import { receiveMetrics } from './metrics';
@@ -84,3 +86,9 @@ export function doLogout() {
       }
     );
 }
+
+export function requireAuthorization(router: Pick<InjectedRouter, 'replace'>) {
+  const returnTo = window.location.pathname + window.location.search + window.location.hash;
+  router.replace({ pathname: '/sessions/new', query: { return_to: returnTo } });
+  return requireAuthorizationAction();
+}
index e527a0e54d678b72a4d5dc764562bcf2c0878d50..ef551894203fac7ae66fab966f2a7f59f1668faf 100644 (file)
@@ -351,16 +351,9 @@ qualifier.UTS=Test File
 qualifier.DEV=Developer
 
 qualifier.configuration.TRK=Project Configuration
-qualifier.configuration.BRC=Sub-project Configuration
-qualifier.configuration.DIR=Directory Configuration
-qualifier.configuration.PAC=Package Configuration
 qualifier.configuration.VW=Portfolio Configuration
 qualifier.configuration.SVW=Portfolio Configuration
 qualifier.configuration.APP=Application Configuration
-qualifier.configuration.FIL=File Configuration
-qualifier.configuration.CLA=File Configuration
-qualifier.configuration.UTS=Test File Configuration
-qualifier.configuration.DEV=Developer Configuration
 
 qualifiers.TRK=Projects
 qualifiers.BRC=Sub-projects
@@ -2430,17 +2423,11 @@ overview.on_new_code=On New Code
 overview.about_this_portfolio=About This Portfolio
 overview.about_this_project.APP=About This Application
 overview.about_this_project.TRK=About This Project
-overview.about_this_project.BRC=About This Sub-Project
-overview.about_this_project.DIR=About This Directory
 overview.project_activity.APP=Application Activity
 overview.project_activity.TRK=Project Activity
-overview.project_activity.BRC=Sub-Project Activity
-overview.project_activity.DIR=Directory Activity
 overview.external_links=External Links
 overview.project_key.APP=Application Key
 overview.project_key.TRK=Project Key
-overview.project_key.BRC=Sub-Project Key
-overview.project_key.DIR=Directory Key
 
 overview.project.no_lines_of_code=This project as no lines of code.
 overview.project.empty=This project is empty.
@@ -3100,25 +3087,17 @@ homepage.check=Check to make the current page your homepage
 #
 #------------------------------------------------------------------------------
 favorite.check.TRK=Click to mark this project as favorite.
-favorite.check.BRC=Click to mark this sub-project as favorite.
-favorite.check.DIR=Click to mark this directory as favorite.
-favorite.check.PAC=Click to mark this package as favorite.
 favorite.check.VW=Click to mark this portfolio as favorite.
 favorite.check.SVW=Click to mark this sub-ortfolio as favorite.
 favorite.check.APP=Click to mark this application as favorite.
 favorite.check.FIL=Click to mark this file as favorite.
-favorite.check.CLA=Click to mark this file as favorite.
 favorite.check.UTS=Click to mark this test file as favorite.
 
 favorite.current.TRK=This project is marked as favorite.
-favorite.current.BRC=This sub-project is marked as favorite.
-favorite.current.DIR=This directory is marked as favorite.
-favorite.current.PAC=This package is marked as favorite.
 favorite.current.VW=This portfolio is marked as favorite.
 favorite.current.SVW=This sub-ortfolio is marked as favorite.
 favorite.current.APP=This application is marked as favorite.
 favorite.current.FIL=This file is marked as favorite.
-favorite.current.CLA=This file is marked as favorite.
 favorite.current.UTS=This test file is marked as favorite.