]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-11368 Disable links in duplications popup for branches and prs (#856)
authorStas Vilchik <stas.vilchik@sonarsource.com>
Mon, 22 Oct 2018 07:24:10 +0000 (09:24 +0200)
committerSonarTech <sonartech@sonarsource.com>
Wed, 7 Nov 2018 19:21:02 +0000 (20:21 +0100)
server/sonar-web/src/main/js/components/SourceViewer/components/CoveragePopup.tsx
server/sonar-web/src/main/js/components/SourceViewer/components/DuplicationPopup.tsx
server/sonar-web/src/main/js/components/SourceViewer/components/LineCoverage.tsx
server/sonar-web/src/main/js/components/SourceViewer/components/LineDuplicationBlock.tsx
server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/LineCoverage-test.tsx.snap
server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/LineDuplicationBlock-test.tsx.snap
server/sonar-web/src/main/js/components/SourceViewer/styles.css

index 9c35f78e2697c1673259d3e8e2e0edc7c3cabb54..cff059653047e45e1410b283dffd89d5426a1daf 100644 (file)
@@ -26,7 +26,12 @@ import { DropdownOverlay } from '../../controls/Dropdown';
 import TestStatusIcon from '../../icons-components/TestStatusIcon';
 import { PopupPlacement } from '../../ui/popups';
 import { WorkspaceContext } from '../../workspace/context';
-import { isSameBranchLike, getBranchLikeQuery } from '../../../helpers/branches';
+import {
+  isSameBranchLike,
+  getBranchLikeQuery,
+  isShortLivingBranch,
+  isPullRequest
+} from '../../../helpers/branches';
 import { translate } from '../../../helpers/l10n';
 import { collapsePath } from '../../../helpers/path';
 
@@ -71,6 +76,11 @@ export default class CoveragePopup extends React.PureComponent<Props, State> {
     this.mounted = false;
   }
 
+  shouldLink() {
+    const { branchLike } = this.props;
+    return !isShortLivingBranch(branchLike) && !isPullRequest(branchLike);
+  }
+
   fetchTests = () => {
     this.setState({ loading: true });
     getTests({
@@ -95,12 +105,22 @@ export default class CoveragePopup extends React.PureComponent<Props, State> {
     event.preventDefault();
     event.currentTarget.blur();
     const { key } = event.currentTarget.dataset;
-    if (key) {
+    if (this.shouldLink() && key) {
       this.context.workspace.openComponent({ branchLike: this.props.branchLike, key });
     }
     this.props.onClose();
   };
 
+  renderFile(file: { key: string; longName: string }) {
+    return this.shouldLink() ? (
+      <a data-key={file.key} href="#" onClick={this.handleTestClick} title={file.longName}>
+        <span>{collapsePath(file.longName)}</span>
+      </a>
+    ) : (
+      <span>{collapsePath(file.longName)}</span>
+    );
+  }
+
   render() {
     const { line } = this.props;
     const testCasesByFile = groupBy(this.state.testCases || [], 'fileKey');
@@ -115,7 +135,7 @@ export default class CoveragePopup extends React.PureComponent<Props, State> {
 
     return (
       <DropdownOverlay placement={PopupPlacement.RightTop}>
-        <div className="abs-width-400">
+        <div className="source-viewer-bubble-popup abs-width-400">
           <h6 className="spacer-bottom">
             {translate('source_viewer.covered')}
             {!!line.conditions && (
@@ -136,13 +156,7 @@ export default class CoveragePopup extends React.PureComponent<Props, State> {
                 translate('source_viewer.tooltip.no_information_about_tests')}
               {testFiles.map(testFile => (
                 <div className="spacer-top text-ellipsis" key={testFile.file.key}>
-                  <a
-                    data-key={testFile.file.key}
-                    href="#"
-                    onClick={this.handleTestClick}
-                    title={testFile.file.longName}>
-                    <span>{collapsePath(testFile.file.longName)}</span>
-                  </a>
+                  {this.renderFile(testFile.file)}
                   <ul>
                     {testFile.tests.map(testCase => (
                       <li
index ec3ec9bf4cb1bded76530d483c5f1cdf077edd21..c3c9bff0e839e49fea344e4f7d8d24cba1936d6a 100644 (file)
@@ -26,6 +26,7 @@ import { DropdownOverlay } from '../../controls/Dropdown';
 import QualifierIcon from '../../icons-components/QualifierIcon';
 import { PopupPlacement } from '../../ui/popups';
 import { WorkspaceContext } from '../../workspace/context';
+import { isShortLivingBranch, isPullRequest } from '../../../helpers/branches';
 import { translate } from '../../../helpers/l10n';
 import { collapsedDirFromPath, fileFromPath } from '../../../helpers/path';
 import { getProjectUrl } from '../../../helpers/urls';
@@ -48,6 +49,11 @@ export default class DuplicationPopup extends React.PureComponent<Props> {
     workspace: PropTypes.object.isRequired
   };
 
+  shouldLink() {
+    const { branchLike } = this.props;
+    return !isShortLivingBranch(branchLike) && !isPullRequest(branchLike);
+  }
+
   isDifferentComponent = (
     a: { project: string; subProject?: string },
     b: { project: string; subProject?: string }
@@ -59,7 +65,7 @@ export default class DuplicationPopup extends React.PureComponent<Props> {
     event.preventDefault();
     event.currentTarget.blur();
     const { key, line } = event.currentTarget.dataset;
-    if (key) {
+    if (this.shouldLink() && key) {
       this.context.workspace.openComponent({
         branchLike: this.props.branchLike,
         key,
@@ -69,6 +75,21 @@ export default class DuplicationPopup extends React.PureComponent<Props> {
     this.props.onClose();
   };
 
+  renderDuplication(file: DuplicatedFile, children: React.ReactNode, line?: number) {
+    return this.shouldLink() ? (
+      <a
+        data-key={file.key}
+        data-line={line}
+        href="#"
+        onClick={this.handleFileClick}
+        title={file.name}>
+        {children}
+      </a>
+    ) : (
+      children
+    );
+  }
+
   render() {
     const { duplicatedFiles = {}, sourceViewerFile } = this.props;
 
@@ -129,17 +150,15 @@ export default class DuplicationPopup extends React.PureComponent<Props> {
 
                     {duplication.file.key !== this.props.sourceViewerFile.key && (
                       <div className="component-name-path">
-                        <a
-                          className="link-action"
-                          data-key={duplication.file.key}
-                          href="#"
-                          onClick={this.handleFileClick}
-                          title={duplication.file.name}>
-                          <span>{collapsedDirFromPath(duplication.file.name)}</span>
-                          <span className="component-name-file">
-                            {fileFromPath(duplication.file.name)}
-                          </span>
-                        </a>
+                        {this.renderDuplication(
+                          duplication.file,
+                          <>
+                            <span>{collapsedDirFromPath(duplication.file.name)}</span>
+                            <span className="component-name-file">
+                              {fileFromPath(duplication.file.name)}
+                            </span>
+                          </>
+                        )}
                       </div>
                     )}
 
@@ -147,15 +166,15 @@ export default class DuplicationPopup extends React.PureComponent<Props> {
                       {'Lines: '}
                       {duplication.blocks.map((block, index) => (
                         <React.Fragment key={index}>
-                          <a
-                            data-key={duplication.file.key}
-                            data-line={block.from}
-                            href="#"
-                            onClick={this.handleFileClick}>
-                            {block.from}
-                            {' – '}
-                            {block.from + block.size - 1}
-                          </a>
+                          {this.renderDuplication(
+                            duplication.file,
+                            <>
+                              {block.from}
+                              {' – '}
+                              {block.from + block.size - 1}
+                            </>,
+                            block.from
+                          )}
                           {index < duplication.blocks.length - 1 && ', '}
                         </React.Fragment>
                       ))}
index be4c2d1a8426a08f3b2ef6b8dfea61defe1b5f77..2be765bb90425e8c376591dcff9ef95960e75706 100644 (file)
@@ -58,25 +58,25 @@ export default class LineCoverage extends React.PureComponent<Props> {
     const hasPopup =
       line.coverageStatus === 'covered' || line.coverageStatus === 'partially-covered';
 
+    const bar = hasPopup ? (
+      <div className="source-line-bar" onClick={this.handleClick} role="button" tabIndex={0} />
+    ) : (
+      <div className="source-line-bar" />
+    );
+
     const cell = line.coverageStatus ? (
       <Tooltip
         overlay={popupOpen ? undefined : translate('source_viewer.tooltip', line.coverageStatus)}
         placement="right">
-        <div className="source-line-bar" />
+        {bar}
       </Tooltip>
     ) : (
-      <div className="source-line-bar" />
+      bar
     );
 
     if (hasPopup) {
       return (
-        <td
-          className={className}
-          data-line-number={line.line}
-          onClick={this.handleClick}
-          // eslint-disable-next-line jsx-a11y/no-noninteractive-element-to-interactive-role
-          role="button"
-          tabIndex={0}>
+        <td className={className} data-line-number={line.line}>
           <Toggler
             onRequestClose={this.closePopup}
             open={popupOpen}
index 93772dcbb72cf3df032abaa3cd34521a1678d12d..0b9ae37f2fcf35c370b0ca910a8799257e9b3477 100644 (file)
@@ -64,29 +64,27 @@ export default class LineDuplicationBlock extends React.PureComponent<Props> {
       'source-line-duplicated': duplicated
     });
 
-    const cell = <div className="source-line-bar" />;
-
     return duplicated ? (
-      <td
-        className={className}
-        data-index={index}
-        data-line-number={line.line}
-        onClick={this.handleClick}
-        // eslint-disable-next-line jsx-a11y/no-noninteractive-element-to-interactive-role
-        role="button"
-        tabIndex={0}>
+      <td className={className} data-index={index} data-line-number={line.line}>
         <Toggler
           onRequestClose={this.closePopup}
           open={popupOpen}
           overlay={this.props.renderDuplicationPopup(index, line.line)}>
-          <Tooltip overlay={translate('source_viewer.tooltip.duplicated_block')} placement="right">
-            {cell}
+          <Tooltip
+            overlay={popupOpen ? undefined : translate('source_viewer.tooltip.duplicated_block')}
+            placement="right">
+            <div
+              className="source-line-bar"
+              onClick={this.handleClick}
+              role="button"
+              tabIndex={0}
+            />
           </Tooltip>
         </Toggler>
       </td>
     ) : (
       <td className={className} data-index={index} data-line-number={line.line}>
-        {cell}
+        <div className="source-line-bar" />
       </td>
     );
   }
index fc47e783cacdb6fc4f937bfc67e458f88fabfba4..fe461767489e224d3000d2249dec62495bb5d467 100644 (file)
@@ -4,9 +4,6 @@ exports[`render covered line 1`] = `
 <td
   className="source-meta source-line-coverage source-line-covered"
   data-line-number={3}
-  onClick={[Function]}
-  role="button"
-  tabIndex={0}
 >
   <Toggler
     onRequestClose={[Function]}
@@ -30,6 +27,9 @@ exports[`render covered line 1`] = `
     >
       <div
         className="source-line-bar"
+        onClick={[Function]}
+        role="button"
+        tabIndex={0}
       />
     </Tooltip>
   </Toggler>
index 7147eca868e3b72590a646540e13e552b394ad68..86a35b7a0837e83d5ee78071a89925ae783b33d6 100644 (file)
@@ -5,9 +5,6 @@ exports[`render duplicated line 1`] = `
   className="source-meta source-line-duplications-extra source-line-duplicated"
   data-index={1}
   data-line-number={3}
-  onClick={[Function]}
-  role="button"
-  tabIndex={0}
 >
   <Toggler
     onRequestClose={[Function]}
@@ -19,6 +16,9 @@ exports[`render duplicated line 1`] = `
     >
       <div
         className="source-line-bar"
+        onClick={[Function]}
+        role="button"
+        tabIndex={0}
       />
     </Tooltip>
   </Toggler>
index c95c5a71925fb9dc3555e56895b3f0510944a8d6..2d1a80c67b17f94bc757c1902371a4afbd611473 100644 (file)
   height: 18px;
 }
 
+.source-line-bar[role='button'] {
+  cursor: pointer;
+}
+
+.source-line-bar:focus {
+  outline: none;
+}
+
 .source-line-covered {
   background-color: var(--green) !important;
 }
   font-family: var(--baseFontFamily);
   font-size: var(--baseFontSize);
   text-align: left;
+  user-select: text;
 }
 
 .issue-location {