Browse Source

drop /component url

tags/7.6
Stas Vilchik 5 years ago
parent
commit
a9d1146749
19 changed files with 158 additions and 214 deletions
  1. 0
    2
      server/sonar-web/src/main/js/app/utils/startReactApp.tsx
  2. 9
    4
      server/sonar-web/src/main/js/apps/code/components/App.tsx
  3. 54
    0
      server/sonar-web/src/main/js/apps/code/components/SourceViewerWrapper.tsx
  4. 0
    71
      server/sonar-web/src/main/js/apps/component/components/App.tsx
  5. 0
    22
      server/sonar-web/src/main/js/apps/component/components/__tests__/__snapshots__/App-test.tsx.snap
  6. 0
    28
      server/sonar-web/src/main/js/apps/component/routes.ts
  7. 3
    0
      server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/ComponentBreadcrumbs-test.tsx.snap
  8. 19
    16
      server/sonar-web/src/main/js/components/SourceViewer/SourceViewerBase.tsx
  9. 0
    1
      server/sonar-web/src/main/js/components/SourceViewer/SourceViewerCode.tsx
  10. 9
    7
      server/sonar-web/src/main/js/components/SourceViewer/SourceViewerContext.tsx
  11. 12
    9
      server/sonar-web/src/main/js/components/SourceViewer/SourceViewerHeader.tsx
  12. 0
    3
      server/sonar-web/src/main/js/components/SourceViewer/components/Line.tsx
  13. 2
    6
      server/sonar-web/src/main/js/components/SourceViewer/components/LineNumber.tsx
  14. 21
    15
      server/sonar-web/src/main/js/components/SourceViewer/components/LineOptionsPopup.tsx
  15. 2
    18
      server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/LineNumber-test.tsx
  16. 11
    7
      server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/LineOptionsPopup-test.tsx
  17. 0
    1
      server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/LineNumber-test.tsx.snap
  18. 6
    2
      server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/LineOptionsPopup-test.tsx.snap
  19. 10
    2
      server/sonar-web/src/main/js/helpers/urls.ts

+ 0
- 2
server/sonar-web/src/main/js/app/utils/startReactApp.tsx View File

import backgroundTasksRoutes from '../../apps/background-tasks/routes'; import backgroundTasksRoutes from '../../apps/background-tasks/routes';
import codeRoutes from '../../apps/code/routes'; import codeRoutes from '../../apps/code/routes';
import codingRulesRoutes from '../../apps/coding-rules/routes'; import codingRulesRoutes from '../../apps/coding-rules/routes';
import componentRoutes from '../../apps/component/routes';
import componentMeasuresRoutes from '../../apps/component-measures/routes'; import componentMeasuresRoutes from '../../apps/component-measures/routes';
import customMeasuresRoutes from '../../apps/custom-measures/routes'; import customMeasuresRoutes from '../../apps/custom-measures/routes';
import groupsRoutes from '../../apps/groups/routes'; import groupsRoutes from '../../apps/groups/routes';
{!isSonarCloud() && ( {!isSonarCloud() && (
<RouteWithChildRoutes path="coding_rules" childRoutes={codingRulesRoutes} /> <RouteWithChildRoutes path="coding_rules" childRoutes={codingRulesRoutes} />
)} )}
<RouteWithChildRoutes path="component" childRoutes={componentRoutes} />
<RouteWithChildRoutes path="documentation" childRoutes={documentationRoutes} /> <RouteWithChildRoutes path="documentation" childRoutes={documentationRoutes} />
<Route path="explore" component={Explore}> <Route path="explore" component={Explore}>
<Route path="issues" component={ExploreIssues} /> <Route path="issues" component={ExploreIssues} />

+ 9
- 4
server/sonar-web/src/main/js/apps/code/components/App.tsx View File

import * as classNames from 'classnames'; import * as classNames from 'classnames';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import Helmet from 'react-helmet'; import Helmet from 'react-helmet';
import { Location } from 'history';
import Components from './Components'; import Components from './Components';
import Breadcrumbs from './Breadcrumbs'; import Breadcrumbs from './Breadcrumbs';
import Search from './Search'; import Search from './Search';
import SourceViewerWrapper from './SourceViewerWrapper';
import { addComponent, addComponentBreadcrumbs, clearBucket } from '../bucket'; import { addComponent, addComponentBreadcrumbs, clearBucket } from '../bucket';
import { retrieveComponentChildren, retrieveComponent, loadMoreChildren } from '../utils'; import { retrieveComponentChildren, retrieveComponent, loadMoreChildren } from '../utils';
import ListFooter from '../../../components/controls/ListFooter'; import ListFooter from '../../../components/controls/ListFooter';
import SourceViewer from '../../../components/SourceViewer/SourceViewer';
import Suggestions from '../../../app/components/embed-docs-modal/Suggestions'; import Suggestions from '../../../app/components/embed-docs-modal/Suggestions';
import { fetchMetrics } from '../../../store/rootActions'; import { fetchMetrics } from '../../../store/rootActions';
import { getMetrics } from '../../../store/rootReducer'; import { getMetrics } from '../../../store/rootReducer';
interface OwnProps { interface OwnProps {
branchLike?: T.BranchLike; branchLike?: T.BranchLike;
component: T.Component; component: T.Component;
location: { query: { [x: string]: string } };
location: Pick<Location, 'query'>;
} }


