aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web
diff options
context:
space:
mode:
authorJeremy Davis <jeremy.davis@sonarsource.com>2019-07-01 18:53:17 +0200
committerSonarTech <sonartech@sonarsource.com>2019-07-18 20:21:12 +0200
commit437a3a305e14e6ac3413eaaf36f1cd68c5a79c28 (patch)
treef99d22461bf0f388e1fff7e809ae673ef1cd5607 /server/sonar-web
parent6ddad7c6256d38730615495b0bf8e189fba147cc (diff)
downloadsonarqube-437a3a305e14e6ac3413eaaf36f1cd68c5a79c28.tar.gz
sonarqube-437a3a305e14e6ac3413eaaf36f1cd68c5a79c28.zip
SONAR-12022 Animate snippets
Diffstat (limited to 'server/sonar-web')
-rw-r--r--server/sonar-web/src/main/js/app/types.d.ts7
-rw-r--r--server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/ComponentSourceSnippetViewer.tsx187
-rw-r--r--server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/SnippetViewer.tsx83
-rw-r--r--server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/ComponentSourceSnippetViewer-test.tsx151
-rw-r--r--server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/__snapshots__/SnippetViewer-test.tsx.snap1792
-rw-r--r--server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/utils-test.ts57
-rw-r--r--server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/utils.ts144
-rw-r--r--server/sonar-web/src/main/js/apps/issues/styles.css35
8 files changed, 1337 insertions, 1119 deletions
diff --git a/server/sonar-web/src/main/js/app/types.d.ts b/server/sonar-web/src/main/js/app/types.d.ts
index 415a5f2e276..09accb78d73 100644
--- a/server/sonar-web/src/main/js/app/types.d.ts
+++ b/server/sonar-web/src/main/js/app/types.d.ts
@@ -792,6 +792,13 @@ declare namespace T {
type: 'SHORT';
}
+ export interface Snippet {
+ start: number;
+ end: number;
+ index: number;
+ toDelete?: boolean;
+ }
+
export interface SnippetGroup extends SnippetsByComponent {
locations: T.FlowLocation[];
}
diff --git a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/ComponentSourceSnippetViewer.tsx b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/ComponentSourceSnippetViewer.tsx
index d9e14742a19..90332683273 100644
--- a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/ComponentSourceSnippetViewer.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/ComponentSourceSnippetViewer.tsx
@@ -19,7 +19,13 @@
*/
import * as React from 'react';
import * as classNames from 'classnames';
-import { createSnippets, expandSnippet, EXPAND_BY_LINES, MERGE_DISTANCE } from './utils';
+import {
+ createSnippets,
+ expandSnippet,
+ EXPAND_BY_LINES,
+ MERGE_DISTANCE,
+ linesForSnippets
+} from './utils';
import SnippetViewer from './SnippetViewer';
import SourceViewerHeaderSlim from '../../../components/SourceViewer/SourceViewerHeaderSlim';
import getCoverageStatus from '../../../components/SourceViewer/helpers/getCoverageStatus';
@@ -57,11 +63,12 @@ interface State {
highlightedSymbols: string[];
loading: boolean;
openIssuesByLine: T.Dict<boolean>;
- snippets: T.SourceLine[][];
+ snippets: T.Snippet[];
}
export default class ComponentSourceSnippetViewer extends React.PureComponent<Props, State> {
mounted = false;
+ rootNodeRef = React.createRef<HTMLDivElement>();
state: State = {
additionalLines: {},
highlightedSymbols: [],
@@ -80,35 +87,78 @@ export default class ComponentSourceSnippetViewer extends React.PureComponent<Pr
}
createSnippetsFromProps() {
- const snippets = createSnippets(
- this.props.snippetGroup.locations,
- this.props.snippetGroup.sources,
- this.props.last
- );
+ const snippets = createSnippets(this.props.snippetGroup.locations, this.props.last);
this.setState({ snippets });
}
+ getNodes(index: number): { wrapper: HTMLElement; table: HTMLElement } | undefined {
+ const root = this.rootNodeRef.current;
+ if (!root) {
+ return undefined;
+ }
+ const element = root.querySelector(`#snippet-wrapper-${index}`);
+ if (!element) {
+ return undefined;
+ }
+ const wrapper = element.querySelector<HTMLElement>('.snippet');
+ if (!wrapper) {
+ return undefined;
+ }
+ const table = wrapper.firstChild as HTMLElement;
+ if (!table) {
+ return undefined;
+ }
+
+ return { wrapper, table };
+ }
+
+ setMaxHeight(index: number, value?: number, up = false) {
+ const nodes = this.getNodes(index);
+
+ if (!nodes) {
+ return;
+ }
+
+ const { wrapper, table } = nodes;
+
+ const maxHeight = value !== undefined ? value : table.getBoundingClientRect().height;
+
+ if (up) {
+ const startHeight = wrapper.getBoundingClientRect().height;
+ table.style.transition = 'none';
+ table.style.marginTop = `${startHeight - maxHeight}px`;
+
+ // animate!
+ setTimeout(() => {
+ table.style.transition = '';
+ table.style.marginTop = '0px';
+ wrapper.style.maxHeight = `${maxHeight + 20}px`;
+ }, 0);
+ } else {
+ wrapper.style.maxHeight = `${maxHeight + 20}px`;
+ }
+ }
+
expandBlock = (snippetIndex: number, direction: T.ExpandDirection) => {
const { branchLike, snippetGroup } = this.props;
const { key } = snippetGroup.component;
const { snippets } = this.state;
-
- const snippet = snippets[snippetIndex];
-
+ const snippet = snippets.find(s => s.index === snippetIndex);
+ if (!snippet) {
+ return;
+ }
// Extend by EXPAND_BY_LINES and add buffer for merging snippets
const extension = EXPAND_BY_LINES + MERGE_DISTANCE - 1;
-
const range =
direction === 'up'
? {
- from: Math.max(1, snippet[0].line - extension),
- to: snippet[0].line - 1
+ from: Math.max(1, snippet.start - extension),
+ to: snippet.start - 1
}
: {
- from: snippet[snippet.length - 1].line + 1,
- to: snippet[snippet.length - 1].line + extension
+ from: snippet.end + 1,
+ to: snippet.end + extension
};
-
getSources({
key,
...range,
@@ -122,27 +172,55 @@ export default class ComponentSourceSnippetViewer extends React.PureComponent<Pr
}, {})
)
.then(
- newLinesMapped => {
- if (this.mounted) {
- this.setState(({ additionalLines, snippets }) => {
- const combinedLines = { ...additionalLines, ...newLinesMapped };
-
- return {
- additionalLines: combinedLines,
- snippets: expandSnippet({
- direction,
- lines: { ...combinedLines, ...this.props.snippetGroup.sources },
- snippetIndex,
- snippets
- })
- };
- });
- }
- },
+ newLinesMapped => this.animateBlockExpansion(snippetIndex, direction, newLinesMapped),
() => {}
);
};
+ animateBlockExpansion(
+ snippetIndex: number,
+ direction: T.ExpandDirection,
+ newLinesMapped: T.Dict<T.SourceLine>
+ ) {
+ if (this.mounted) {
+ const { snippets } = this.state;
+
+ const newSnippets = expandSnippet({
+ direction,
+ snippetIndex,
+ snippets
+ });
+
+ const deletedSnippets = newSnippets.filter(s => s.toDelete);
+
+ // set max-height to current height for CSS transitions
+ deletedSnippets.forEach(s => this.setMaxHeight(s.index));
+ this.setMaxHeight(snippetIndex);
+
+ this.setState(
+ ({ additionalLines, snippets }) => {
+ const combinedLines = { ...additionalLines, ...newLinesMapped };
+ return {
+ additionalLines: combinedLines,
+ snippets
+ };
+ },
+ () => {
+ // Set max-height 0 to trigger CSS transitions
+ deletedSnippets.forEach(s => {
+ this.setMaxHeight(s.index, 0);
+ });
+ this.setMaxHeight(snippetIndex, undefined, direction === 'up');
+
+ // Wait for transition to finish before updating dom
+ setTimeout(() => {
+ this.setState({ snippets: newSnippets.filter(s => !s.toDelete) });
+ }, 200);
+ }
+ );
+ }
+ }
+
expandComponent = () => {
const { branchLike, snippetGroup } = this.props;
const { key } = snippetGroup.component;
@@ -152,7 +230,14 @@ export default class ComponentSourceSnippetViewer extends React.PureComponent<Pr
getSources({ key, ...getBranchLikeQuery(branchLike) }).then(
lines => {
if (this.mounted) {
- this.setState({ loading: false, snippets: [lines] });
+ this.setState(({ additionalLines }) => {
+ const combinedLines = { ...additionalLines, ...lines };
+ return {
+ additionalLines: combinedLines,
+ loading: false,
+ snippets: [{ start: 0, end: lines[lines.length - 1].line, index: -1 }]
+ };
+ });
}
},
() => {
@@ -222,7 +307,6 @@ export default class ComponentSourceSnippetViewer extends React.PureComponent<Pr
issue={this.props.issue}
issuePopup={this.props.issuePopup}
issuesByLine={issuesByLine}
- key={index}
last={last}
loadDuplications={this.loadDuplications}
locations={this.props.locations}
@@ -240,19 +324,26 @@ export default class ComponentSourceSnippetViewer extends React.PureComponent<Pr
render() {
const { branchLike, duplications, issue, issuesByLine, last, snippetGroup } = this.props;
- const { loading, snippets } = this.state;
+ const { additionalLines, loading, snippets } = this.state;
const locations = locationsByLine([issue]);
const fullyShown =
snippets.length === 1 &&
snippetGroup.component.measures &&
- snippets[0].length === parseInt(snippetGroup.component.measures.lines || '', 10);
+ snippets[0].end - snippets[0].start ===
+ parseInt(snippetGroup.component.measures.lines || '', 10);
+
+ const snippetLines = linesForSnippets(snippets, {
+ ...snippetGroup.sources,
+ ...additionalLines
+ });
return (
<div
className={classNames('component-source-container', {
'source-duplications-expanded': duplications && duplications.length > 0
- })}>
+ })}
+ ref={this.rootNodeRef}>
<SourceViewerHeaderSlim
branchLike={branchLike}
expandable={!fullyShown}
@@ -260,15 +351,17 @@ export default class ComponentSourceSnippetViewer extends React.PureComponent<Pr
onExpand={this.expandComponent}
sourceViewerFile={snippetGroup.component}
/>
- {snippets.map((snippet, index) =>
- this.renderSnippet({
- snippet,
- index,
- issuesByLine: last ? issuesByLine : {},
- locationsByLine: last && index === snippets.length - 1 ? locations : {},
- last: last && index === snippets.length - 1
- })
- )}
+ {snippetLines.map((snippet, index) => (
+ <div id={`snippet-wrapper-${snippets[index].index}`} key={snippets[index].index}>
+ {this.renderSnippet({
+ snippet,
+ index: snippets[index].index,
+ issuesByLine: last ? issuesByLine : {},
+ locationsByLine: last && index === snippets.length - 1 ? locations : {},
+ last: last && index === snippets.length - 1
+ })}
+ </div>
+ ))}
</div>
);
}
diff --git a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/SnippetViewer.tsx b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/SnippetViewer.tsx
index daa6af037f4..91ded7f72fd 100644
--- a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/SnippetViewer.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/SnippetViewer.tsx
@@ -18,6 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import classNames from 'classnames';
import ExpandSnippetIcon from 'sonar-ui-common/components/icons/ExpandSnippetIcon';
import { scrollHorizontally } from 'sonar-ui-common/helpers/scrolling';
import { translate } from 'sonar-ui-common/helpers/l10n';
@@ -191,46 +192,48 @@ export default class SnippetViewer extends React.PureComponent<Props> {
return (
<div className="source-viewer-code snippet" ref={this.node}>
- <table className="source-table">
- <tbody>
- {snippet[0].line > 1 && (
- <tr className="expand-block expand-block-above">
- <td colSpan={5}>
- <button
- aria-label={translate('source_viewer.expand_above')}
- onClick={this.expandBlock('up')}
- type="button">
- <ExpandSnippetIcon />
- </button>
- </td>
- </tr>
- )}
- {snippet.map((line, index) =>
- this.renderLine({
- displayDuplications,
- index,
- issuesForLine: issuesByLine[line.line] || [],
- issueLocations: locationsByLine[line.line] || [],
- line,
- snippet,
- symbols: symbols[line.line],
- verticalBuffer: index === snippet.length - 1 ? verticalBuffer : 0
- })
- )}
- {(!lastLine || snippet[snippet.length - 1].line < lastLine) && (
- <tr className="expand-block expand-block-below">
- <td colSpan={5}>
- <button
- aria-label={translate('source_viewer.expand_below')}
- onClick={this.expandBlock('down')}
- type="button">
- <ExpandSnippetIcon />
- </button>
- </td>
- </tr>
- )}
- </tbody>
- </table>
+ <div>
+ {snippet[0].line > 1 && (
+ <div className="expand-block expand-block-above">
+ <button
+ aria-label={translate('source_viewer.expand_above')}
+ onClick={this.expandBlock('up')}
+ type="button">
+ <ExpandSnippetIcon />
+ </button>
+ </div>
+ )}
+ <table
+ className={classNames('source-table', {
+ 'expand-up': snippet[0].line > 1,
+ 'expand-down': !lastLine || snippet[snippet.length - 1].line < lastLine
+ })}>
+ <tbody>
+ {snippet.map((line, index) =>
+ this.renderLine({
+ displayDuplications,
+ index,
+ issuesForLine: issuesByLine[line.line] || [],
+ issueLocations: locationsByLine[line.line] || [],
+ line,
+ snippet,
+ symbols: symbols[line.line],
+ verticalBuffer: index === snippet.length - 1 ? verticalBuffer : 0
+ })
+ )}
+ </tbody>
+ </table>
+ {(!lastLine || snippet[snippet.length - 1].line < lastLine) && (
+ <div className="expand-block expand-block-below">
+ <button
+ aria-label={translate('source_viewer.expand_below')}
+ onClick={this.expandBlock('down')}
+ type="button">
+ <ExpandSnippetIcon />
+ </button>
+ </div>
+ )}
+ </div>
</div>
);
}
diff --git a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/ComponentSourceSnippetViewer-test.tsx b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/ComponentSourceSnippetViewer-test.tsx
index 2bfa852f381..0b78f105f23 100644
--- a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/ComponentSourceSnippetViewer-test.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/ComponentSourceSnippetViewer-test.tsx
@@ -18,7 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import { shallow } from 'enzyme';
+import { shallow, mount, ReactWrapper } from 'enzyme';
import { times } from 'lodash';
import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
import ComponentSourceSnippetViewer from '../ComponentSourceSnippetViewer';
@@ -70,7 +70,7 @@ it('should expand block', async () => {
expect(getSources).toHaveBeenCalledWith({ from: 19, key: 'a', to: 31 });
expect(wrapper.state('snippets')).toHaveLength(2);
- expect(wrapper.state('snippets')[0]).toHaveLength(15);
+ expect(wrapper.state('snippets')[0]).toEqual({ index: 0, start: 22, end: 36 });
expect(Object.keys(wrapper.state('additionalLines'))).toHaveLength(10);
});
@@ -99,7 +99,7 @@ it('should expand full component', async () => {
expect(getSources).toHaveBeenCalledWith({ key: 'a' });
expect(wrapper.state('snippets')).toHaveLength(1);
- expect(wrapper.state('snippets')[0]).toHaveLength(14);
+ expect(wrapper.state('snippets')[0]).toEqual({ index: -1, start: 0, end: 13 });
});
it('should get the right branch when expanding', async () => {
@@ -190,6 +190,107 @@ it('should correctly handle lines actions', () => {
);
});
+describe('getNodes', () => {
+ const snippetGroup: T.SnippetGroup = {
+ component: mockSourceViewerFile(),
+ locations: [],
+ sources: []
+ };
+ const wrapper = mount<ComponentSourceSnippetViewer>(
+ <ComponentSourceSnippetViewer
+ branchLike={mockMainBranch()}
+ duplications={undefined}
+ duplicationsByLine={undefined}
+ highlightedLocationMessage={{ index: 0, text: '' }}
+ issue={mockIssue()}
+ issuesByLine={{}}
+ last={false}
+ linePopup={undefined}
+ loadDuplications={jest.fn()}
+ locations={[]}
+ onIssueChange={jest.fn()}
+ onIssuePopupToggle={jest.fn()}
+ onLinePopupToggle={jest.fn()}
+ onLocationSelect={jest.fn()}
+ renderDuplicationPopup={jest.fn()}
+ scroll={jest.fn()}
+ snippetGroup={snippetGroup}
+ />
+ );
+
+ it('should return undefined if any node is missing', async () => {
+ await waitAndUpdate(wrapper);
+ const rootNode = wrapper.instance().rootNodeRef;
+ mockDom(rootNode.current!);
+ expect(wrapper.instance().getNodes(0)).toBeUndefined();
+ expect(wrapper.instance().getNodes(1)).toBeUndefined();
+ expect(wrapper.instance().getNodes(2)).toBeUndefined();
+ });
+
+ it('should return elements if dom is correct', async () => {
+ await waitAndUpdate(wrapper);
+ const rootNode = wrapper.instance().rootNodeRef;
+ mockDom(rootNode.current!);
+ expect(wrapper.instance().getNodes(3)).not.toBeUndefined();
+ });
+});
+
+describe('getHeight', () => {
+ jest.useFakeTimers();
+
+ const snippetGroup: T.SnippetGroup = {
+ component: mockSourceViewerFile(),
+ locations: [],
+ sources: []
+ };
+ const wrapper = mount<ComponentSourceSnippetViewer>(
+ <ComponentSourceSnippetViewer
+ branchLike={mockMainBranch()}
+ duplications={undefined}
+ duplicationsByLine={undefined}
+ highlightedLocationMessage={{ index: 0, text: '' }}
+ issue={mockIssue()}
+ issuesByLine={{}}
+ last={false}
+ linePopup={undefined}
+ loadDuplications={jest.fn()}
+ locations={[]}
+ onIssueChange={jest.fn()}
+ onIssuePopupToggle={jest.fn()}
+ onLinePopupToggle={jest.fn()}
+ onLocationSelect={jest.fn()}
+ renderDuplicationPopup={jest.fn()}
+ scroll={jest.fn()}
+ snippetGroup={snippetGroup}
+ />
+ );
+
+ it('should set maxHeight to current height', async () => {
+ await waitAndUpdate(wrapper);
+
+ const nodes = mockDomForSizes(wrapper, { wrapperHeight: 42, tableHeight: 68 });
+ wrapper.instance().setMaxHeight(0);
+
+ expect(nodes.wrapper.getAttribute('style')).toBe('max-height: 88px;');
+ expect(nodes.table.getAttribute('style')).toBeNull();
+ });
+
+ it('should set margin and then maxHeight for a nice upwards animation', async () => {
+ await waitAndUpdate(wrapper);
+
+ const nodes = mockDomForSizes(wrapper, { wrapperHeight: 42, tableHeight: 68 });
+ wrapper.instance().setMaxHeight(0, undefined, true);
+
+ expect(nodes.wrapper.getAttribute('style')).toBeNull();
+ expect(nodes.table.getAttribute('style')).toBe('transition: none; margin-top: -26px;');
+
+ jest.runAllTimers();
+
+ expect(nodes.wrapper.getAttribute('style')).toBe('max-height: 88px;');
+ expect(nodes.table.getAttribute('style')).toBe('margin-top: 0px;');
+ });
+});
+
function shallowRender(props: Partial<ComponentSourceSnippetViewer['props']> = {}) {
const snippetGroup: T.SnippetGroup = {
component: mockSourceViewerFile(),
@@ -219,3 +320,47 @@ function shallowRender(props: Partial<ComponentSourceSnippetViewer['props']> = {
/>
);
}
+
+function mockDom(refNode: HTMLDivElement) {
+ refNode.querySelector = jest.fn(query => {
+ const index = query.split('-').pop();
+
+ switch (index) {
+ case '0':
+ return null;
+ case '1':
+ return mount(<div />).getDOMNode();
+ case '2':
+ return mount(
+ <div>
+ <div className="snippet" />
+ </div>
+ ).getDOMNode();
+ case '3':
+ return mount(
+ <div>
+ <div className="snippet">
+ <div />
+ </div>
+ </div>
+ ).getDOMNode();
+ default:
+ return null;
+ }
+ });
+}
+
+function mockDomForSizes(
+ componentWrapper: ReactWrapper<{}, {}, ComponentSourceSnippetViewer>,
+ { wrapperHeight = 0, tableHeight = 0 }
+) {
+ const wrapper = mount(<div className="snippet" />).getDOMNode();
+ wrapper.getBoundingClientRect = jest.fn().mockReturnValue({ height: wrapperHeight });
+ const table = mount(<div />).getDOMNode();
+ table.getBoundingClientRect = jest.fn().mockReturnValue({ height: tableHeight });
+ componentWrapper.instance().getNodes = jest.fn().mockReturnValue({
+ wrapper,
+ table
+ });
+ return { wrapper, table };
+}
diff --git a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/__snapshots__/SnippetViewer-test.tsx.snap b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/__snapshots__/SnippetViewer-test.tsx.snap
index e2081bb97cb..1dccbb712e6 100644
--- a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/__snapshots__/SnippetViewer-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/__snapshots__/SnippetViewer-test.tsx.snap
@@ -4,212 +4,206 @@ exports[`should render correctly 1`] = `
<div
className="source-viewer-code snippet"
>
- <table
- className="source-table"
- >
- <tbody>
- <tr
- className="expand-block expand-block-above"
+ <div>
+ <div
+ className="expand-block expand-block-above"
+ >
+ <button
+ aria-label="source_viewer.expand_above"
+ onClick={[Function]}
+ type="button"
>
- <td
- colSpan={5}
- >
- <button
- aria-label="source_viewer.expand_above"
- onClick={[Function]}
- type="button"
- >
- <ExpandSnippetIcon />
- </button>
- </td>
- </tr>
- <Line
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "isMain": true,
- "name": "master",
- }
- }
- displayAllIssues={false}
- displayCoverage={true}
- displayDuplications={false}
- displayIssues={true}
- displayLocationMarkers={true}
- duplications={Array []}
- duplicationsCount={0}
- highlighted={false}
- issueLocations={Array []}
- issues={Array []}
- key="5"
- last={false}
- line={
- Object {
- "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
- "coverageStatus": "covered",
- "coveredConditions": 2,
- "duplicated": false,
- "isNew": true,
- "line": 5,
- "scmAuthor": "simon.brandhof@sonarsource.com",
- "scmDate": "2018-12-11T10:48:39+0100",
- "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
- }
- }
- loadDuplications={[MockFunction]}
- onIssueChange={[MockFunction]}
- onIssuePopupToggle={[MockFunction]}
- onIssueSelect={[Function]}
- onIssueUnselect={[Function]}
- onIssuesClose={[MockFunction]}
- onIssuesOpen={[MockFunction]}
- onLinePopupToggle={[MockFunction]}
- onLocationSelect={[MockFunction]}
- onSymbolClick={[MockFunction]}
- renderDuplicationPopup={[MockFunction]}
- scroll={[Function]}
- secondaryIssueLocations={Array []}
- verticalBuffer={0}
- />
- <Line
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "isMain": true,
- "name": "master",
- }
- }
- displayAllIssues={false}
- displayCoverage={true}
- displayDuplications={false}
- displayIssues={true}
- displayLocationMarkers={true}
- duplications={Array []}
- duplicationsCount={0}
- highlighted={false}
- issueLocations={Array []}
- issues={Array []}
- key="6"
- last={false}
- line={
- Object {
- "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
- "coverageStatus": "covered",
- "coveredConditions": 2,
- "duplicated": false,
- "isNew": true,
- "line": 6,
- "scmAuthor": "simon.brandhof@sonarsource.com",
- "scmDate": "2018-12-11T10:48:39+0100",
- "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
- }
- }
- loadDuplications={[MockFunction]}
- onIssueChange={[MockFunction]}
- onIssuePopupToggle={[MockFunction]}
- onIssueSelect={[Function]}
- onIssueUnselect={[Function]}
- onIssuesClose={[MockFunction]}
- onIssuesOpen={[MockFunction]}
- onLinePopupToggle={[MockFunction]}
- onLocationSelect={[MockFunction]}
- onSymbolClick={[MockFunction]}
- previousLine={
- Object {
- "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
- "coverageStatus": "covered",
- "coveredConditions": 2,
- "duplicated": false,
- "isNew": true,
- "line": 5,
- "scmAuthor": "simon.brandhof@sonarsource.com",
- "scmDate": "2018-12-11T10:48:39+0100",
- "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
- }
- }
- renderDuplicationPopup={[MockFunction]}
- scroll={[Function]}
- secondaryIssueLocations={Array []}
- verticalBuffer={0}
- />
- <Line
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "isMain": true,
- "name": "master",
- }
- }
- displayAllIssues={false}
- displayCoverage={true}
- displayDuplications={false}
- displayIssues={true}
- displayLocationMarkers={true}
- duplications={Array []}
- duplicationsCount={0}
- highlighted={false}
- issueLocations={Array []}
- issues={Array []}
- key="7"
- last={false}
- line={
- Object {
- "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
- "coverageStatus": "covered",
- "coveredConditions": 2,
- "duplicated": false,
- "isNew": true,
- "line": 7,
- "scmAuthor": "simon.brandhof@sonarsource.com",
- "scmDate": "2018-12-11T10:48:39+0100",
- "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
- }
- }
- loadDuplications={[MockFunction]}
- onIssueChange={[MockFunction]}
- onIssuePopupToggle={[MockFunction]}
- onIssueSelect={[Function]}
- onIssueUnselect={[Function]}
- onIssuesClose={[MockFunction]}
- onIssuesOpen={[MockFunction]}
- onLinePopupToggle={[MockFunction]}
- onLocationSelect={[MockFunction]}
- onSymbolClick={[MockFunction]}
- previousLine={
- Object {
- "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
- "coverageStatus": "covered",
- "coveredConditions": 2,
- "duplicated": false,
- "isNew": true,
- "line": 6,
- "scmAuthor": "simon.brandhof@sonarsource.com",
- "scmDate": "2018-12-11T10:48:39+0100",
- "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
- }
- }
- renderDuplicationPopup={[MockFunction]}
- scroll={[Function]}
- secondaryIssueLocations={Array []}
- verticalBuffer={0}
- />
- <tr
- className="expand-block expand-block-below"
+ <ExpandSnippetIcon />
+ </button>
+ </div>
+ <table
+ className="source-table expand-up expand-down"
+ >
+ <tbody>
+ <Line
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ displayAllIssues={false}
+ displayCoverage={true}
+ displayDuplications={false}
+ displayIssues={true}
+ displayLocationMarkers={true}
+ duplications={Array []}
+ duplicationsCount={0}
+ highlighted={false}
+ issueLocations={Array []}
+ issues={Array []}
+ key="5"
+ last={false}
+ line={
+ Object {
+ "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
+ "coverageStatus": "covered",
+ "coveredConditions": 2,
+ "duplicated": false,
+ "isNew": true,
+ "line": 5,
+ "scmAuthor": "simon.brandhof@sonarsource.com",
+ "scmDate": "2018-12-11T10:48:39+0100",
+ "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
+ }
+ }
+ loadDuplications={[MockFunction]}
+ onIssueChange={[MockFunction]}
+ onIssuePopupToggle={[MockFunction]}
+ onIssueSelect={[Function]}
+ onIssueUnselect={[Function]}
+ onIssuesClose={[MockFunction]}
+ onIssuesOpen={[MockFunction]}
+ onLinePopupToggle={[MockFunction]}
+ onLocationSelect={[MockFunction]}
+ onSymbolClick={[MockFunction]}
+ renderDuplicationPopup={[MockFunction]}
+ scroll={[Function]}
+ secondaryIssueLocations={Array []}
+ verticalBuffer={0}
+ />
+ <Line
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ displayAllIssues={false}
+ displayCoverage={true}
+ displayDuplications={false}
+ displayIssues={true}
+ displayLocationMarkers={true}
+ duplications={Array []}
+ duplicationsCount={0}
+ highlighted={false}
+ issueLocations={Array []}
+ issues={Array []}
+ key="6"
+ last={false}
+ line={
+ Object {
+ "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
+ "coverageStatus": "covered",
+ "coveredConditions": 2,
+ "duplicated": false,
+ "isNew": true,
+ "line": 6,
+ "scmAuthor": "simon.brandhof@sonarsource.com",
+ "scmDate": "2018-12-11T10:48:39+0100",
+ "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
+ }
+ }
+ loadDuplications={[MockFunction]}
+ onIssueChange={[MockFunction]}
+ onIssuePopupToggle={[MockFunction]}
+ onIssueSelect={[Function]}
+ onIssueUnselect={[Function]}
+ onIssuesClose={[MockFunction]}
+ onIssuesOpen={[MockFunction]}
+ onLinePopupToggle={[MockFunction]}
+ onLocationSelect={[MockFunction]}
+ onSymbolClick={[MockFunction]}
+ previousLine={
+ Object {
+ "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
+ "coverageStatus": "covered",
+ "coveredConditions": 2,
+ "duplicated": false,
+ "isNew": true,
+ "line": 5,
+ "scmAuthor": "simon.brandhof@sonarsource.com",
+ "scmDate": "2018-12-11T10:48:39+0100",
+ "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
+ }
+ }
+ renderDuplicationPopup={[MockFunction]}
+ scroll={[Function]}
+ secondaryIssueLocations={Array []}
+ verticalBuffer={0}
+ />
+ <Line
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ displayAllIssues={false}
+ displayCoverage={true}
+ displayDuplications={false}
+ displayIssues={true}
+ displayLocationMarkers={true}
+ duplications={Array []}
+ duplicationsCount={0}
+ highlighted={false}
+ issueLocations={Array []}
+ issues={Array []}
+ key="7"
+ last={false}
+ line={
+ Object {
+ "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
+ "coverageStatus": "covered",
+ "coveredConditions": 2,
+ "duplicated": false,
+ "isNew": true,
+ "line": 7,
+ "scmAuthor": "simon.brandhof@sonarsource.com",
+ "scmDate": "2018-12-11T10:48:39+0100",
+ "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
+ }
+ }
+ loadDuplications={[MockFunction]}
+ onIssueChange={[MockFunction]}
+ onIssuePopupToggle={[MockFunction]}
+ onIssueSelect={[Function]}
+ onIssueUnselect={[Function]}
+ onIssuesClose={[MockFunction]}
+ onIssuesOpen={[MockFunction]}
+ onLinePopupToggle={[MockFunction]}
+ onLocationSelect={[MockFunction]}
+ onSymbolClick={[MockFunction]}
+ previousLine={
+ Object {
+ "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
+ "coverageStatus": "covered",
+ "coveredConditions": 2,
+ "duplicated": false,
+ "isNew": true,
+ "line": 6,
+ "scmAuthor": "simon.brandhof@sonarsource.com",
+ "scmDate": "2018-12-11T10:48:39+0100",
+ "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
+ }
+ }
+ renderDuplicationPopup={[MockFunction]}
+ scroll={[Function]}
+ secondaryIssueLocations={Array []}
+ verticalBuffer={0}
+ />
+ </tbody>
+ </table>
+ <div
+ className="expand-block expand-block-below"
+ >
+ <button
+ aria-label="source_viewer.expand_below"
+ onClick={[Function]}
+ type="button"
>
- <td
- colSpan={5}
- >
- <button
- aria-label="source_viewer.expand_below"
- onClick={[Function]}
- type="button"
- >
- <ExpandSnippetIcon />
- </button>
- </td>
- </tr>
- </tbody>
- </table>
+ <ExpandSnippetIcon />
+ </button>
+ </div>
+ </div>
</div>
`;
@@ -217,273 +211,267 @@ exports[`should render correctly when at the bottom of the file 1`] = `
<div
className="source-viewer-code snippet"
>
- <table
- className="source-table"
- >
- <tbody>
- <tr
- className="expand-block expand-block-above"
+ <div>
+ <div
+ className="expand-block expand-block-above"
+ >
+ <button
+ aria-label="source_viewer.expand_above"
+ onClick={[Function]}
+ type="button"
>
- <td
- colSpan={5}
- >
- <button
- aria-label="source_viewer.expand_above"
- onClick={[Function]}
- type="button"
- >
- <ExpandSnippetIcon />
- </button>
- </td>
- </tr>
- <Line
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "isMain": true,
- "name": "master",
- }
- }
- displayAllIssues={false}
- displayCoverage={true}
- displayDuplications={false}
- displayIssues={true}
- displayLocationMarkers={true}
- duplications={Array []}
- duplicationsCount={0}
- highlighted={false}
- issueLocations={Array []}
- issues={Array []}
- key="10"
- last={false}
- line={
- Object {
- "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
- "coverageStatus": "covered",
- "coveredConditions": 2,
- "duplicated": false,
- "isNew": true,
- "line": 10,
- "scmAuthor": "simon.brandhof@sonarsource.com",
- "scmDate": "2018-12-11T10:48:39+0100",
- "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
- }
- }
- loadDuplications={[MockFunction]}
- onIssueChange={[MockFunction]}
- onIssuePopupToggle={[MockFunction]}
- onIssueSelect={[Function]}
- onIssueUnselect={[Function]}
- onIssuesClose={[MockFunction]}
- onIssuesOpen={[MockFunction]}
- onLinePopupToggle={[MockFunction]}
- onLocationSelect={[MockFunction]}
- onSymbolClick={[MockFunction]}
- renderDuplicationPopup={[MockFunction]}
- scroll={[Function]}
- secondaryIssueLocations={Array []}
- verticalBuffer={0}
- />
- <Line
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "isMain": true,
- "name": "master",
- }
- }
- displayAllIssues={false}
- displayCoverage={true}
- displayDuplications={false}
- displayIssues={true}
- displayLocationMarkers={true}
- duplications={Array []}
- duplicationsCount={0}
- highlighted={false}
- issueLocations={Array []}
- issues={Array []}
- key="11"
- last={false}
- line={
- Object {
- "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
- "coverageStatus": "covered",
- "coveredConditions": 2,
- "duplicated": false,
- "isNew": true,
- "line": 11,
- "scmAuthor": "simon.brandhof@sonarsource.com",
- "scmDate": "2018-12-11T10:48:39+0100",
- "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
- }
- }
- loadDuplications={[MockFunction]}
- onIssueChange={[MockFunction]}
- onIssuePopupToggle={[MockFunction]}
- onIssueSelect={[Function]}
- onIssueUnselect={[Function]}
- onIssuesClose={[MockFunction]}
- onIssuesOpen={[MockFunction]}
- onLinePopupToggle={[MockFunction]}
- onLocationSelect={[MockFunction]}
- onSymbolClick={[MockFunction]}
- previousLine={
- Object {
- "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
- "coverageStatus": "covered",
- "coveredConditions": 2,
- "duplicated": false,
- "isNew": true,
- "line": 10,
- "scmAuthor": "simon.brandhof@sonarsource.com",
- "scmDate": "2018-12-11T10:48:39+0100",
- "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
- }
- }
- renderDuplicationPopup={[MockFunction]}
- scroll={[Function]}
- secondaryIssueLocations={Array []}
- verticalBuffer={0}
- />
- <Line
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "isMain": true,
- "name": "master",
- }
- }
- displayAllIssues={false}
- displayCoverage={true}
- displayDuplications={false}
- displayIssues={true}
- displayLocationMarkers={true}
- duplications={Array []}
- duplicationsCount={0}
- highlighted={false}
- issueLocations={Array []}
- issues={Array []}
- key="12"
- last={false}
- line={
- Object {
- "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
- "coverageStatus": "covered",
- "coveredConditions": 2,
- "duplicated": false,
- "isNew": true,
- "line": 12,
- "scmAuthor": "simon.brandhof@sonarsource.com",
- "scmDate": "2018-12-11T10:48:39+0100",
- "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
- }
- }
- loadDuplications={[MockFunction]}
- onIssueChange={[MockFunction]}
- onIssuePopupToggle={[MockFunction]}
- onIssueSelect={[Function]}
- onIssueUnselect={[Function]}
- onIssuesClose={[MockFunction]}
- onIssuesOpen={[MockFunction]}
- onLinePopupToggle={[MockFunction]}
- onLocationSelect={[MockFunction]}
- onSymbolClick={[MockFunction]}
- previousLine={
- Object {
- "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
- "coverageStatus": "covered",
- "coveredConditions": 2,
- "duplicated": false,
- "isNew": true,
- "line": 11,
- "scmAuthor": "simon.brandhof@sonarsource.com",
- "scmDate": "2018-12-11T10:48:39+0100",
- "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
- }
- }
- renderDuplicationPopup={[MockFunction]}
- scroll={[Function]}
- secondaryIssueLocations={Array []}
- verticalBuffer={0}
- />
- <Line
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "isMain": true,
- "name": "master",
- }
- }
- displayAllIssues={false}
- displayCoverage={true}
- displayDuplications={false}
- displayIssues={true}
- displayLocationMarkers={true}
- duplications={Array []}
- duplicationsCount={0}
- highlighted={false}
- issueLocations={Array []}
- issues={Array []}
- key="13"
- last={false}
- line={
- Object {
- "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
- "coverageStatus": "covered",
- "coveredConditions": 2,
- "duplicated": false,
- "isNew": true,
- "line": 13,
- "scmAuthor": "simon.brandhof@sonarsource.com",
- "scmDate": "2018-12-11T10:48:39+0100",
- "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
- }
- }
- loadDuplications={[MockFunction]}
- onIssueChange={[MockFunction]}
- onIssuePopupToggle={[MockFunction]}
- onIssueSelect={[Function]}
- onIssueUnselect={[Function]}
- onIssuesClose={[MockFunction]}
- onIssuesOpen={[MockFunction]}
- onLinePopupToggle={[MockFunction]}
- onLocationSelect={[MockFunction]}
- onSymbolClick={[MockFunction]}
- previousLine={
- Object {
- "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
- "coverageStatus": "covered",
- "coveredConditions": 2,
- "duplicated": false,
- "isNew": true,
- "line": 12,
- "scmAuthor": "simon.brandhof@sonarsource.com",
- "scmDate": "2018-12-11T10:48:39+0100",
- "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
- }
- }
- renderDuplicationPopup={[MockFunction]}
- scroll={[Function]}
- secondaryIssueLocations={Array []}
- verticalBuffer={0}
- />
- <tr
- className="expand-block expand-block-below"
+ <ExpandSnippetIcon />
+ </button>
+ </div>
+ <table
+ className="source-table expand-up expand-down"
+ >
+ <tbody>
+ <Line
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ displayAllIssues={false}
+ displayCoverage={true}
+ displayDuplications={false}
+ displayIssues={true}
+ displayLocationMarkers={true}
+ duplications={Array []}
+ duplicationsCount={0}
+ highlighted={false}
+ issueLocations={Array []}
+ issues={Array []}
+ key="10"
+ last={false}
+ line={
+ Object {
+ "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
+ "coverageStatus": "covered",
+ "coveredConditions": 2,
+ "duplicated": false,
+ "isNew": true,
+ "line": 10,
+ "scmAuthor": "simon.brandhof@sonarsource.com",
+ "scmDate": "2018-12-11T10:48:39+0100",
+ "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
+ }
+ }
+ loadDuplications={[MockFunction]}
+ onIssueChange={[MockFunction]}
+ onIssuePopupToggle={[MockFunction]}
+ onIssueSelect={[Function]}
+ onIssueUnselect={[Function]}
+ onIssuesClose={[MockFunction]}
+ onIssuesOpen={[MockFunction]}
+ onLinePopupToggle={[MockFunction]}
+ onLocationSelect={[MockFunction]}
+ onSymbolClick={[MockFunction]}
+ renderDuplicationPopup={[MockFunction]}
+ scroll={[Function]}
+ secondaryIssueLocations={Array []}
+ verticalBuffer={0}
+ />
+ <Line
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ displayAllIssues={false}
+ displayCoverage={true}
+ displayDuplications={false}
+ displayIssues={true}
+ displayLocationMarkers={true}
+ duplications={Array []}
+ duplicationsCount={0}
+ highlighted={false}
+ issueLocations={Array []}
+ issues={Array []}
+ key="11"
+ last={false}
+ line={
+ Object {
+ "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
+ "coverageStatus": "covered",
+ "coveredConditions": 2,
+ "duplicated": false,
+ "isNew": true,
+ "line": 11,
+ "scmAuthor": "simon.brandhof@sonarsource.com",
+ "scmDate": "2018-12-11T10:48:39+0100",
+ "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
+ }
+ }
+ loadDuplications={[MockFunction]}
+ onIssueChange={[MockFunction]}
+ onIssuePopupToggle={[MockFunction]}
+ onIssueSelect={[Function]}
+ onIssueUnselect={[Function]}
+ onIssuesClose={[MockFunction]}
+ onIssuesOpen={[MockFunction]}
+ onLinePopupToggle={[MockFunction]}
+ onLocationSelect={[MockFunction]}
+ onSymbolClick={[MockFunction]}
+ previousLine={
+ Object {
+ "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
+ "coverageStatus": "covered",
+ "coveredConditions": 2,
+ "duplicated": false,
+ "isNew": true,
+ "line": 10,
+ "scmAuthor": "simon.brandhof@sonarsource.com",
+ "scmDate": "2018-12-11T10:48:39+0100",
+ "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
+ }
+ }
+ renderDuplicationPopup={[MockFunction]}
+ scroll={[Function]}
+ secondaryIssueLocations={Array []}
+ verticalBuffer={0}
+ />
+ <Line
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ displayAllIssues={false}
+ displayCoverage={true}
+ displayDuplications={false}
+ displayIssues={true}
+ displayLocationMarkers={true}
+ duplications={Array []}
+ duplicationsCount={0}
+ highlighted={false}
+ issueLocations={Array []}
+ issues={Array []}
+ key="12"
+ last={false}
+ line={
+ Object {
+ "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
+ "coverageStatus": "covered",
+ "coveredConditions": 2,
+ "duplicated": false,
+ "isNew": true,
+ "line": 12,
+ "scmAuthor": "simon.brandhof@sonarsource.com",
+ "scmDate": "2018-12-11T10:48:39+0100",
+ "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
+ }
+ }
+ loadDuplications={[MockFunction]}
+ onIssueChange={[MockFunction]}
+ onIssuePopupToggle={[MockFunction]}
+ onIssueSelect={[Function]}
+ onIssueUnselect={[Function]}
+ onIssuesClose={[MockFunction]}
+ onIssuesOpen={[MockFunction]}
+ onLinePopupToggle={[MockFunction]}
+ onLocationSelect={[MockFunction]}
+ onSymbolClick={[MockFunction]}
+ previousLine={
+ Object {
+ "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
+ "coverageStatus": "covered",
+ "coveredConditions": 2,
+ "duplicated": false,
+ "isNew": true,
+ "line": 11,
+ "scmAuthor": "simon.brandhof@sonarsource.com",
+ "scmDate": "2018-12-11T10:48:39+0100",
+ "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
+ }
+ }
+ renderDuplicationPopup={[MockFunction]}
+ scroll={[Function]}
+ secondaryIssueLocations={Array []}
+ verticalBuffer={0}
+ />
+ <Line
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ displayAllIssues={false}
+ displayCoverage={true}
+ displayDuplications={false}
+ displayIssues={true}
+ displayLocationMarkers={true}
+ duplications={Array []}
+ duplicationsCount={0}
+ highlighted={false}
+ issueLocations={Array []}
+ issues={Array []}
+ key="13"
+ last={false}
+ line={
+ Object {
+ "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
+ "coverageStatus": "covered",
+ "coveredConditions": 2,
+ "duplicated": false,
+ "isNew": true,
+ "line": 13,
+ "scmAuthor": "simon.brandhof@sonarsource.com",
+ "scmDate": "2018-12-11T10:48:39+0100",
+ "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
+ }
+ }
+ loadDuplications={[MockFunction]}
+ onIssueChange={[MockFunction]}
+ onIssuePopupToggle={[MockFunction]}
+ onIssueSelect={[Function]}
+ onIssueUnselect={[Function]}
+ onIssuesClose={[MockFunction]}
+ onIssuesOpen={[MockFunction]}
+ onLinePopupToggle={[MockFunction]}
+ onLocationSelect={[MockFunction]}
+ onSymbolClick={[MockFunction]}
+ previousLine={
+ Object {
+ "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
+ "coverageStatus": "covered",
+ "coveredConditions": 2,
+ "duplicated": false,
+ "isNew": true,
+ "line": 12,
+ "scmAuthor": "simon.brandhof@sonarsource.com",
+ "scmDate": "2018-12-11T10:48:39+0100",
+ "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
+ }
+ }
+ renderDuplicationPopup={[MockFunction]}
+ scroll={[Function]}
+ secondaryIssueLocations={Array []}
+ verticalBuffer={0}
+ />
+ </tbody>
+ </table>
+ <div
+ className="expand-block expand-block-below"
+ >
+ <button
+ aria-label="source_viewer.expand_below"
+ onClick={[Function]}
+ type="button"
>
- <td
- colSpan={5}
- >
- <button
- aria-label="source_viewer.expand_below"
- onClick={[Function]}
- type="button"
- >
- <ExpandSnippetIcon />
- </button>
- </td>
- </tr>
- </tbody>
- </table>
+ <ExpandSnippetIcon />
+ </button>
+ </div>
+ </div>
</div>
`;
@@ -491,440 +479,438 @@ exports[`should render correctly when at the top of the file 1`] = `
<div
className="source-viewer-code snippet"
>
- <table
- className="source-table"
- >
- <tbody>
- <Line
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "isMain": true,
- "name": "master",
- }
- }
- displayAllIssues={false}
- displayCoverage={true}
- displayDuplications={false}
- displayIssues={true}
- displayLocationMarkers={true}
- duplications={Array []}
- duplicationsCount={0}
- highlighted={false}
- issueLocations={Array []}
- issues={Array []}
- key="1"
- last={false}
- line={
- Object {
- "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
- "coverageStatus": "covered",
- "coveredConditions": 2,
- "duplicated": false,
- "isNew": true,
- "line": 1,
- "scmAuthor": "simon.brandhof@sonarsource.com",
- "scmDate": "2018-12-11T10:48:39+0100",
- "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
- }
- }
- loadDuplications={[MockFunction]}
- onIssueChange={[MockFunction]}
- onIssuePopupToggle={[MockFunction]}
- onIssueSelect={[Function]}
- onIssueUnselect={[Function]}
- onIssuesClose={[MockFunction]}
- onIssuesOpen={[MockFunction]}
- onLinePopupToggle={[MockFunction]}
- onLocationSelect={[MockFunction]}
- onSymbolClick={[MockFunction]}
- renderDuplicationPopup={[MockFunction]}
- scroll={[Function]}
- secondaryIssueLocations={Array []}
- verticalBuffer={0}
- />
- <Line
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "isMain": true,
- "name": "master",
- }
- }
- displayAllIssues={false}
- displayCoverage={true}
- displayDuplications={false}
- displayIssues={true}
- displayLocationMarkers={true}
- duplications={Array []}
- duplicationsCount={0}
- highlighted={false}
- issueLocations={Array []}
- issues={Array []}
- key="2"
- last={false}
- line={
- Object {
- "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
- "coverageStatus": "covered",
- "coveredConditions": 2,
- "duplicated": false,
- "isNew": true,
- "line": 2,
- "scmAuthor": "simon.brandhof@sonarsource.com",
- "scmDate": "2018-12-11T10:48:39+0100",
- "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
- }
- }
- loadDuplications={[MockFunction]}
- onIssueChange={[MockFunction]}
- onIssuePopupToggle={[MockFunction]}
- onIssueSelect={[Function]}
- onIssueUnselect={[Function]}
- onIssuesClose={[MockFunction]}
- onIssuesOpen={[MockFunction]}
- onLinePopupToggle={[MockFunction]}
- onLocationSelect={[MockFunction]}
- onSymbolClick={[MockFunction]}
- previousLine={
- Object {
- "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
- "coverageStatus": "covered",
- "coveredConditions": 2,
- "duplicated": false,
- "isNew": true,
- "line": 1,
- "scmAuthor": "simon.brandhof@sonarsource.com",
- "scmDate": "2018-12-11T10:48:39+0100",
- "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
- }
- }
- renderDuplicationPopup={[MockFunction]}
- scroll={[Function]}
- secondaryIssueLocations={Array []}
- verticalBuffer={0}
- />
- <Line
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "isMain": true,
- "name": "master",
- }
- }
- displayAllIssues={false}
- displayCoverage={true}
- displayDuplications={false}
- displayIssues={true}
- displayLocationMarkers={true}
- duplications={Array []}
- duplicationsCount={0}
- highlighted={false}
- issueLocations={Array []}
- issues={Array []}
- key="3"
- last={false}
- line={
- Object {
- "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
- "coverageStatus": "covered",
- "coveredConditions": 2,
- "duplicated": false,
- "isNew": true,
- "line": 3,
- "scmAuthor": "simon.brandhof@sonarsource.com",
- "scmDate": "2018-12-11T10:48:39+0100",
- "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
- }
- }
- loadDuplications={[MockFunction]}
- onIssueChange={[MockFunction]}
- onIssuePopupToggle={[MockFunction]}
- onIssueSelect={[Function]}
- onIssueUnselect={[Function]}
- onIssuesClose={[MockFunction]}
- onIssuesOpen={[MockFunction]}
- onLinePopupToggle={[MockFunction]}
- onLocationSelect={[MockFunction]}
- onSymbolClick={[MockFunction]}
- previousLine={
- Object {
- "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
- "coverageStatus": "covered",
- "coveredConditions": 2,
- "duplicated": false,
- "isNew": true,
- "line": 2,
- "scmAuthor": "simon.brandhof@sonarsource.com",
- "scmDate": "2018-12-11T10:48:39+0100",
- "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
- }
- }
- renderDuplicationPopup={[MockFunction]}
- scroll={[Function]}
- secondaryIssueLocations={Array []}
- verticalBuffer={0}
- />
- <Line
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "isMain": true,
- "name": "master",
- }
- }
- displayAllIssues={false}
- displayCoverage={true}
- displayDuplications={false}
- displayIssues={true}
- displayLocationMarkers={true}
- duplications={Array []}
- duplicationsCount={0}
- highlighted={false}
- issueLocations={Array []}
- issues={Array []}
- key="4"
- last={false}
- line={
- Object {
- "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
- "coverageStatus": "covered",
- "coveredConditions": 2,
- "duplicated": false,
- "isNew": true,
- "line": 4,
- "scmAuthor": "simon.brandhof@sonarsource.com",
- "scmDate": "2018-12-11T10:48:39+0100",
- "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
- }
- }
- loadDuplications={[MockFunction]}
- onIssueChange={[MockFunction]}
- onIssuePopupToggle={[MockFunction]}
- onIssueSelect={[Function]}
- onIssueUnselect={[Function]}
- onIssuesClose={[MockFunction]}
- onIssuesOpen={[MockFunction]}
- onLinePopupToggle={[MockFunction]}
- onLocationSelect={[MockFunction]}
- onSymbolClick={[MockFunction]}
- previousLine={
- Object {
- "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
- "coverageStatus": "covered",
- "coveredConditions": 2,
- "duplicated": false,
- "isNew": true,
- "line": 3,
- "scmAuthor": "simon.brandhof@sonarsource.com",
- "scmDate": "2018-12-11T10:48:39+0100",
- "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
- }
- }
- renderDuplicationPopup={[MockFunction]}
- scroll={[Function]}
- secondaryIssueLocations={Array []}
- verticalBuffer={0}
- />
- <Line
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "isMain": true,
- "name": "master",
- }
- }
- displayAllIssues={false}
- displayCoverage={true}
- displayDuplications={false}
- displayIssues={true}
- displayLocationMarkers={true}
- duplications={Array []}
- duplicationsCount={0}
- highlighted={false}
- issueLocations={Array []}
- issues={Array []}
- key="5"
- last={false}
- line={
- Object {
- "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
- "coverageStatus": "covered",
- "coveredConditions": 2,
- "duplicated": false,
- "isNew": true,
- "line": 5,
- "scmAuthor": "simon.brandhof@sonarsource.com",
- "scmDate": "2018-12-11T10:48:39+0100",
- "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
- }
- }
- loadDuplications={[MockFunction]}
- onIssueChange={[MockFunction]}
- onIssuePopupToggle={[MockFunction]}
- onIssueSelect={[Function]}
- onIssueUnselect={[Function]}
- onIssuesClose={[MockFunction]}
- onIssuesOpen={[MockFunction]}
- onLinePopupToggle={[MockFunction]}
- onLocationSelect={[MockFunction]}
- onSymbolClick={[MockFunction]}
- previousLine={
- Object {
- "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
- "coverageStatus": "covered",
- "coveredConditions": 2,
- "duplicated": false,
- "isNew": true,
- "line": 4,
- "scmAuthor": "simon.brandhof@sonarsource.com",
- "scmDate": "2018-12-11T10:48:39+0100",
- "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
- }
- }
- renderDuplicationPopup={[MockFunction]}
- scroll={[Function]}
- secondaryIssueLocations={Array []}
- verticalBuffer={0}
- />
- <Line
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "isMain": true,
- "name": "master",
- }
- }
- displayAllIssues={false}
- displayCoverage={true}
- displayDuplications={false}
- displayIssues={true}
- displayLocationMarkers={true}
- duplications={Array []}
- duplicationsCount={0}
- highlighted={false}
- issueLocations={Array []}
- issues={Array []}
- key="6"
- last={false}
- line={
- Object {
- "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
- "coverageStatus": "covered",
- "coveredConditions": 2,
- "duplicated": false,
- "isNew": true,
- "line": 6,
- "scmAuthor": "simon.brandhof@sonarsource.com",
- "scmDate": "2018-12-11T10:48:39+0100",
- "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
- }
- }
- loadDuplications={[MockFunction]}
- onIssueChange={[MockFunction]}
- onIssuePopupToggle={[MockFunction]}
- onIssueSelect={[Function]}
- onIssueUnselect={[Function]}
- onIssuesClose={[MockFunction]}
- onIssuesOpen={[MockFunction]}
- onLinePopupToggle={[MockFunction]}
- onLocationSelect={[MockFunction]}
- onSymbolClick={[MockFunction]}
- previousLine={
- Object {
- "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
- "coverageStatus": "covered",
- "coveredConditions": 2,
- "duplicated": false,
- "isNew": true,
- "line": 5,
- "scmAuthor": "simon.brandhof@sonarsource.com",
- "scmDate": "2018-12-11T10:48:39+0100",
- "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
- }
- }
- renderDuplicationPopup={[MockFunction]}
- scroll={[Function]}
- secondaryIssueLocations={Array []}
- verticalBuffer={0}
- />
- <Line
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "isMain": true,
- "name": "master",
- }
- }
- displayAllIssues={false}
- displayCoverage={true}
- displayDuplications={false}
- displayIssues={true}
- displayLocationMarkers={true}
- duplications={Array []}
- duplicationsCount={0}
- highlighted={false}
- issueLocations={Array []}
- issues={Array []}
- key="7"
- last={false}
- line={
- Object {
- "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
- "coverageStatus": "covered",
- "coveredConditions": 2,
- "duplicated": false,
- "isNew": true,
- "line": 7,
- "scmAuthor": "simon.brandhof@sonarsource.com",
- "scmDate": "2018-12-11T10:48:39+0100",
- "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
- }
- }
- loadDuplications={[MockFunction]}
- onIssueChange={[MockFunction]}
- onIssuePopupToggle={[MockFunction]}
- onIssueSelect={[Function]}
- onIssueUnselect={[Function]}
- onIssuesClose={[MockFunction]}
- onIssuesOpen={[MockFunction]}
- onLinePopupToggle={[MockFunction]}
- onLocationSelect={[MockFunction]}
- onSymbolClick={[MockFunction]}
- previousLine={
- Object {
- "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
- "coverageStatus": "covered",
- "coveredConditions": 2,
- "duplicated": false,
- "isNew": true,
- "line": 6,
- "scmAuthor": "simon.brandhof@sonarsource.com",
- "scmDate": "2018-12-11T10:48:39+0100",
- "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
- }
- }
- renderDuplicationPopup={[MockFunction]}
- scroll={[Function]}
- secondaryIssueLocations={Array []}
- verticalBuffer={0}
- />
- <tr
- className="expand-block expand-block-below"
+ <div>
+ <table
+ className="source-table expand-down"
+ >
+ <tbody>
+ <Line
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ displayAllIssues={false}
+ displayCoverage={true}
+ displayDuplications={false}
+ displayIssues={true}
+ displayLocationMarkers={true}
+ duplications={Array []}
+ duplicationsCount={0}
+ highlighted={false}
+ issueLocations={Array []}
+ issues={Array []}
+ key="1"
+ last={false}
+ line={
+ Object {
+ "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
+ "coverageStatus": "covered",
+ "coveredConditions": 2,
+ "duplicated": false,
+ "isNew": true,
+ "line": 1,
+ "scmAuthor": "simon.brandhof@sonarsource.com",
+ "scmDate": "2018-12-11T10:48:39+0100",
+ "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
+ }
+ }
+ loadDuplications={[MockFunction]}
+ onIssueChange={[MockFunction]}
+ onIssuePopupToggle={[MockFunction]}
+ onIssueSelect={[Function]}
+ onIssueUnselect={[Function]}
+ onIssuesClose={[MockFunction]}
+ onIssuesOpen={[MockFunction]}
+ onLinePopupToggle={[MockFunction]}
+ onLocationSelect={[MockFunction]}
+ onSymbolClick={[MockFunction]}
+ renderDuplicationPopup={[MockFunction]}
+ scroll={[Function]}
+ secondaryIssueLocations={Array []}
+ verticalBuffer={0}
+ />
+ <Line
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ displayAllIssues={false}
+ displayCoverage={true}
+ displayDuplications={false}
+ displayIssues={true}
+ displayLocationMarkers={true}
+ duplications={Array []}
+ duplicationsCount={0}
+ highlighted={false}
+ issueLocations={Array []}
+ issues={Array []}
+ key="2"
+ last={false}
+ line={
+ Object {
+ "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
+ "coverageStatus": "covered",
+ "coveredConditions": 2,
+ "duplicated": false,
+ "isNew": true,
+ "line": 2,
+ "scmAuthor": "simon.brandhof@sonarsource.com",
+ "scmDate": "2018-12-11T10:48:39+0100",
+ "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
+ }
+ }
+ loadDuplications={[MockFunction]}
+ onIssueChange={[MockFunction]}
+ onIssuePopupToggle={[MockFunction]}
+ onIssueSelect={[Function]}
+ onIssueUnselect={[Function]}
+ onIssuesClose={[MockFunction]}
+ onIssuesOpen={[MockFunction]}
+ onLinePopupToggle={[MockFunction]}
+ onLocationSelect={[MockFunction]}
+ onSymbolClick={[MockFunction]}
+ previousLine={
+ Object {
+ "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
+ "coverageStatus": "covered",
+ "coveredConditions": 2,
+ "duplicated": false,
+ "isNew": true,
+ "line": 1,
+ "scmAuthor": "simon.brandhof@sonarsource.com",
+ "scmDate": "2018-12-11T10:48:39+0100",
+ "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
+ }
+ }
+ renderDuplicationPopup={[MockFunction]}
+ scroll={[Function]}
+ secondaryIssueLocations={Array []}
+ verticalBuffer={0}
+ />
+ <Line
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ displayAllIssues={false}
+ displayCoverage={true}
+ displayDuplications={false}
+ displayIssues={true}
+ displayLocationMarkers={true}
+ duplications={Array []}
+ duplicationsCount={0}
+ highlighted={false}
+ issueLocations={Array []}
+ issues={Array []}
+ key="3"
+ last={false}
+ line={
+ Object {
+ "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
+ "coverageStatus": "covered",
+ "coveredConditions": 2,
+ "duplicated": false,
+ "isNew": true,
+ "line": 3,
+ "scmAuthor": "simon.brandhof@sonarsource.com",
+ "scmDate": "2018-12-11T10:48:39+0100",
+ "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
+ }
+ }
+ loadDuplications={[MockFunction]}
+ onIssueChange={[MockFunction]}
+ onIssuePopupToggle={[MockFunction]}
+ onIssueSelect={[Function]}
+ onIssueUnselect={[Function]}
+ onIssuesClose={[MockFunction]}
+ onIssuesOpen={[MockFunction]}
+ onLinePopupToggle={[MockFunction]}
+ onLocationSelect={[MockFunction]}
+ onSymbolClick={[MockFunction]}
+ previousLine={
+ Object {
+ "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
+ "coverageStatus": "covered",
+ "coveredConditions": 2,
+ "duplicated": false,
+ "isNew": true,
+ "line": 2,
+ "scmAuthor": "simon.brandhof@sonarsource.com",
+ "scmDate": "2018-12-11T10:48:39+0100",
+ "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
+ }
+ }
+ renderDuplicationPopup={[MockFunction]}
+ scroll={[Function]}
+ secondaryIssueLocations={Array []}
+ verticalBuffer={0}
+ />
+ <Line
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ displayAllIssues={false}
+ displayCoverage={true}
+ displayDuplications={false}
+ displayIssues={true}
+ displayLocationMarkers={true}
+ duplications={Array []}
+ duplicationsCount={0}
+ highlighted={false}
+ issueLocations={Array []}
+ issues={Array []}
+ key="4"
+ last={false}
+ line={
+ Object {
+ "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
+ "coverageStatus": "covered",
+ "coveredConditions": 2,
+ "duplicated": false,
+ "isNew": true,
+ "line": 4,
+ "scmAuthor": "simon.brandhof@sonarsource.com",
+ "scmDate": "2018-12-11T10:48:39+0100",
+ "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
+ }
+ }
+ loadDuplications={[MockFunction]}
+ onIssueChange={[MockFunction]}
+ onIssuePopupToggle={[MockFunction]}
+ onIssueSelect={[Function]}
+ onIssueUnselect={[Function]}
+ onIssuesClose={[MockFunction]}
+ onIssuesOpen={[MockFunction]}
+ onLinePopupToggle={[MockFunction]}
+ onLocationSelect={[MockFunction]}
+ onSymbolClick={[MockFunction]}
+ previousLine={
+ Object {
+ "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
+ "coverageStatus": "covered",
+ "coveredConditions": 2,
+ "duplicated": false,
+ "isNew": true,
+ "line": 3,
+ "scmAuthor": "simon.brandhof@sonarsource.com",
+ "scmDate": "2018-12-11T10:48:39+0100",
+ "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
+ }
+ }
+ renderDuplicationPopup={[MockFunction]}
+ scroll={[Function]}
+ secondaryIssueLocations={Array []}
+ verticalBuffer={0}
+ />
+ <Line
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ displayAllIssues={false}
+ displayCoverage={true}
+ displayDuplications={false}
+ displayIssues={true}
+ displayLocationMarkers={true}
+ duplications={Array []}
+ duplicationsCount={0}
+ highlighted={false}
+ issueLocations={Array []}
+ issues={Array []}
+ key="5"
+ last={false}
+ line={
+ Object {
+ "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
+ "coverageStatus": "covered",
+ "coveredConditions": 2,
+ "duplicated": false,
+ "isNew": true,
+ "line": 5,
+ "scmAuthor": "simon.brandhof@sonarsource.com",
+ "scmDate": "2018-12-11T10:48:39+0100",
+ "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
+ }
+ }
+ loadDuplications={[MockFunction]}
+ onIssueChange={[MockFunction]}
+ onIssuePopupToggle={[MockFunction]}
+ onIssueSelect={[Function]}
+ onIssueUnselect={[Function]}
+ onIssuesClose={[MockFunction]}
+ onIssuesOpen={[MockFunction]}
+ onLinePopupToggle={[MockFunction]}
+ onLocationSelect={[MockFunction]}
+ onSymbolClick={[MockFunction]}
+ previousLine={
+ Object {
+ "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
+ "coverageStatus": "covered",
+ "coveredConditions": 2,
+ "duplicated": false,
+ "isNew": true,
+ "line": 4,
+ "scmAuthor": "simon.brandhof@sonarsource.com",
+ "scmDate": "2018-12-11T10:48:39+0100",
+ "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
+ }
+ }
+ renderDuplicationPopup={[MockFunction]}
+ scroll={[Function]}
+ secondaryIssueLocations={Array []}
+ verticalBuffer={0}
+ />
+ <Line
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ displayAllIssues={false}
+ displayCoverage={true}
+ displayDuplications={false}
+ displayIssues={true}
+ displayLocationMarkers={true}
+ duplications={Array []}
+ duplicationsCount={0}
+ highlighted={false}
+ issueLocations={Array []}
+ issues={Array []}
+ key="6"
+ last={false}
+ line={
+ Object {
+ "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
+ "coverageStatus": "covered",
+ "coveredConditions": 2,
+ "duplicated": false,
+ "isNew": true,
+ "line": 6,
+ "scmAuthor": "simon.brandhof@sonarsource.com",
+ "scmDate": "2018-12-11T10:48:39+0100",
+ "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
+ }
+ }
+ loadDuplications={[MockFunction]}
+ onIssueChange={[MockFunction]}
+ onIssuePopupToggle={[MockFunction]}
+ onIssueSelect={[Function]}
+ onIssueUnselect={[Function]}
+ onIssuesClose={[MockFunction]}
+ onIssuesOpen={[MockFunction]}
+ onLinePopupToggle={[MockFunction]}
+ onLocationSelect={[MockFunction]}
+ onSymbolClick={[MockFunction]}
+ previousLine={
+ Object {
+ "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
+ "coverageStatus": "covered",
+ "coveredConditions": 2,
+ "duplicated": false,
+ "isNew": true,
+ "line": 5,
+ "scmAuthor": "simon.brandhof@sonarsource.com",
+ "scmDate": "2018-12-11T10:48:39+0100",
+ "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
+ }
+ }
+ renderDuplicationPopup={[MockFunction]}
+ scroll={[Function]}
+ secondaryIssueLocations={Array []}
+ verticalBuffer={0}
+ />
+ <Line
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ displayAllIssues={false}
+ displayCoverage={true}
+ displayDuplications={false}
+ displayIssues={true}
+ displayLocationMarkers={true}
+ duplications={Array []}
+ duplicationsCount={0}
+ highlighted={false}
+ issueLocations={Array []}
+ issues={Array []}
+ key="7"
+ last={false}
+ line={
+ Object {
+ "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
+ "coverageStatus": "covered",
+ "coveredConditions": 2,
+ "duplicated": false,
+ "isNew": true,
+ "line": 7,
+ "scmAuthor": "simon.brandhof@sonarsource.com",
+ "scmDate": "2018-12-11T10:48:39+0100",
+ "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
+ }
+ }
+ loadDuplications={[MockFunction]}
+ onIssueChange={[MockFunction]}
+ onIssuePopupToggle={[MockFunction]}
+ onIssueSelect={[Function]}
+ onIssueUnselect={[Function]}
+ onIssuesClose={[MockFunction]}
+ onIssuesOpen={[MockFunction]}
+ onLinePopupToggle={[MockFunction]}
+ onLocationSelect={[MockFunction]}
+ onSymbolClick={[MockFunction]}
+ previousLine={
+ Object {
+ "code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
+ "coverageStatus": "covered",
+ "coveredConditions": 2,
+ "duplicated": false,
+ "isNew": true,
+ "line": 6,
+ "scmAuthor": "simon.brandhof@sonarsource.com",
+ "scmDate": "2018-12-11T10:48:39+0100",
+ "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
+ }
+ }
+ renderDuplicationPopup={[MockFunction]}
+ scroll={[Function]}
+ secondaryIssueLocations={Array []}
+ verticalBuffer={0}
+ />
+ </tbody>
+ </table>
+ <div
+ className="expand-block expand-block-below"
+ >
+ <button
+ aria-label="source_viewer.expand_below"
+ onClick={[Function]}
+ type="button"
>
- <td
- colSpan={5}
- >
- <button
- aria-label="source_viewer.expand_below"
- onClick={[Function]}
- type="button"
- >
- <ExpandSnippetIcon />
- </button>
- </td>
- </tr>
- </tbody>
- </table>
+ <ExpandSnippetIcon />
+ </button>
+ </div>
+ </div>
</div>
`;
diff --git a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/utils-test.ts b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/utils-test.ts
index ad114d760a3..7f93c687f3a 100644
--- a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/utils-test.ts
+++ b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/utils-test.ts
@@ -17,13 +17,8 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { keyBy, range } from 'lodash';
import { groupLocationsByComponent, createSnippets, expandSnippet } from '../utils';
-import {
- mockFlowLocation,
- mockSnippetsByComponent,
- mockSourceLine
-} from '../../../../helpers/testMocks';
+import { mockFlowLocation, mockSnippetsByComponent } from '../../../../helpers/testMocks';
describe('groupLocationsByComponent', () => {
it('should handle empty args', () => {
@@ -92,12 +87,11 @@ describe('createSnippets', () => {
textRange: { startLine: 19, startOffset: 2, endLine: 19, endOffset: 3 }
})
],
- mockSnippetsByComponent('', [14, 15, 16, 17, 18, 19, 20, 21, 22]).sources,
false
);
expect(results).toHaveLength(1);
- expect(results[0]).toHaveLength(8);
+ expect(results[0]).toEqual({ index: 0, start: 14, end: 21 });
});
it('should merge snippets correctly, even when not in sequence', () => {
@@ -113,13 +107,12 @@ describe('createSnippets', () => {
textRange: { startLine: 14, startOffset: 2, endLine: 14, endOffset: 3 }
})
],
- mockSnippetsByComponent('', [12, 13, 14, 15, 16, 17, 18, 45, 46, 47, 48, 49]).sources,
false
);
expect(results).toHaveLength(2);
- expect(results[0]).toHaveLength(7);
- expect(results[1]).toHaveLength(5);
+ expect(results[0]).toEqual({ index: 0, start: 12, end: 18 });
+ expect(results[1]).toEqual({ index: 1, start: 45, end: 49 });
});
it('should merge three snippets together', () => {
@@ -138,56 +131,46 @@ describe('createSnippets', () => {
textRange: { startLine: 18, startOffset: 2, endLine: 18, endOffset: 3 }
})
],
- mockSnippetsByComponent('', [14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 45, 46, 47, 48, 49])
- .sources,
false
);
expect(results).toHaveLength(2);
- expect(results[0]).toHaveLength(11);
- expect(results[1]).toHaveLength(5);
+ expect(results[0]).toEqual({ index: 0, start: 14, end: 24 });
+ expect(results[1]).toEqual({ index: 1, start: 45, end: 49 });
});
});
describe('expandSnippet', () => {
it('should add lines above', () => {
- const lines = keyBy(range(4, 19).map(line => mockSourceLine({ line })), 'line');
- const snippets = [[lines[14], lines[15], lines[16], lines[17], lines[18]]];
+ const snippets = [{ start: 14, end: 18, index: 0 }];
- const result = expandSnippet({ direction: 'up', lines, snippetIndex: 0, snippets });
+ const result = expandSnippet({ direction: 'up', snippetIndex: 0, snippets });
expect(result).toHaveLength(1);
- expect(result[0]).toHaveLength(15);
- expect(result[0].map(l => l.line)).toEqual(range(4, 19));
+ expect(result[0]).toEqual({ start: 4, end: 18, index: 0 });
});
it('should add lines below', () => {
- const lines = keyBy(range(4, 19).map(line => mockSourceLine({ line })), 'line');
- const snippets = [[lines[4], lines[5], lines[6], lines[7], lines[8]]];
+ const snippets = [{ start: 4, end: 8, index: 0 }];
- const result = expandSnippet({ direction: 'down', lines, snippetIndex: 0, snippets });
+ const result = expandSnippet({ direction: 'down', snippetIndex: 0, snippets });
expect(result).toHaveLength(1);
- expect(result[0].map(l => l.line)).toEqual(range(4, 19));
+ expect(result[0]).toEqual({ start: 4, end: 18, index: 0 });
});
it('should merge snippets if necessary', () => {
- const lines = keyBy(
- range(4, 23)
- .concat(range(38, 43))
- .map(line => mockSourceLine({ line })),
- 'line'
- );
const snippets = [
- [lines[4], lines[5], lines[6], lines[7], lines[8]],
- [lines[38], lines[39], lines[40], lines[41], lines[42]],
- [lines[17], lines[18], lines[19], lines[20], lines[21]]
+ { index: 1, start: 4, end: 8 },
+ { index: 2, start: 38, end: 42 },
+ { index: 3, start: 17, end: 21 }
];
- const result = expandSnippet({ direction: 'down', lines, snippetIndex: 0, snippets });
+ const result = expandSnippet({ direction: 'down', snippetIndex: 1, snippets });
- expect(result).toHaveLength(2);
- expect(result[0].map(l => l.line)).toEqual(range(4, 22));
- expect(result[1].map(l => l.line)).toEqual(range(38, 43));
+ expect(result).toHaveLength(3);
+ expect(result[0]).toEqual({ index: 1, start: 4, end: 21 });
+ expect(result[1]).toEqual({ index: 2, start: 38, end: 42 });
+ expect(result[2]).toEqual({ index: 3, start: 17, end: 21, toDelete: true });
});
});
diff --git a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/utils.ts b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/utils.ts
index 5c34f42dfbb..c900f543268 100644
--- a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/utils.ts
+++ b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/utils.ts
@@ -42,62 +42,53 @@ function collision([startA, endA]: number[], [startB, endB]: number[]) {
return !(startA > endB + MERGE_DISTANCE || endA < startB - MERGE_DISTANCE);
}
-export function createSnippets(
- locations: T.FlowLocation[],
- componentLines: T.LineMap = {},
- last: boolean
-): T.SourceLine[][] {
- return rangesToSnippets(
- // For each location's range (2 above and 2 below), and then compare with other ranges
- // to merge snippets that collide.
- locations.reduce((snippets: Array<{ start: number; end: number }>, loc, index) => {
- const startIndex = Math.max(1, loc.textRange.startLine - LINES_ABOVE);
- const endIndex =
- loc.textRange.endLine +
- (last && index === locations.length - 1 ? LINES_BELOW_LAST : LINES_BELOW);
-
- let firstCollision: { start: number; end: number } | undefined;
-
- // Remove ranges that collide into the first collision
- snippets = snippets.filter(snippet => {
- if (collision([snippet.start, snippet.end], [startIndex, endIndex])) {
- let keep = false;
- // Check if we've already collided
- if (!firstCollision) {
- firstCollision = snippet;
- keep = true;
- }
- // Merge with first collision:
- firstCollision.start = Math.min(startIndex, snippet.start, firstCollision.start);
- firstCollision.end = Math.max(endIndex, snippet.end, firstCollision.end);
-
- // remove the range if it was not the first collision
- return keep;
+export function createSnippets(locations: T.FlowLocation[], last: boolean): T.Snippet[] {
+ // For each location's range (2 above and 2 below), and then compare with other ranges
+ // to merge snippets that collide.
+ return locations.reduce((snippets: T.Snippet[], loc, index) => {
+ const startIndex = Math.max(1, loc.textRange.startLine - LINES_ABOVE);
+ const endIndex =
+ loc.textRange.endLine +
+ (last && index === locations.length - 1 ? LINES_BELOW_LAST : LINES_BELOW);
+
+ let firstCollision: { start: number; end: number } | undefined;
+
+ // Remove ranges that collide into the first collision
+ snippets = snippets.filter(snippet => {
+ if (collision([snippet.start, snippet.end], [startIndex, endIndex])) {
+ let keep = false;
+ // Check if we've already collided
+ if (!firstCollision) {
+ firstCollision = snippet;
+ keep = true;
}
- return true;
- });
+ // Merge with first collision:
+ firstCollision.start = Math.min(startIndex, snippet.start, firstCollision.start);
+ firstCollision.end = Math.max(endIndex, snippet.end, firstCollision.end);
- if (firstCollision === undefined) {
- snippets.push({
- start: startIndex,
- end: endIndex
- });
+ // remove the range if it was not the first collision
+ return keep;
}
+ return true;
+ });
+
+ if (firstCollision === undefined) {
+ snippets.push({
+ start: startIndex,
+ end: endIndex,
+ index
+ });
+ }
- return snippets;
- }, []),
- componentLines
- );
+ return snippets;
+ }, []);
}
-function rangesToSnippets(
- ranges: Array<{ start: number; end: number }>,
- componentLines: T.LineMap
-) {
- return ranges
- .map(range => {
+export function linesForSnippets(snippets: T.Snippet[], componentLines: T.LineMap) {
+ return snippets
+ .map(snippet => {
const lines = [];
- for (let i = range.start; i <= range.end; i++) {
+ for (let i = snippet.start; i <= snippet.end; i++) {
if (componentLines[i]) {
lines.push(componentLines[i]);
}
@@ -133,51 +124,36 @@ export function groupLocationsByComponent(
export function expandSnippet({
direction,
- lines,
snippetIndex,
snippets
}: {
direction: T.ExpandDirection;
- lines: T.LineMap;
snippetIndex: number;
- snippets: T.SourceLine[][];
+ snippets: T.Snippet[];
}) {
- const snippetToExpand = snippets[snippetIndex];
-
- const snippetToExpandRange = {
- start: Math.max(0, snippetToExpand[0].line - (direction === 'up' ? EXPAND_BY_LINES : 0)),
- end:
- snippetToExpand[snippetToExpand.length - 1].line +
- (direction === 'down' ? EXPAND_BY_LINES : 0)
- };
+ const snippetToExpand = snippets.find(s => s.index === snippetIndex);
+ if (!snippetToExpand) {
+ throw new Error(`Snippet ${snippetIndex} not found`);
+ }
+
+ snippetToExpand.start = Math.max(
+ 0,
+ snippetToExpand.start - (direction === 'up' ? EXPAND_BY_LINES : 0)
+ );
+ snippetToExpand.end += direction === 'down' ? EXPAND_BY_LINES : 0;
- const ranges: Array<{ start: number; end: number }> = [];
-
- snippets.forEach((snippet, index: number) => {
- const snippetRange = {
- start: snippet[0].line,
- end: snippet[snippet.length - 1].line
- };
-
- if (index === snippetIndex) {
- // keep expanded snippet
- ranges.push(snippetToExpandRange);
- } else if (
- collision(
- [snippetRange.start, snippetRange.end],
- [snippetToExpandRange.start, snippetToExpandRange.end]
- )
- ) {
+ return snippets.map(snippet => {
+ if (snippet.index === snippetIndex) {
+ return snippetToExpand;
+ }
+ if (collision([snippet.start, snippet.end], [snippetToExpand.start, snippetToExpand.end])) {
// Merge with expanded snippet
- snippetToExpandRange.start = Math.min(snippetRange.start, snippetToExpandRange.start);
- snippetToExpandRange.end = Math.max(snippetRange.end, snippetToExpandRange.end);
- } else {
- // No collision, jsut keep the snippet
- ranges.push(snippetRange);
+ snippetToExpand.start = Math.min(snippet.start, snippetToExpand.start);
+ snippetToExpand.end = Math.max(snippet.end, snippetToExpand.end);
+ snippet.toDelete = true;
}
+ return snippet;
});
-
- return rangesToSnippets(ranges, lines);
}
export function inSnippet(line: number, snippet: T.SourceLine[]) {
diff --git a/server/sonar-web/src/main/js/apps/issues/styles.css b/server/sonar-web/src/main/js/apps/issues/styles.css
index e89e0916a7a..700eddf3eec 100644
--- a/server/sonar-web/src/main/js/apps/issues/styles.css
+++ b/server/sonar-web/src/main/js/apps/issues/styles.css
@@ -242,13 +242,28 @@
margin: var(--gridSize);
border: 1px solid var(--gray80);
overflow-x: auto;
+ overflow-y: hidden;
+ transition: max-height 0.2s;
}
-.snippet > table {
+.snippet > div {
+ display: table;
+ width: 100%;
+ position: relative;
+ transition: margin-top 0.2s;
+}
+
+.snippet table {
+ width: 100%;
+}
+
+.expand-block {
+ position: absolute;
+ z-index: 2;
width: 100%;
}
-.expand-block > td > button {
+.expand-block > button {
background: transparent;
box-sizing: border-box;
color: var(--secondFontColor);
@@ -259,17 +274,27 @@
text-align: left;
cursor: pointer;
}
-.expand-block > td > button:hover,
-.expand-block > td > button:focus,
-.expand-block > td > button:active {
+.expand-block > button:hover,
+.expand-block > button:focus,
+.expand-block > button:active {
color: var(--darkBlue);
outline: none;
}
.expand-block-above {
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAAXNSR0IArs4c6QAAADdJREFUCB1dzMEKADAIAlBd1v9/bcc2YgRjHh8qq2qTxCQzsX4wM6y30RARF3sy0Es1SIK7Y64OpCES1W69JS4AAAAASUVORK5CYII=');
+ top: 0;
}
.expand-block-below {
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4wQQBjQEQVd5jwAAADhJREFUCNddyTEKADEMA8GVA/7/Z+PGwUp1cGTaYe/tv5lxrLWoKj6SiMzkjZDEG7JtANt0N+ccLrB/KZxXTt7fAAAAAElFTkSuQmCC');
+ bottom: 0;
+}
+
+.source-table.expand-up {
+ margin-top: 20px;
+}
+
+.source-table.expand-down {
+ margin-bottom: 20px;
}
.issues-my-issues-filter {