]> source.dussan.org Git - sonarqube.git/commitdiff
drop /component url
authorStas Vilchik <stas.vilchik@sonarsource.com>
Wed, 2 Jan 2019 14:43:44 +0000 (15:43 +0100)
committerSonarTech <sonartech@sonarsource.com>
Mon, 7 Jan 2019 19:21:00 +0000 (20:21 +0100)
20 files changed:
server/sonar-web/src/main/js/app/utils/startReactApp.tsx
server/sonar-web/src/main/js/apps/code/components/App.tsx
server/sonar-web/src/main/js/apps/code/components/SourceViewerWrapper.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component/components/App.tsx [deleted file]
server/sonar-web/src/main/js/apps/component/components/__tests__/App-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/component/components/__tests__/__snapshots__/App-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/component/routes.ts [deleted file]
server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/ComponentBreadcrumbs-test.tsx.snap
server/sonar-web/src/main/js/components/SourceViewer/SourceViewerBase.tsx
server/sonar-web/src/main/js/components/SourceViewer/SourceViewerCode.tsx
server/sonar-web/src/main/js/components/SourceViewer/SourceViewerContext.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/components/SourceViewer/SourceViewerHeader.tsx
server/sonar-web/src/main/js/components/SourceViewer/components/Line.tsx
server/sonar-web/src/main/js/components/SourceViewer/components/LineNumber.tsx
server/sonar-web/src/main/js/components/SourceViewer/components/LineOptionsPopup.tsx
server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/LineNumber-test.tsx
server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/LineOptionsPopup-test.tsx
server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/LineNumber-test.tsx.snap
server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/LineOptionsPopup-test.tsx.snap
server/sonar-web/src/main/js/helpers/urls.ts

index 68ae6f8ccb595afe28334758a99dccc2d7061e7c..781120376f3869f12ebf2a211e88f9862a80550b 100644 (file)
@@ -34,7 +34,6 @@ import accountRoutes from '../../apps/account/routes';
 import backgroundTasksRoutes from '../../apps/background-tasks/routes';
 import codeRoutes from '../../apps/code/routes';
 import codingRulesRoutes from '../../apps/coding-rules/routes';
-import componentRoutes from '../../apps/component/routes';
 import componentMeasuresRoutes from '../../apps/component-measures/routes';
 import customMeasuresRoutes from '../../apps/custom-measures/routes';
 import groupsRoutes from '../../apps/groups/routes';
