Browse Source

SONAR-15177 Improve code viewer when no component is analysis

tags/9.1.0.47736
Mathieu Suen 2 years ago
parent
commit
47a8580737

+ 5
- 0
server/sonar-web/src/main/js/apps/code/code.css View File

@@ -99,3 +99,8 @@ table > thead > tr.code-components-header > th {
height: 8px;
width: 4px;
}

.code-components .no-file .h1 {
position: fixed;
top: 50%;
}

server/sonar-web/src/main/js/apps/code/components/App.tsx → server/sonar-web/src/main/js/apps/code/components/AppCode.tsx View File

@@ -71,7 +71,7 @@ interface State {
total: number;
}

export class App extends React.PureComponent<Props, State> {
export class AppCode extends React.PureComponent<Props, State> {
mounted = false;
state: State;

@@ -255,6 +255,8 @@ export class App extends React.PureComponent<Props, State> {

const showSearch = searchResults !== undefined;

const hasNoFile = components.length === 0 && searchResults === undefined;

const shouldShowBreadcrumbs = breadcrumbs.length > 1 && !showSearch;
const shouldShowComponentList =
sourceViewer === undefined && components.length > 0 && !showSearch;
@@ -278,14 +280,26 @@ export class App extends React.PureComponent<Props, State> {
/>
<A11ySkipTarget anchor="code_main" />

<Search
branchLike={branchLike}
component={component}
onSearchClear={this.handleSearchClear}
onSearchResults={this.handleSearchResults}
/>
{!hasNoFile && (
<Search
branchLike={branchLike}
component={component}
onSearchClear={this.handleSearchClear}
onSearchResults={this.handleSearchResults}
/>
)}

<div className="code-components">
{hasNoFile && (
<div className="display-flex-center display-flex-column no-file">
<span className="h1 text-muted">
{translate(
'code_viewer.no_source_code_displayed_due_to_empty_analysis',
component.qualifier
)}
</span>
</div>
)}
{shouldShowBreadcrumbs && (
<Breadcrumbs
branchLike={branchLike}
@@ -360,4 +374,4 @@ const mapDispatchToProps: DispatchToProps = {
export default connect<StateToProps, DispatchToProps, Props>(
mapStateToProps,
mapDispatchToProps
)(App);
)(AppCode);

+ 0
- 108
server/sonar-web/src/main/js/apps/code/components/__tests__/App-test.tsx View File

@@ -1,108 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2021 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 { shallow } from 'enzyme';
import * as React from 'react';
import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
import { mockPullRequest } from '../../../../helpers/mocks/branch-like';
import { mockIssue, mockRouter } from '../../../../helpers/testMocks';
import { retrieveComponent } from '../../utils';
import { App } from '../App';

jest.mock('../../utils', () => ({
retrieveComponent: jest.fn().mockResolvedValue({
breadcrumbs: [],
component: { qualifier: 'APP' },
components: [],
page: 0,
total: 1
}),
retrieveComponentChildren: () => Promise.resolve()
}));

const METRICS = {
coverage: { id: '2', key: 'coverage', type: 'PERCENT', name: 'Coverage', domain: 'Coverage' },
new_bugs: { id: '4', key: 'new_bugs', type: 'INT', name: 'New Bugs', domain: 'Reliability' }
};

beforeEach(() => {
(retrieveComponent as jest.Mock<any>).mockClear();
});

it('should have correct title for APP based component', async () => {
const wrapper = shallowRender();
await waitAndUpdate(wrapper);
expect(wrapper.find('Helmet')).toMatchSnapshot();
});

it('should have correct title for portfolio base component', async () => {
(retrieveComponent as jest.Mock<any>).mockResolvedValueOnce({
breadcrumbs: [],
component: { qualifier: 'VW' },
components: [],
page: 0,
total: 1
});
const wrapper = shallowRender();
await waitAndUpdate(wrapper);
expect(wrapper.find('Helmet')).toMatchSnapshot();
});

it('should have correct title for project component', async () => {
(retrieveComponent as jest.Mock<any>).mockResolvedValueOnce({
breadcrumbs: [],
component: { qualifier: 'TRK' },
components: [],
page: 0,
total: 1
});
const wrapper = shallowRender();
await waitAndUpdate(wrapper);
expect(wrapper.find('Helmet')).toMatchSnapshot();
});

it('should refresh branch status if issues are updated', async () => {
const fetchBranchStatus = jest.fn();
const branchLike = mockPullRequest();
const wrapper = shallowRender({ branchLike, fetchBranchStatus });
const instance = wrapper.instance();
await waitAndUpdate(wrapper);

instance.handleIssueChange(mockIssue());
expect(fetchBranchStatus).toBeCalledWith(branchLike, 'foo');
});

function shallowRender(props: Partial<App['props']> = {}) {
return shallow<App>(
<App
component={{
breadcrumbs: [],
name: 'foo',
key: 'foo',
qualifier: 'FOO'
}}
fetchBranchStatus={jest.fn()}
fetchMetrics={jest.fn()}
location={{ query: { branch: 'b', id: 'foo', line: '7' } }}
metrics={METRICS}
router={mockRouter()}
{...props}
/>
);
}

+ 198
- 0
server/sonar-web/src/main/js/apps/code/components/__tests__/AppCode-test.tsx View File

@@ -0,0 +1,198 @@
/*
* SonarQube
* Copyright (C) 2009-2021 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 { shallow } from 'enzyme';
import * as React from 'react';
import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
import { mockPullRequest } from '../../../../helpers/mocks/branch-like';
import {
mockComponent,
mockComponentMeasure,
mockIssue,
mockRouter
} from '../../../../helpers/testMocks';
import { ComponentQualifier } from '../../../../types/component';
import { loadMoreChildren, retrieveComponent } from '../../utils';
import { AppCode } from '../AppCode';

jest.mock('../../utils', () => ({
loadMoreChildren: jest.fn().mockResolvedValue({}),
retrieveComponent: jest.fn().mockResolvedValue({
breadcrumbs: [],
component: { qualifier: 'APP' },
components: [],
page: 0,
total: 1
}),
retrieveComponentChildren: () => Promise.resolve()
}));

const METRICS = {
coverage: { id: '2', key: 'coverage', type: 'PERCENT', name: 'Coverage', domain: 'Coverage' },
new_bugs: { id: '4', key: 'new_bugs', type: 'INT', name: 'New Bugs', domain: 'Reliability' }
};

beforeEach(() => {
(retrieveComponent as jest.Mock<any>).mockClear();
});

it.each([
[ComponentQualifier.Application],
[ComponentQualifier.Project],
[ComponentQualifier.Portfolio],
[ComponentQualifier.SubPortfolio]
])('should render correclty when no sub component for %s', async qualifier => {
const component = { breadcrumbs: [], name: 'foo', key: 'foo', qualifier };
(retrieveComponent as jest.Mock<any>).mockResolvedValueOnce({
breadcrumbs: [],
component,
components: [],
page: 0,
total: 1
});
const wrapper = shallowRender({ component });
await waitAndUpdate(wrapper);
expect(wrapper).toMatchSnapshot();
wrapper.instance().handleSearchResults([]);
expect(wrapper).toMatchSnapshot('no search');
(retrieveComponent as jest.Mock<any>).mockResolvedValueOnce({
breadcrumbs: [],
component,
components: [mockComponent({ qualifier: ComponentQualifier.File })],
page: 0,
total: 1
});
wrapper.instance().loadComponent(component.key);
await waitAndUpdate(wrapper);
expect(wrapper).toMatchSnapshot('with sub component');
});

it('should refresh branch status if issues are updated', async () => {
const fetchBranchStatus = jest.fn();
const branchLike = mockPullRequest();
const wrapper = shallowRender({ branchLike, fetchBranchStatus });
const instance = wrapper.instance();
await waitAndUpdate(wrapper);

instance.handleIssueChange(mockIssue());
expect(fetchBranchStatus).toBeCalledWith(branchLike, 'foo');
});

it('should load more behave correctly', async () => {
const component1 = mockComponent();
const component2 = mockComponent();
(retrieveComponent as jest.Mock<any>).mockResolvedValueOnce({
breadcrumbs: [],
component: mockComponent(),
components: [component1],
page: 0,
total: 1
});
let wrapper = shallowRender();
await waitAndUpdate(wrapper);

(loadMoreChildren as jest.Mock<any>).mockResolvedValueOnce({
components: [component2],
page: 0,
total: 1
});

wrapper.instance().handleLoadMore();
expect(wrapper.state().components).toContainEqual(component1);
expect(wrapper.state().components).toContainEqual(component2);

(retrieveComponent as jest.Mock<any>).mockRejectedValueOnce({});
wrapper = shallowRender();
await waitAndUpdate(wrapper);
wrapper.instance().handleLoadMore();
expect(wrapper.state().components).toBeUndefined();
});

it('should handle go to parent correctly', async () => {
const router = mockRouter();
(retrieveComponent as jest.Mock<any>).mockResolvedValueOnce({
breadcrumbs: [],
component: mockComponent(),
components: [],
page: 0,
total: 1
});
let wrapper = shallowRender();
await waitAndUpdate(wrapper);
wrapper.instance().handleGoToParent();
expect(wrapper.state().highlighted).toBeUndefined();

const breadcrumb = { key: 'key2', name: 'name2', qualifier: ComponentQualifier.Directory };
(retrieveComponent as jest.Mock<any>).mockResolvedValueOnce({
breadcrumbs: [
{ key: 'key1', name: 'name1', qualifier: ComponentQualifier.Directory },
breadcrumb
],
component: mockComponent(),
components: [],
page: 0,
total: 1
});
wrapper = shallowRender({ router });
await waitAndUpdate(wrapper);
wrapper.instance().handleGoToParent();
expect(wrapper.state().highlighted).toBe(breadcrumb);
expect(router.push).toHaveBeenCalledWith({
pathname: '/code',
query: { id: 'foo', line: undefined, selected: 'key1' }
});
});

it('should handle select correctly', () => {
const router = mockRouter();
const wrapper = shallowRender({ router });
wrapper.setState({ highlighted: mockComponentMeasure() });

wrapper.instance().handleSelect(mockComponentMeasure(true, { refKey: 'test' }));
expect(router.push).toHaveBeenCalledWith({
pathname: '/dashboard',
query: { branch: undefined, id: 'test' }
});
expect(wrapper.state().highlighted).toBeUndefined();

wrapper.instance().handleSelect(mockComponentMeasure());
expect(router.push).toHaveBeenCalledWith({
pathname: '/dashboard',
query: { branch: undefined, id: 'test' }
});
});

function shallowRender(props: Partial<AppCode['props']> = {}) {
return shallow<AppCode>(
<AppCode
component={{
breadcrumbs: [],
name: 'foo',
key: 'foo',
qualifier: 'FOO'
}}
fetchBranchStatus={jest.fn()}
fetchMetrics={jest.fn()}
location={{ query: { branch: 'b', id: 'foo', line: '7' } }}
metrics={METRICS}
router={mockRouter()}
{...props}
/>
);
}

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

@@ -1,25 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should have correct title for APP based component 1`] = `
<Helmet
defer={false}
encodeSpecialCharacters={true}
title="projects.page"
/>
`;

exports[`should have correct title for portfolio base component 1`] = `
<Helmet
defer={false}
encodeSpecialCharacters={true}
title="projects.page"
/>
`;

exports[`should have correct title for project component 1`] = `
<Helmet
defer={false}
encodeSpecialCharacters={true}
title="code.page"
/>
`;

+ 765
- 0
server/sonar-web/src/main/js/apps/code/components/__tests__/__snapshots__/AppCode-test.tsx.snap View File

@@ -0,0 +1,765 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should render correclty when no sub component for APP 1`] = `
<div
className="page page-limited"
>
<Suggestions
suggestions="code"
/>
<Helmet
defer={false}
encodeSpecialCharacters={true}
title="projects.page"
/>
<A11ySkipTarget
anchor="code_main"
/>
<div
className="code-components"
>
<div
className="display-flex-center display-flex-column no-file"
>
<span
className="h1 text-muted"
>
code_viewer.no_source_code_displayed_due_to_empty_analysis.APP
</span>
</div>
</div>
</div>
`;

exports[`should render correclty when no sub component for APP: no search 1`] = `
<div
className="page page-limited"
>
<Suggestions
suggestions="code"
/>
<Helmet
defer={false}
encodeSpecialCharacters={true}
title="projects.page"
/>
<A11ySkipTarget
anchor="code_main"
/>
<withRouter(Search)
component={
Object {
"breadcrumbs": Array [],
"key": "foo",
"name": "foo",
"qualifier": "APP",
}
}
onSearchClear={[Function]}
onSearchResults={[Function]}
/>
<div
className="code-components"
>
<div
className="boxed-group spacer-top search-results"
>
<withKeyboardNavigation(Components)
components={Array []}
metrics={Object {}}
onHighlight={[Function]}
onSelect={[Function]}
rootComponent={
Object {
"breadcrumbs": Array [],
"key": "foo",
"name": "foo",
"qualifier": "APP",
}
}
/>
</div>
</div>
</div>
`;

exports[`should render correclty when no sub component for APP: with sub component 1`] = `
<div
className="page page-limited"
>
<Suggestions
suggestions="code"
/>
<Helmet
defer={false}
encodeSpecialCharacters={true}
title="projects.page"
/>
<A11ySkipTarget
anchor="code_main"
/>
<withRouter(Search)
component={
Object {
"breadcrumbs": Array [],
"key": "foo",
"name": "foo",
"qualifier": "APP",
}
}
onSearchClear={[Function]}
onSearchResults={[Function]}
/>
<div
className="code-components"
>
<div
className="boxed-group spacer-top"
>
<withKeyboardNavigation(Components)
baseComponent={
Object {
"breadcrumbs": Array [],
"key": "foo",
"name": "foo",
"qualifier": "APP",
}
}
components={
Array [
Object {
"breadcrumbs": Array [],
"key": "my-project",
"name": "MyProject",
"qualifier": "FIL",
"qualityGate": Object {
"isDefault": true,
"key": "30",
"name": "Sonar way",
},
"qualityProfiles": Array [
Object {
"deleted": false,
"key": "my-qp",
"language": "ts",
"name": "Sonar way",
},
],
"tags": Array [],
},
]
}
cycle={true}
metrics={
Object {
"coverage": Object {
"domain": "Coverage",
"id": "2",
"key": "coverage",
"name": "Coverage",
"type": "PERCENT",
},
"new_bugs": Object {
"domain": "Reliability",
"id": "4",
"key": "new_bugs",
"name": "New Bugs",
"type": "INT",
},
}
}
onEndOfList={[Function]}
onGoToParent={[Function]}
onHighlight={[Function]}
onSelect={[Function]}
rootComponent={
Object {
"breadcrumbs": Array [],
"key": "foo",
"name": "foo",
"qualifier": "APP",
}
}
/>
</div>
<ListFooter
count={1}
loadMore={[Function]}
total={1}
/>
</div>
</div>
`;

exports[`should render correclty when no sub component for SVW 1`] = `
<div
className="page page-limited"
>
<Suggestions
suggestions="code"
/>
<Helmet
defer={false}
encodeSpecialCharacters={true}
title="projects.page"
/>
<A11ySkipTarget
anchor="code_main"
/>
<div
className="code-components"
>
<div
className="display-flex-center display-flex-column no-file"
>
<span
className="h1 text-muted"
>
code_viewer.no_source_code_displayed_due_to_empty_analysis.SVW
</span>
</div>
</div>
</div>
`;

exports[`should render correclty when no sub component for SVW: no search 1`] = `
<div
className="page page-limited"
>
<Suggestions
suggestions="code"
/>
<Helmet
defer={false}
encodeSpecialCharacters={true}
title="projects.page"
/>
<A11ySkipTarget
anchor="code_main"
/>
<withRouter(Search)
component={
Object {
"breadcrumbs": Array [],
"key": "foo",
"name": "foo",
"qualifier": "SVW",
}
}
onSearchClear={[Function]}
onSearchResults={[Function]}
/>
<div
className="code-components"
>
<div
className="boxed-group spacer-top search-results"
>
<withKeyboardNavigation(Components)
components={Array []}
metrics={Object {}}
onHighlight={[Function]}
onSelect={[Function]}
rootComponent={
Object {
"breadcrumbs": Array [],
"key": "foo",
"name": "foo",
"qualifier": "SVW",
}
}
/>
</div>
</div>
</div>
`;

exports[`should render correclty when no sub component for SVW: with sub component 1`] = `
<div
className="page page-limited"
>
<Suggestions
suggestions="code"
/>
<Helmet
defer={false}
encodeSpecialCharacters={true}
title="projects.page"
/>
<A11ySkipTarget
anchor="code_main"
/>
<withRouter(Search)
component={
Object {
"breadcrumbs": Array [],
"key": "foo",
"name": "foo",
"qualifier": "SVW",
}
}
onSearchClear={[Function]}
onSearchResults={[Function]}
/>
<div
className="code-components"
>
<div
className="boxed-group spacer-top"
>
<withKeyboardNavigation(Components)
baseComponent={
Object {
"breadcrumbs": Array [],
"key": "foo",
"name": "foo",
"qualifier": "SVW",
}
}
components={
Array [
Object {
"breadcrumbs": Array [],
"key": "my-project",
"name": "MyProject",
"qualifier": "FIL",
"qualityGate": Object {
"isDefault": true,
"key": "30",
"name": "Sonar way",
},
"qualityProfiles": Array [
Object {
"deleted": false,
"key": "my-qp",
"language": "ts",
"name": "Sonar way",
},
],
"tags": Array [],
},
]
}
cycle={true}
metrics={
Object {
"coverage": Object {
"domain": "Coverage",
"id": "2",
"key": "coverage",
"name": "Coverage",
"type": "PERCENT",
},
"new_bugs": Object {
"domain": "Reliability",
"id": "4",
"key": "new_bugs",
"name": "New Bugs",
"type": "INT",
},
}
}
onEndOfList={[Function]}
onGoToParent={[Function]}
onHighlight={[Function]}
onSelect={[Function]}
rootComponent={
Object {
"breadcrumbs": Array [],
"key": "foo",
"name": "foo",
"qualifier": "SVW",
}
}
/>
</div>
<ListFooter
count={1}
loadMore={[Function]}
total={1}
/>
</div>
</div>
`;

exports[`should render correclty when no sub component for TRK 1`] = `
<div
className="page page-limited"
>
<Suggestions
suggestions="code"
/>
<Helmet
defer={false}
encodeSpecialCharacters={true}
title="code.page"
/>
<A11ySkipTarget
anchor="code_main"
/>
<div
className="code-components"
>
<div
className="display-flex-center display-flex-column no-file"
>
<span
className="h1 text-muted"
>
code_viewer.no_source_code_displayed_due_to_empty_analysis.TRK
</span>
</div>
</div>
</div>
`;

exports[`should render correclty when no sub component for TRK: no search 1`] = `
<div
className="page page-limited"
>
<Suggestions
suggestions="code"
/>
<Helmet
defer={false}
encodeSpecialCharacters={true}
title="code.page"
/>
<A11ySkipTarget
anchor="code_main"
/>
<withRouter(Search)
component={
Object {
"breadcrumbs": Array [],
"key": "foo",
"name": "foo",
"qualifier": "TRK",
}
}
onSearchClear={[Function]}
onSearchResults={[Function]}
/>
<div
className="code-components"
>
<div
className="boxed-group spacer-top search-results"
>
<withKeyboardNavigation(Components)
components={Array []}
metrics={Object {}}
onHighlight={[Function]}
onSelect={[Function]}
rootComponent={
Object {
"breadcrumbs": Array [],
"key": "foo",
"name": "foo",
"qualifier": "TRK",
}
}
/>
</div>
</div>
</div>
`;

exports[`should render correclty when no sub component for TRK: with sub component 1`] = `
<div
className="page page-limited"
>
<Suggestions
suggestions="code"
/>
<Helmet
defer={false}
encodeSpecialCharacters={true}
title="code.page"
/>
<A11ySkipTarget
anchor="code_main"
/>
<withRouter(Search)
component={
Object {
"breadcrumbs": Array [],
"key": "foo",
"name": "foo",
"qualifier": "TRK",
}
}
onSearchClear={[Function]}
onSearchResults={[Function]}
/>
<div
className="code-components"
>
<div
className="boxed-group spacer-top"
>
<withKeyboardNavigation(Components)
baseComponent={
Object {
"breadcrumbs": Array [],
"key": "foo",
"name": "foo",
"qualifier": "TRK",
}
}
components={
Array [
Object {
"breadcrumbs": Array [],
"key": "my-project",
"name": "MyProject",
"qualifier": "FIL",
"qualityGate": Object {
"isDefault": true,
"key": "30",
"name": "Sonar way",
},
"qualityProfiles": Array [
Object {
"deleted": false,
"key": "my-qp",
"language": "ts",
"name": "Sonar way",
},
],
"tags": Array [],
},
]
}
cycle={true}
metrics={
Object {
"coverage": Object {
"domain": "Coverage",
"id": "2",
"key": "coverage",
"name": "Coverage",
"type": "PERCENT",
},
"new_bugs": Object {
"domain": "Reliability",
"id": "4",
"key": "new_bugs",
"name": "New Bugs",
"type": "INT",
},
}
}
onEndOfList={[Function]}
onGoToParent={[Function]}
onHighlight={[Function]}
onSelect={[Function]}
rootComponent={
Object {
"breadcrumbs": Array [],
"key": "foo",
"name": "foo",
"qualifier": "TRK",
}
}
/>
</div>
<ListFooter
count={1}
loadMore={[Function]}
total={1}
/>
</div>
</div>
`;

exports[`should render correclty when no sub component for VW 1`] = `
<div
className="page page-limited"
>
<Suggestions
suggestions="code"
/>
<Helmet
defer={false}
encodeSpecialCharacters={true}
title="projects.page"
/>
<A11ySkipTarget
anchor="code_main"
/>
<div
className="code-components"
>
<div
className="display-flex-center display-flex-column no-file"
>
<span
className="h1 text-muted"
>
code_viewer.no_source_code_displayed_due_to_empty_analysis.VW
</span>
</div>
</div>
</div>
`;

exports[`should render correclty when no sub component for VW: no search 1`] = `
<div
className="page page-limited"
>
<Suggestions
suggestions="code"
/>
<Helmet
defer={false}
encodeSpecialCharacters={true}
title="projects.page"
/>
<A11ySkipTarget
anchor="code_main"
/>
<withRouter(Search)
component={
Object {
"breadcrumbs": Array [],
"key": "foo",
"name": "foo",
"qualifier": "VW",
}
}
onSearchClear={[Function]}
onSearchResults={[Function]}
/>
<div
className="code-components"
>
<div
className="boxed-group spacer-top search-results"
>
<withKeyboardNavigation(Components)
components={Array []}
metrics={Object {}}
onHighlight={[Function]}
onSelect={[Function]}
rootComponent={
Object {
"breadcrumbs": Array [],
"key": "foo",
"name": "foo",
"qualifier": "VW",
}
}
/>
</div>
</div>
</div>
`;

exports[`should render correclty when no sub component for VW: with sub component 1`] = `
<div
className="page page-limited"
>
<Suggestions
suggestions="code"
/>
<Helmet
defer={false}
encodeSpecialCharacters={true}
title="projects.page"
/>
<A11ySkipTarget
anchor="code_main"
/>
<withRouter(Search)
component={
Object {
"breadcrumbs": Array [],
"key": "foo",
"name": "foo",
"qualifier": "VW",
}
}
onSearchClear={[Function]}
onSearchResults={[Function]}
/>
<div
className="code-components"
>
<div
className="boxed-group spacer-top"
>
<withKeyboardNavigation(Components)
baseComponent={
Object {
"breadcrumbs": Array [],
"key": "foo",
"name": "foo",
"qualifier": "VW",
}
}
components={
Array [
Object {
"breadcrumbs": Array [],
"key": "my-project",
"name": "MyProject",
"qualifier": "FIL",
"qualityGate": Object {
"isDefault": true,
"key": "30",
"name": "Sonar way",
},
"qualityProfiles": Array [
Object {
"deleted": false,
"key": "my-qp",
"language": "ts",
"name": "Sonar way",
},
],
"tags": Array [],
},
]
}
cycle={true}
metrics={
Object {
"coverage": Object {
"domain": "Coverage",
"id": "2",
"key": "coverage",
"name": "Coverage",
"type": "PERCENT",
},
"new_bugs": Object {
"domain": "Reliability",
"id": "4",
"key": "new_bugs",
"name": "New Bugs",
"type": "INT",
},
}
}
onEndOfList={[Function]}
onGoToParent={[Function]}
onHighlight={[Function]}
onSelect={[Function]}
rootComponent={
Object {
"breadcrumbs": Array [],
"key": "foo",
"name": "foo",
"qualifier": "VW",
}
}
/>
</div>
<ListFooter
count={1}
loadMore={[Function]}
total={1}
/>
</div>
</div>
`;

+ 1
- 1
server/sonar-web/src/main/js/apps/code/routes.ts View File

@@ -21,7 +21,7 @@ import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent'

const routes = [
{
indexRoute: { component: lazyLoadComponent(() => import('./components/App')) }
indexRoute: { component: lazyLoadComponent(() => import('./components/AppCode')) }
}
];


+ 4
- 0
sonar-core/src/main/resources/org/sonar/l10n/core.properties View File

@@ -1401,6 +1401,10 @@ duplications.dups_found_on_deleted_resource=This file contains duplicated blocks
# GENERIC CODE VIEWER
#
#------------------------------------------------------------------------------
code_viewer.no_source_code_displayed_due_to_empty_analysis.TRK=No code files were found for analysis.
code_viewer.no_source_code_displayed_due_to_empty_analysis.APP=No projects in this application.
code_viewer.no_source_code_displayed_due_to_empty_analysis.VW=No projects, applications, or portfolios in this portfolio.
code_viewer.no_source_code_displayed_due_to_empty_analysis.SVW=No projects, applications, or portfolios in this portfolio.
code_viewer.no_source_code_displayed_due_to_security=Due to security settings, no source code can be displayed.
code_viewer.no_source_code_displayed_due_to_source_removed=The file was removed, no source code can be displayed.


Loading…
Cancel
Save