type Props = StateToProps & DispatchToProps & OwnProps; type Props = StateToProps & DispatchToProps & OwnProps;
}; };


render() { render() {
const { branchLike, component } = this.props;
const { branchLike, component, location } = this.props;
const { loading, baseComponent, components, breadcrumbs, total, sourceViewer } = this.state; const { loading, baseComponent, components, breadcrumbs, total, sourceViewer } = this.state;
const shouldShowBreadcrumbs = breadcrumbs.length > 1; const shouldShowBreadcrumbs = breadcrumbs.length > 1;




{sourceViewer !== undefined && ( {sourceViewer !== undefined && (
<div className="spacer-top"> <div className="spacer-top">
<SourceViewer branchLike={branchLike} component={sourceViewer.key} />
<SourceViewerWrapper
branchLike={branchLike}
component={sourceViewer.key}
location={location}
/>
</div> </div>
)} )}
</div> </div>

+ 54
- 0
server/sonar-web/src/main/js/apps/code/components/SourceViewerWrapper.tsx View File

/*
* 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}
/>
);
}

+ 0
- 71
server/sonar-web/src/main/js/apps/component/components/App.tsx View File

/*
* 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>
);
}
}

+ 0
- 22
server/sonar-web/src/main/js/apps/component/components/__tests__/__snapshots__/App-test.tsx.snap View File

// 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>
`;

+ 0
- 28
server/sonar-web/src/main/js/apps/component/routes.ts View File

/*
* 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;

+ 3
- 0
server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/ComponentBreadcrumbs-test.tsx.snap View File

"pathname": "/code", "pathname": "/code",
"query": Object { "query": Object {
"id": "proj", "id": "proj",
"line": undefined,
"selected": "comp", "selected": "comp",
}, },
} }
"query": Object { "query": Object {
"branch": "feature", "branch": "feature",
"id": "proj", "id": "proj",
"line": undefined,
"selected": "comp", "selected": "comp",
}, },
} }
"pathname": "/code", "pathname": "/code",
"query": Object { "query": Object {
"id": "proj", "id": "proj",
"line": undefined,
"selected": "comp", "selected": "comp",
}, },
} }

+ 19
- 16
server/sonar-web/src/main/js/components/SourceViewer/SourceViewerBase.tsx View File

import { intersection, uniqBy } from 'lodash'; import { intersection, uniqBy } from 'lodash';
import SourceViewerHeader from './SourceViewerHeader'; import SourceViewerHeader from './SourceViewerHeader';
import SourceViewerCode from './SourceViewerCode'; import SourceViewerCode from './SourceViewerCode';
import { SourceViewerContext } from './SourceViewerContext';
import DuplicationPopup from './components/DuplicationPopup'; import DuplicationPopup from './components/DuplicationPopup';
import defaultLoadIssues from './helpers/loadIssues'; import defaultLoadIssues from './helpers/loadIssues';
import getCoverageStatus from './helpers/getCoverageStatus'; import getCoverageStatus from './helpers/getCoverageStatus';
}); });


return ( 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>
); );
} }
} }

+ 0
- 1
server/sonar-web/src/main/js/components/SourceViewer/SourceViewerCode.tsx View File

return ( return (
<Line <Line
branchLike={this.props.branchLike} branchLike={this.props.branchLike}
componentKey={this.props.componentKey}
displayAllIssues={this.props.displayAllIssues} displayAllIssues={this.props.displayAllIssues}
displayCoverage={displayCoverage} displayCoverage={displayCoverage}
displayDuplications={displayDuplications} displayDuplications={displayDuplications}

server/sonar-web/src/main/js/apps/component/components/__tests__/App-test.tsx → server/sonar-web/src/main/js/components/SourceViewer/SourceViewerContext.tsx View File

* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
import * as React from 'react'; 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();
});
interface SourceViewerContextShape {
branchLike?: T.BranchLike;
file: T.SourceViewerFile;
}

export const SourceViewerContext = React.createContext({
branchLike: {},
file: {}
}) as React.Context<SourceViewerContextShape>;

+ 12
- 9
server/sonar-web/src/main/js/components/SourceViewer/SourceViewerHeader.tsx View File

getPathUrlAsString, getPathUrlAsString,
getBranchLikeUrl, getBranchLikeUrl,
getComponentIssuesUrl, getComponentIssuesUrl,
getBaseUrl
getBaseUrl,
getCodeUrl
} from '../../helpers/urls'; } from '../../helpers/urls';
import { collapsedDirFromPath, fileFromPath } from '../../helpers/path'; import { collapsedDirFromPath, fileFromPath } from '../../helpers/path';
import { translate } from '../../helpers/l10n'; import { translate } from '../../helpers/l10n';
</a> </a>
</li> </li>
<li> <li>
<a
<Link
className="js-new-window" 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')} {translate('component_viewer.new_window')}
</a>
</Link>
</li> </li>
{!workspace && ( {!workspace && (
<li> <li>
</li> </li>
)} )}
<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')} {translate('component_viewer.show_raw_source')}
</a> </a>
</li> </li>

+ 0
- 3
server/sonar-web/src/main/js/components/SourceViewer/components/Line.tsx View File



interface Props { interface Props {
branchLike: T.BranchLike | undefined; branchLike: T.BranchLike | undefined;
componentKey: string;
displayAllIssues?: boolean; displayAllIssues?: boolean;
displayCoverage: boolean; displayCoverage: boolean;
displayDuplications: boolean; displayDuplications: boolean;
return ( return (
<tr className={className} data-line-number={line.line}> <tr className={className} data-line-number={line.line}>
<LineNumber <LineNumber
branchLike={this.props.branchLike}
componentKey={this.props.componentKey}
line={line} line={line}
onPopupToggle={this.props.onLinePopupToggle} onPopupToggle={this.props.onLinePopupToggle}
popupOpen={this.isPopupOpen('line-number')} popupOpen={this.isPopupOpen('line-number')}

+ 2
- 6
server/sonar-web/src/main/js/components/SourceViewer/components/LineNumber.tsx View File

import Toggler from '../../controls/Toggler'; import Toggler from '../../controls/Toggler';


interface Props { interface Props {
branchLike: T.BranchLike | undefined;
componentKey: string;
line: T.SourceLine; line: T.SourceLine;
onPopupToggle: (x: { index?: number; line: number; name: string; open?: boolean }) => void; onPopupToggle: (x: { index?: number; line: number; name: string; open?: boolean }) => void;
popupOpen: boolean; popupOpen: boolean;
}; };


render() { render() {
const { branchLike, componentKey, line, popupOpen } = this.props;
const { line, popupOpen } = this.props;
const { line: lineNumber } = line; const { line: lineNumber } = line;
const hasLineNumber = !!lineNumber; const hasLineNumber = !!lineNumber;
return hasLineNumber ? ( return hasLineNumber ? (
<Toggler <Toggler
onRequestClose={this.closePopup} onRequestClose={this.closePopup}
open={popupOpen} open={popupOpen}
overlay={
<LineOptionsPopup branchLike={branchLike} componentKey={componentKey} line={line} />
}
overlay={<LineOptionsPopup line={line} />}
/> />
</td> </td>
) : ( ) : (

+ 21
- 15
server/sonar-web/src/main/js/components/SourceViewer/components/LineOptionsPopup.tsx View File

import { DropdownOverlay } from '../../controls/Dropdown'; import { DropdownOverlay } from '../../controls/Dropdown';
import { PopupPlacement } from '../../ui/popups'; import { PopupPlacement } from '../../ui/popups';
import { translate } from '../../../helpers/l10n'; import { translate } from '../../../helpers/l10n';
import { getBranchLikeQuery } from '../../../helpers/branches';
import { getCodeUrl } from '../../../helpers/urls';
import { SourceViewerContext } from '../SourceViewerContext';


interface Props { interface Props {
branchLike: T.BranchLike | undefined;
componentKey: string;
line: T.SourceLine; 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 ( 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>
); );
} }

+ 2
- 18
server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/LineNumber-test.tsx View File



it('render line 3', () => { it('render line 3', () => {
const line = { 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(); expect(wrapper).toMatchSnapshot();
click(wrapper); click(wrapper);
}); });


it('render line 0', () => { it('render line 0', () => {
const line = { 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(); expect(wrapper).toMatchSnapshot();
}); });

+ 11
- 7
server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/LineOptionsPopup-test.tsx View File

import { shallow } from 'enzyme'; import { shallow } from 'enzyme';
import LineOptionsPopup from '../LineOptionsPopup'; 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', () => { it('should render', () => {
const line = { line: 3 }; 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(); expect(wrapper).toMatchSnapshot();
}); });

+ 0
- 1
server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/LineNumber-test.tsx.snap View File

open={false} open={false}
overlay={ overlay={
<LineOptionsPopup <LineOptionsPopup
componentKey="foo"
line={ line={
Object { Object {
"line": 3, "line": 3,

+ 6
- 2
server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/LineOptionsPopup-test.tsx.snap View File

> >
<Link <Link
className="js-get-permalink" className="js-get-permalink"
onClick={[Function]}
onlyActiveOnIndex={false} onlyActiveOnIndex={false}
rel="noopener noreferrer"
style={Object {}} style={Object {}}
target="_blank"
to={ to={
Object { Object {
"pathname": "/component",
"pathname": "/code",
"query": Object { "query": Object {
"branch": "feature", "branch": "feature",
"id": "foo",
"id": "prj",
"line": 3, "line": 3,
"selected": "foo",
}, },
} }
} }

+ 10
- 2
server/sonar-web/src/main/js/helpers/urls.ts View File

return getBaseUrl() + '/markdown/help'; 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) { export function getOrganizationUrl(organization: string) {

Loading…
Cancel
Save