@@ -172,7 +171,6 @@ export default function startReactApp(
                 {!isSonarCloud() && (
                   <RouteWithChildRoutes path="coding_rules" childRoutes={codingRulesRoutes} />
                 )}
-                <RouteWithChildRoutes path="component" childRoutes={componentRoutes} />
                 <RouteWithChildRoutes path="documentation" childRoutes={documentationRoutes} />
                 <Route path="explore" component={Explore}>
                   <Route path="issues" component={ExploreIssues} />
index 02904305e0c570daa04881921dfa1866c4a5a539..ca8f1d392fb6359d19f19014ba609597f64ed812 100644 (file)
@@ -21,13 +21,14 @@ import * as React from 'react';
 import * as classNames from 'classnames';
 import { connect } from 'react-redux';
 import Helmet from 'react-helmet';
+import { Location } from 'history';
 import Components from './Components';
 import Breadcrumbs from './Breadcrumbs';
 import Search from './Search';
+import SourceViewerWrapper from './SourceViewerWrapper';
 import { addComponent, addComponentBreadcrumbs, clearBucket } from '../bucket';
 import { retrieveComponentChildren, retrieveComponent, loadMoreChildren } from '../utils';
 import ListFooter from '../../../components/controls/ListFooter';
-import SourceViewer from '../../../components/SourceViewer/SourceViewer';
 import Suggestions from '../../../app/components/embed-docs-modal/Suggestions';
 import { fetchMetrics } from '../../../store/rootActions';
 import { getMetrics } from '../../../store/rootReducer';
@@ -46,7 +47,7 @@ interface DispatchToProps {
 interface OwnProps {
   branchLike?: T.BranchLike;
   component: T.Component;
-  location: { query: { [x: string]: string } };
+  location: Pick<Location, 'query'>;
 }
 
 type Props = StateToProps & DispatchToProps & OwnProps;
@@ -175,7 +176,7 @@ export class App extends React.PureComponent<Props, State> {
   };
 
   render() {
-    const { branchLike, component } = this.props;
+    const { branchLike, component, location } = this.props;
     const { loading, baseComponent, components, breadcrumbs, total, sourceViewer } = this.state;
     const shouldShowBreadcrumbs = breadcrumbs.length > 1;
 
@@ -224,7 +225,11 @@ export class App extends React.PureComponent<Props, State> {
 
           {sourceViewer !== undefined && (
             <div className="spacer-top">
-              <SourceViewer branchLike={branchLike} component={sourceViewer.key} />
+              <SourceViewerWrapper
+                branchLike={branchLike}
+                component={sourceViewer.key}
+                location={location}
+              />
             </div>
           )}
         </div>
diff --git a/server/sonar-web/src/main/js/apps/code/components/SourceViewerWrapper.tsx b/server/sonar-web/src/main/js/apps/code/components/SourceViewerWrapper.tsx
new file mode 100644 (file)
index 0000000..a3797f2
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * 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 { Location } from 'history';
+import SourceViewer from '../../../components/SourceViewer/SourceViewer';
+import { scrollToElement } from '../../../helpers/scrolling';
+
+interface Props {
+  branchLike?: T.BranchLike;
+  component: string;
+  location: Pick<Location, 'query'>;
+}
+
+export default function SourceViewerWrapper({ branchLike, component, location }: Props) {
+  const { line } = location.query;
+
+  const scrollToLine = () => {
+    if (line) {
+      const row = document.querySelector(`.source-line[data-line-number="${line}"]`);
+      if (row) {
+        scrollToElement(row, { smooth: false, bottomOffset: window.innerHeight / 2 - 60 });
+      }
+    }
+  };
+
+  const finalLine = line ? Number(line) : undefined;
+
+  return (
+    <SourceViewer
+      aroundLine={finalLine}
+      branchLike={branchLike}
+      component={component}
+      highlightedLine={finalLine}
+      onLoaded={scrollToLine}
+    />
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/component/components/App.tsx b/server/sonar-web/src/main/js/apps/component/components/App.tsx
deleted file mode 100644 (file)
index bef1332..0000000
+++ /dev/null
@@ -1,71 +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 SourceViewer from '../../../components/SourceViewer/SourceViewer';
-import { fillBranchLike } from '../../../helpers/branches';
-
-interface Props {
-  location: {
-    query: {
-      branch?: string;
-      id: string;
-      line?: string;
-      pullRequest?: string;
-    };
-  };
-}
-
-export default class App extends React.PureComponent<Props> {
-  scrollToLine = () => {
-    const { line } = this.props.location.query;
-    if (line) {
-      const row = document.querySelector(`.source-line[data-line-number="${line}"]`);
-      if (row) {
-        const rect = row.getBoundingClientRect();
-        const topOffset = window.innerHeight / 2 - 60;
-        const goal = rect.top - topOffset;
-        window.scrollTo(0, goal);
-      }
-    }
-  };
-
-  render() {
-    const { branch, id, line, pullRequest } = this.props.location.query;
-
-    const finalLine = line ? Number(line) : undefined;
-
-    // TODO find a way to avoid creating this fakeBranchLike
-    // probably the best way would be to drop this page completely
-    // and redirect to the Code page
-    const fakeBranchLike = fillBranchLike(branch, pullRequest);
-
-    return (
-      <div className="page page-limited">
-        <SourceViewer
-          aroundLine={finalLine}
-          branchLike={fakeBranchLike}
-          component={id}
-          highlightedLine={finalLine}
-          onLoaded={this.scrollToLine}
-        />
-      </div>
-    );
-  }
-}
diff --git a/server/sonar-web/src/main/js/apps/component/components/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/component/components/__tests__/App-test.tsx
deleted file mode 100644 (file)
index 935c168..0000000
+++ /dev/null
@@ -1,28 +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 { shallow } from 'enzyme';
-import App from '../App';
-
-it('renders', () => {
-  expect(
-    shallow(<App location={{ query: { branch: 'b', id: 'foo', line: '7' } }} />)
-  ).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/apps/component/components/__tests__/__snapshots__/App-test.tsx.snap b/server/sonar-web/src/main/js/apps/component/components/__tests__/__snapshots__/App-test.tsx.snap
deleted file mode 100644 (file)
index 80a0c87..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders 1`] = `
-<div
-  className="page page-limited"
->
-  <LazyLoader
-    aroundLine={7}
-    branchLike={
-      Object {
-        "isMain": false,
-        "mergeBranch": "",
-        "name": "b",
-        "type": "SHORT",
-      }
-    }
-    component="foo"
-    highlightedLine={7}
-    onLoaded={[Function]}
-  />
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/component/routes.ts b/server/sonar-web/src/main/js/apps/component/routes.ts
deleted file mode 100644 (file)
index 094046e..0000000
+++ /dev/null
@@ -1,28 +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 { lazyLoad } from '../../components/lazyLoad';
-
-const routes = [
-  {
-    indexRoute: { component: lazyLoad(() => import('./components/App')) }
-  }
-];
-
-export default routes;
index c0182df2b97a64488654ec76cdba1b78f86257b7..dea3a478dcbaa4f0a66c507b544e31a4d77b3967 100644 (file)
@@ -41,6 +41,7 @@ exports[`renders 1`] = `
         "pathname": "/code",
         "query": Object {
           "id": "proj",
+          "line": undefined,
           "selected": "comp",
         },
       }
@@ -122,6 +123,7 @@ exports[`renders with branch 1`] = `
         "query": Object {
           "branch": "feature",
           "id": "proj",
+          "line": undefined,
           "selected": "comp",
         },
       }
@@ -200,6 +202,7 @@ exports[`renders with sub-project 1`] = `
         "pathname": "/code",
         "query": Object {
           "id": "proj",
+          "line": undefined,
           "selected": "comp",
         },
       }
index 8d914ec0becb586d0d0f6d3bee02dcdd2f501dfa..db24f1d0ceb4304f0db3baaf54c2369383fea373 100644 (file)
@@ -22,6 +22,7 @@ import * as classNames from 'classnames';
 import { intersection, uniqBy } from 'lodash';
 import SourceViewerHeader from './SourceViewerHeader';
 import SourceViewerCode from './SourceViewerCode';
+import { SourceViewerContext } from './SourceViewerContext';
 import DuplicationPopup from './components/DuplicationPopup';
 import defaultLoadIssues from './helpers/loadIssues';
 import getCoverageStatus from './helpers/getCoverageStatus';
@@ -703,23 +704,25 @@ export default class SourceViewerBase extends React.PureComponent<Props, State>
     });
 
     return (
-      <div className={className} ref={node => (this.node = node)}>
-        <WorkspaceContext.Consumer>
-          {({ openComponent }) => (
-            <SourceViewerHeader
-              branchLike={this.props.branchLike}
-              openComponent={openComponent}
-              sourceViewerFile={component}
-            />
+      <SourceViewerContext.Provider value={{ branchLike: this.props.branchLike, file: component }}>
+        <div className={className} ref={node => (this.node = node)}>
+          <WorkspaceContext.Consumer>
+            {({ openComponent }) => (
+              <SourceViewerHeader
+                branchLike={this.props.branchLike}
+                openComponent={openComponent}
+                sourceViewerFile={component}
+              />
+            )}
+          </WorkspaceContext.Consumer>
+          {sourceRemoved && (
+            <Alert className="spacer-top" variant="warning">
+              {translate('code_viewer.no_source_code_displayed_due_to_source_removed')}
+            </Alert>
           )}
-        </WorkspaceContext.Consumer>
-        {sourceRemoved && (
-          <Alert className="spacer-top" variant="warning">
-            {translate('code_viewer.no_source_code_displayed_due_to_source_removed')}
-          </Alert>
-        )}
-        {!sourceRemoved && sources !== undefined && this.renderCode(sources)}
-      </div>
+          {!sourceRemoved && sources !== undefined && this.renderCode(sources)}
+        </div>
+      </SourceViewerContext.Provider>
     );
   }
 }
index 4b0c419e2badc469179f5f690fe104cc1b3496a1..923f3b6ff9f05084a2d1c090d95073a33ab5b68b 100644 (file)
@@ -156,7 +156,6 @@ export default class SourceViewerCode extends React.PureComponent<Props> {
     return (
       <Line
         branchLike={this.props.branchLike}
-        componentKey={this.props.componentKey}
         displayAllIssues={this.props.displayAllIssues}
         displayCoverage={displayCoverage}
         displayDuplications={displayDuplications}
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerContext.tsx b/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerContext.tsx
new file mode 100644 (file)
index 0000000..a546d03
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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';
+
+interface SourceViewerContextShape {
+  branchLike?: T.BranchLike;
+  file: T.SourceViewerFile;
+}
+
+export const SourceViewerContext = React.createContext({
+  branchLike: {},
+  file: {}
+}) as React.Context<SourceViewerContextShape>;
index 53e896eff12ecd05ab5ae5a830cff3a5d86f1140..bd11c8c615d075fa6db6a83b33470bd855cb7a39 100644 (file)
@@ -32,7 +32,8 @@ import {
   getPathUrlAsString,
   getBranchLikeUrl,
   getComponentIssuesUrl,
-  getBaseUrl
+  getBaseUrl,
+  getCodeUrl
 } from '../../helpers/urls';
 import { collapsedDirFromPath, fileFromPath } from '../../helpers/path';
 import { translate } from '../../helpers/l10n';
@@ -136,15 +137,13 @@ export default class SourceViewerHeader extends React.PureComponent<Props, State
                 </a>
               </li>
               <li>
-                <a
+                <Link
                   className="js-new-window"
-                  href={getPathUrlAsString({
-                    pathname: '/component',
-                    query: { id: key, ...getBranchLikeQuery(this.props.branchLike) }
-                  })}
-                  target="_blank">
+                  rel="noopener noreferrer"
+                  target="_blank"
+                  to={getCodeUrl(this.props.sourceViewerFile.project, this.props.branchLike, key)}>
                   {translate('component_viewer.new_window')}
-                </a>
+                </Link>
               </li>
               {!workspace && (
                 <li>
@@ -154,7 +153,11 @@ export default class SourceViewerHeader extends React.PureComponent<Props, State
                 </li>
               )}
               <li>
-                <a className="js-raw-source" href={rawSourcesLink} target="_blank">
+                <a
+                  className="js-raw-source"
+                  href={rawSourcesLink}
+                  rel="noopener noreferrer"
+                  target="_blank">
                   {translate('component_viewer.show_raw_source')}
                 </a>
               </li>
index e7f315caec5cc66040481a3fe9092f7d29505ee5..7955f4df686157c4bceacb341dcae410bb176b86 100644 (file)
@@ -30,7 +30,6 @@ import LineCode from './LineCode';
 
 interface Props {
   branchLike: T.BranchLike | undefined;
-  componentKey: string;
   displayAllIssues?: boolean;
   displayCoverage: boolean;
   displayDuplications: boolean;
@@ -112,8 +111,6 @@ export default class Line extends React.PureComponent<Props> {
     return (
       <tr className={className} data-line-number={line.line}>
         <LineNumber
-          branchLike={this.props.branchLike}
-          componentKey={this.props.componentKey}
           line={line}
           onPopupToggle={this.props.onLinePopupToggle}
           popupOpen={this.isPopupOpen('line-number')}
index c190e5a004c737690b9c78921735dca014fef392..5d90fb7acdd122558f3d7b63e0e11aedccdad263 100644 (file)
@@ -22,8 +22,6 @@ import LineOptionsPopup from './LineOptionsPopup';
 import Toggler from '../../controls/Toggler';
 
 interface Props {
-  branchLike: T.BranchLike | undefined;
-  componentKey: string;
   line: T.SourceLine;
   onPopupToggle: (x: { index?: number; line: number; name: string; open?: boolean }) => void;
   popupOpen: boolean;
@@ -46,7 +44,7 @@ export default class LineNumber extends React.PureComponent<Props> {
   };
 
   render() {
-    const { branchLike, componentKey, line, popupOpen } = this.props;
+    const { line, popupOpen } = this.props;
     const { line: lineNumber } = line;
     const hasLineNumber = !!lineNumber;
     return hasLineNumber ? (
@@ -60,9 +58,7 @@ export default class LineNumber extends React.PureComponent<Props> {
         <Toggler
           onRequestClose={this.closePopup}
           open={popupOpen}
-          overlay={
-            <LineOptionsPopup branchLike={branchLike} componentKey={componentKey} line={line} />
-          }
+          overlay={<LineOptionsPopup line={line} />}
         />
       </td>
     ) : (
index 24875c9404d2d5512753e29b466761705b5e31e2..5beb76d4c8cd7ba0e7c99b397fad744437389528 100644 (file)
@@ -22,26 +22,32 @@ import { Link } from 'react-router';
 import { DropdownOverlay } from '../../controls/Dropdown';
 import { PopupPlacement } from '../../ui/popups';
 import { translate } from '../../../helpers/l10n';
-import { getBranchLikeQuery } from '../../../helpers/branches';
+import { getCodeUrl } from '../../../helpers/urls';
+import { SourceViewerContext } from '../SourceViewerContext';
 
 interface Props {
-  branchLike: T.BranchLike | undefined;
-  componentKey: string;
   line: T.SourceLine;
 }
 
-export default function LineOptionsPopup({ branchLike, componentKey, line }: Props) {
-  const permalink = {
-    pathname: '/component',
-    query: { id: componentKey, line: line.line, ...getBranchLikeQuery(branchLike) }
-  };
+export default function LineOptionsPopup({ line }: Props) {
   return (
-    <DropdownOverlay placement={PopupPlacement.RightTop}>
-      <div className="source-viewer-bubble-popup nowrap">
-        <Link className="js-get-permalink" to={permalink}>
-          {translate('component_viewer.get_permalink')}
-        </Link>
-      </div>
-    </DropdownOverlay>
+    <SourceViewerContext.Consumer>
+      {({ branchLike, file }) => (
+        <DropdownOverlay placement={PopupPlacement.RightTop}>
+          <div className="source-viewer-bubble-popup nowrap">
+            <Link
+              className="js-get-permalink"
+              onClick={event => {
+                event.stopPropagation();
+              }}
+              rel="noopener noreferrer"
+              target="_blank"
+              to={getCodeUrl(file.project, branchLike, file.key, line.line)}>
+              {translate('component_viewer.get_permalink')}
+            </Link>
+          </div>
+        </DropdownOverlay>
+      )}
+    </SourceViewerContext.Consumer>
   );
 }
index 03cdce961f58511c40da2cc21912013a3f5c36e5..2b4a7453a9f9e71f9263ecc8772b79a8eed76163 100644 (file)
@@ -24,29 +24,13 @@ import LineNumber from '../LineNumber';
 
 it('render line 3', () => {
   const line = { line: 3 };
-  const wrapper = shallow(
-    <LineNumber
-      branchLike={undefined}
-      componentKey="foo"
-      line={line}
-      onPopupToggle={jest.fn()}
-      popupOpen={false}
-    />
-  );
+  const wrapper = shallow(<LineNumber line={line} onPopupToggle={jest.fn()} popupOpen={false} />);
   expect(wrapper).toMatchSnapshot();
   click(wrapper);
 });
 
 it('render line 0', () => {
   const line = { line: 0 };
-  const wrapper = shallow(
-    <LineNumber
-      branchLike={undefined}
-      componentKey="foo"
-      line={line}
-      onPopupToggle={jest.fn()}
-      popupOpen={false}
-    />
-  );
+  const wrapper = shallow(<LineNumber line={line} onPopupToggle={jest.fn()} popupOpen={false} />);
   expect(wrapper).toMatchSnapshot();
 });
index a3fce5c3135f6e91c202aa5e095dcf1c71012f32..4bdb873af4fc8850b72a7050bbd1f3913e840de6 100644 (file)
@@ -21,14 +21,18 @@ import * as React from 'react';
 import { shallow } from 'enzyme';
 import LineOptionsPopup from '../LineOptionsPopup';
 
+jest.mock('../../SourceViewerContext', () => ({
+  SourceViewerContext: {
+    Consumer: (props: any) =>
+      props.children({
+        branchLike: { isMain: false, name: 'feature', type: 'SHORT' },
+        file: { project: 'prj', key: 'foo' }
+      })
+  }
+}));
+
 it('should render', () => {
   const line = { line: 3 };
-  const branch: T.ShortLivingBranch = {
-    isMain: false,
-    mergeBranch: 'master',
-    name: 'feature',
-    type: 'SHORT'
-  };
-  const wrapper = shallow(<LineOptionsPopup branchLike={branch} componentKey="foo" line={line} />);
+  const wrapper = shallow(<LineOptionsPopup line={line} />).dive();
   expect(wrapper).toMatchSnapshot();
 });
index 985f1f51937a78ac71f7f8f6e94c87ca6414d469..a6bb1627d08b8f68ce9b114fa37138152b6a2fd6 100644 (file)
@@ -19,7 +19,6 @@ exports[`render line 3 1`] = `
     open={false}
     overlay={
       <LineOptionsPopup
-        componentKey="foo"
         line={
           Object {
             "line": 3,
index 96b360bb80a5cab701b2da3a8bbed8492d21999b..936909da9dcb6e99f6032270dd90f73d07dd34e6 100644 (file)
@@ -9,15 +9,19 @@ exports[`should render 1`] = `
   >
     <Link
       className="js-get-permalink"
+      onClick={[Function]}
       onlyActiveOnIndex={false}
+      rel="noopener noreferrer"
       style={Object {}}
+      target="_blank"
       to={
         Object {
-          "pathname": "/component",
+          "pathname": "/code",
           "query": Object {
             "branch": "feature",
-            "id": "foo",
+            "id": "prj",
             "line": 3,
+            "selected": "foo",
           },
         }
       }
index f899255e25505937afb473b1cbc841184c2fa013..c7090bc67705d8c2879b426a1e43c4cd39076f3a 100644 (file)
@@ -219,8 +219,16 @@ export function getMarkdownHelpUrl(): string {
   return getBaseUrl() + '/markdown/help';
 }
 
-export function getCodeUrl(project: string, branchLike?: T.BranchLike, selected?: string) {
-  return { pathname: '/code', query: { id: project, ...getBranchLikeQuery(branchLike), selected } };
+export function getCodeUrl(
+  project: string,
+  branchLike?: T.BranchLike,
+  selected?: string,
+  line?: number
+) {
+  return {
+    pathname: '/code',
+    query: { id: project, ...getBranchLikeQuery(branchLike), selected, line }
+  };
 }
 
 export function getOrganizationUrl(organization: string) {