]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-10177 Dont rely on router Link in the source code viewer header
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>
Mon, 18 Dec 2017 14:15:54 +0000 (15:15 +0100)
committerGrégoire Aubert <gregoire.aubert@sonarsource.com>
Tue, 19 Dec 2017 08:30:25 +0000 (09:30 +0100)
server/sonar-web/src/main/js/apps/coding-rules/rule/rule-issues-view.js
server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentCell.js
server/sonar-web/src/main/js/components/SourceViewer/SourceViewerHeader.js
server/sonar-web/src/main/js/helpers/__tests__/urls-test.ts
server/sonar-web/src/main/js/helpers/urls.ts

index 74406c29807d8e2292970d97c7901d62e16c34d4..c38c25ea7f6bd225a8779f16e294fc42bec8796a 100644 (file)
@@ -20,7 +20,7 @@
 import Marionette from 'backbone.marionette';
 import Template from '../templates/rule/coding-rules-rule-issues.hbs';
 import { searchIssues } from '../../../api/issues';
-import { getComponentIssuesUrlAsString, getBaseUrl } from '../../../helpers/urls';
+import { getPathUrlAsString, getComponentIssuesUrl, getBaseUrl } from '../../../helpers/urls';
 
 export default Marionette.ItemView.extend({
   template: Template,
@@ -68,10 +68,12 @@ export default Marionette.ItemView.extend({
           name: projectBase != null ? projectBase.longName : '',
           issuesUrl:
             projectBase != null &&
-            getComponentIssuesUrlAsString(projectBase.key, {
-              resolved: 'false',
-              rules: this.model.id
-            })
+            getPathUrlAsString(
+              getComponentIssuesUrl(projectBase.key, {
+                resolved: 'false',
+                rules: this.model.id
+              })
+            )
         };
       });
       this.projects = projects;
index 855c605c5853fdeff9291de041fccf4cf91244d8..b39191261322db077a179c0970eef96a74577e6a 100644 (file)
@@ -21,7 +21,7 @@
 import React from 'react';
 import QualifierIcon from '../../../components/icons-components/QualifierIcon';
 import { splitPath } from '../../../helpers/path';
-import { getComponentUrl } from '../../../helpers/urls';
+import { getPathUrlAsString, getProjectUrl } from '../../../helpers/urls';
 /*:: import type { ComponentEnhanced } from '../types'; */
 
 /*:: type Props = {
@@ -72,7 +72,7 @@ export default class ComponentCell extends React.PureComponent {
             <a
               id={'component-measures-component-link-' + component.key}
               className="link-no-underline"
-              href={getComponentUrl(component.key, branch)}
+              href={getPathUrlAsString(getProjectUrl(component.key, branch))}
               onClick={this.handleClick}>
               {this.renderInner()}
             </a>
@@ -80,7 +80,7 @@ export default class ComponentCell extends React.PureComponent {
             <a
               id={'component-measures-component-link-' + component.key}
               className="link-no-underline"
-              href={getComponentUrl(component.refKey, branch)}>
+              href={getPathUrlAsString(getProjectUrl(component.refKey, branch))}>
               <span className="big-spacer-right">
                 <i className="icon-detach" />
               </span>
index 282f7211b1a7077ea4376ae1929f29c1f045827c..453bc4d3945ebc542b420bee5c1de4e8f8eae842 100644 (file)
  */
 // @flow
 import React from 'react';
-import { Link } from 'react-router';
 import QualifierIcon from '../shared/QualifierIcon';
 import FavoriteContainer from '../controls/FavoriteContainer';
-import { getProjectUrl, getComponentIssuesUrl } from '../../helpers/urls';
+import { getPathUrlAsString, getProjectUrl, getComponentIssuesUrl } from '../../helpers/urls';
 import { collapsedDirFromPath, fileFromPath } from '../../helpers/path';
 import { translate } from '../../helpers/l10n';
 import { formatMeasure } from '../../helpers/measures';
@@ -77,7 +76,6 @@ export default class SourceViewerHeader extends React.PureComponent {
       uuid
     } = this.props.component;
     const isUnitTest = q === 'UTS';
-    // TODO check if source viewer is displayed inside workspace
     const workspace = false;
     let rawSourcesLink =
       window.baseUrl + `/api/sources/raw?key=${encodeURIComponent(this.props.component.key)}`;
@@ -91,16 +89,20 @@ export default class SourceViewerHeader extends React.PureComponent {
         <div className="source-viewer-header-component">
           <div className="component-name">
             <div className="component-name-parent">
-              <Link to={getProjectUrl(project, this.props.branch)} className="link-with-icon">
+              <a
+                href={getPathUrlAsString(getProjectUrl(project, this.props.branch))}
+                className="link-with-icon">
                 <QualifierIcon qualifier="TRK" /> <span>{projectName}</span>
-              </Link>
+              </a>
             </div>
 
             {subProject != null && (
               <div className="component-name-parent">
-                <Link to={getProjectUrl(subProject, this.props.branch)} className="link-with-icon">
+                <a
+                  href={getPathUrlAsString(getProjectUrl(subProject, this.props.branch))}
+                  className="link-with-icon">
                   <QualifierIcon qualifier="BRC" /> <span>{subProjectName}</span>
-                </Link>
+                </a>
               </div>
             )}
 
@@ -127,15 +129,15 @@ export default class SourceViewerHeader extends React.PureComponent {
               </a>
             </li>
             <li>
-              <Link
+              <a
                 className="js-new-window"
                 target="_blank"
-                to={{
+                href={getPathUrlAsString({
                   pathname: '/component',
                   query: { branch: this.props.branch, id: this.props.component.key }
-                }}>
+                })}>
                 {translate('component_viewer.new_window')}
-              </Link>
+              </a>
             </li>
             {!workspace && (
               <li>
@@ -177,17 +179,19 @@ export default class SourceViewerHeader extends React.PureComponent {
 
           <div className="source-viewer-header-measure">
             <span className="source-viewer-header-measure-value">
-              <Link
-                to={getComponentIssuesUrl(project, {
-                  resolved: 'false',
-                  fileUuids: uuid,
-                  branch: this.props.branch
-                })}
+              <a
+                href={getPathUrlAsString(
+                  getComponentIssuesUrl(project, {
+                    resolved: 'false',
+                    fileUuids: uuid,
+                    branch: this.props.branch
+                  })
+                )}
                 className="source-viewer-header-external-link"
                 target="_blank">
                 {measures.issues != null ? formatMeasure(measures.issues, 'SHORT_INT') : 0}{' '}
                 <i className="icon-detach" />
-              </Link>
+              </a>
             </span>
             <span className="source-viewer-header-measure-label">
               {translate('metric.violations.name')}
index 90f0417fd6a26ee05a70e00d2c42ab4f41df44f8..b78c07f1800dac8134c41e8ecd9d0bc5e18fa15e 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import {
-  getComponentUrl,
   getComponentIssuesUrl,
   getComponentDrilldownUrl,
+  getPathUrlAsString,
+  getProjectUrl,
   getQualityGatesUrl,
   getQualityGateUrl
 } from '../urls';
@@ -40,20 +41,22 @@ afterEach(() => {
   (window as any).baseUrl = oldBaseUrl;
 });
 
-describe('#getComponentUrl', () => {
+describe('#getPathUrlAsString', () => {
   it('should return component url', () => {
-    expect(getComponentUrl(SIMPLE_COMPONENT_KEY)).toBe('/dashboard?id=' + SIMPLE_COMPONENT_KEY);
+    expect(getPathUrlAsString(getProjectUrl(SIMPLE_COMPONENT_KEY, 'branch:7.0'))).toBe(
+      '/dashboard?id=' + SIMPLE_COMPONENT_KEY + '&branch=branch%3A7.0'
+    );
   });
 
   it('should encode component key', () => {
-    expect(getComponentUrl(COMPLEX_COMPONENT_KEY)).toBe(
+    expect(getPathUrlAsString(getProjectUrl(COMPLEX_COMPONENT_KEY))).toBe(
       '/dashboard?id=' + COMPLEX_COMPONENT_KEY_ENCODED
     );
   });
 
   it('should take baseUrl into account', () => {
     (window as any).baseUrl = '/context';
-    expect(getComponentUrl(COMPLEX_COMPONENT_KEY)).toBe(
+    expect(getPathUrlAsString(getProjectUrl(COMPLEX_COMPONENT_KEY))).toBe(
       '/context/dashboard?id=' + COMPLEX_COMPONENT_KEY_ENCODED
     );
   });
index aae5afb93bc47064c8fc3dda86db4396c14dc476..e73d9d2d67d82e8075d34d204447d346f1df7807 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+import { omitBy, isNil } from 'lodash';
 import { stringify } from 'querystring';
 import { isShortLivingBranch } from './branches';
 import { getProfilePath } from '../apps/quality-profiles/utils';
@@ -35,13 +36,8 @@ export function getBaseUrl(): string {
   return (window as any).baseUrl;
 }
 
-/**
- * Generate URL for a component's home page
- * Deprecated : use getProjectUrl
- */
-export function getComponentUrl(componentKey: string, branch?: string): string {
-  const branchQuery = branch ? `&branch=${encodeURIComponent(branch)}` : '';
-  return getBaseUrl() + '/dashboard?id=' + encodeURIComponent(componentKey) + branchQuery;
+export function getPathUrlAsString(path: Location): string {
+  return `${getBaseUrl()}${path.pathname}?${stringify(omitBy(path.query, isNil))}`;
 }
 
 export function getProjectUrl(key: string, branch?: string): Location {
@@ -79,11 +75,6 @@ export function getComponentIssuesUrl(componentKey: string, query?: Query): Loca
   return { pathname: '/project/issues', query: { ...query || {}, id: componentKey } };
 }
 
-export function getComponentIssuesUrlAsString(componentKey: string, query?: Query): string {
-  const path = getComponentIssuesUrl(componentKey, query);
-  return `${getBaseUrl()}${path.pathname}?${stringify(path.query)}`;
-}
-
 /**
  * Generate URL for a component's drilldown page
  */