From 0599d3bbc85be6a96a18cd67ca84bc0c236c5f51 Mon Sep 17 00:00:00 2001 From: Mathieu Suen Date: Tue, 19 Apr 2022 15:17:47 +0200 Subject: SONAR-16042 Move issues box rendering outside of line component --- .../components/SourceViewer/SourceViewerCode.tsx | 38 ++-- .../js/components/SourceViewer/components/Line.tsx | 33 +-- .../SourceViewer/components/LineCode.tsx | 64 ++---- .../SourceViewer/components/LineIssuesList.tsx | 36 +++- .../components/__tests__/Line-test.tsx | 6 - .../components/__tests__/LineCode-test.tsx | 20 +- .../components/__tests__/LineIssueList-test.tsx | 52 +++++ .../__tests__/__snapshots__/Line-test.tsx.snap | 76 ------- .../__tests__/__snapshots__/LineCode-test.tsx.snap | 234 +-------------------- .../__snapshots__/LineIssueList-test.tsx.snap | 54 +++++ .../js/components/SourceViewer/helpers/lines.ts | 8 +- 11 files changed, 182 insertions(+), 439 deletions(-) create mode 100644 server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/LineIssueList-test.tsx create mode 100644 server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/LineIssueList-test.tsx.snap (limited to 'server/sonar-web/src/main/js/components/SourceViewer') diff --git a/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerCode.tsx b/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerCode.tsx index dead6b916ac..c591c404cde 100644 --- a/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerCode.tsx +++ b/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerCode.tsx @@ -30,12 +30,9 @@ import { SourceLine } from '../../types/types'; import Line from './components/Line'; +import LineIssuesList from './components/LineIssuesList'; import { getSecondaryIssueLocationsForLine } from './helpers/issueLocations'; -import { - optimizeHighlightedSymbols, - optimizeLocationMessage, - optimizeSelectedIssue -} from './helpers/lines'; +import { optimizeHighlightedSymbols, optimizeLocationMessage } from './helpers/lines'; const EMPTY_ARRAY: any[] = []; @@ -124,9 +121,12 @@ export default class SourceViewerCode extends React.PureComponent { }) => { const { highlightedLocationMessage, + selectedIssue, + openIssuesByLine, + issueLocationsByLine, + displayAllIssues, highlightedLocations, metricKey, - selectedIssue, sources } = this.props; @@ -152,12 +152,9 @@ export default class SourceViewerCode extends React.PureComponent { return ( 0} @@ -174,14 +171,11 @@ export default class SourceViewerCode extends React.PureComponent { this.props.highlightedSymbols )} issueLocations={this.getIssueLocationsForLine(line)} - issuePopup={this.props.issuePopup} issues={issuesForLine} key={line.line || line.code} last={index === this.props.sources.length - 1 && !this.props.hasSourcesAfter} line={line} loadDuplications={this.props.loadDuplications} - onIssueChange={this.props.onIssueChange} - onIssuePopupToggle={this.props.onIssuePopupToggle} onIssueSelect={this.props.onIssueSelect} onIssueUnselect={this.props.onIssueUnselect} onIssuesClose={this.props.onIssuesClose} @@ -193,9 +187,23 @@ export default class SourceViewerCode extends React.PureComponent { renderDuplicationPopup={this.props.renderDuplicationPopup} scroll={this.props.scroll} scrollToUncoveredLine={scrollToUncoveredLine} - secondaryIssueLocations={secondaryIssueLocations} - selectedIssue={optimizeSelectedIssue(selectedIssue, issuesForLine)} - /> + secondaryIssueLocations={secondaryIssueLocations}> + + ); }; diff --git a/server/sonar-web/src/main/js/components/SourceViewer/components/Line.tsx b/server/sonar-web/src/main/js/components/SourceViewer/components/Line.tsx index 29df74831bd..e8a060ba501 100644 --- a/server/sonar-web/src/main/js/components/SourceViewer/components/Line.tsx +++ b/server/sonar-web/src/main/js/components/SourceViewer/components/Line.tsx @@ -20,7 +20,6 @@ import classNames from 'classnames'; import { times } from 'lodash'; import * as React from 'react'; -import { BranchLike } from '../../../types/branch-like'; import { Issue, LinearIssueLocation, SourceLine } from '../../../types/types'; import './Line.css'; import LineCode from './LineCode'; @@ -31,13 +30,10 @@ import LineNumber from './LineNumber'; import LineSCM from './LineSCM'; interface Props { - additionalChild?: React.ReactNode; - branchLike: BranchLike | undefined; + children?: React.ReactNode; displayAllIssues?: boolean; displayCoverage: boolean; displayDuplications: boolean; - displayIssueLocationsCount?: boolean; - displayIssueLocationsLink?: boolean; displayIssues: boolean; displayLineNumberOptions?: boolean; displayLocationMarkers?: boolean; @@ -49,13 +45,10 @@ interface Props { highlightedLocationMessage: { index: number; text: string | undefined } | undefined; highlightedSymbols: string[] | undefined; issueLocations: LinearIssueLocation[]; - issuePopup: { issue: string; name: string } | undefined; issues: Issue[]; last: boolean; line: SourceLine; loadDuplications: (line: SourceLine) => void; - onIssueChange: (issue: Issue) => void; - onIssuePopupToggle: (issueKey: string, popupName: string, open?: boolean) => void; onIssuesClose: (line: SourceLine) => void; onIssueSelect: (issueKey: string) => void; onIssuesOpen: (line: SourceLine) => void; @@ -68,7 +61,6 @@ interface Props { scroll?: (element: HTMLElement) => void; scrollToUncoveredLine?: boolean; secondaryIssueLocations: LinearIssueLocation[]; - selectedIssue: string | undefined; verticalBuffer?: number; } @@ -91,13 +83,10 @@ export default class Line extends React.PureComponent { render() { const { - additionalChild, - branchLike, + children, displayAllIssues, displayCoverage, displayDuplications, - displayIssueLocationsCount, - displayIssueLocationsLink, displayLineNumberOptions, displayLocationMarkers, highlightedLocationMessage, @@ -109,7 +98,6 @@ export default class Line extends React.PureComponent { highlighted, highlightedSymbols, issueLocations, - issuePopup, issues, last, line, @@ -117,7 +105,6 @@ export default class Line extends React.PureComponent { previousLine, scrollToUncoveredLine, secondaryIssueLocations, - selectedIssue, verticalBuffer } = this.props; @@ -186,28 +173,18 @@ export default class Line extends React.PureComponent { )} + secondaryIssueLocations={secondaryIssueLocations}> + {children} + ); } diff --git a/server/sonar-web/src/main/js/components/SourceViewer/components/LineCode.tsx b/server/sonar-web/src/main/js/components/SourceViewer/components/LineCode.tsx index a6dc9efcd28..21736e0cdff 100644 --- a/server/sonar-web/src/main/js/components/SourceViewer/components/LineCode.tsx +++ b/server/sonar-web/src/main/js/components/SourceViewer/components/LineCode.tsx @@ -19,8 +19,7 @@ */ import classNames from 'classnames'; import * as React from 'react'; -import { BranchLike } from '../../../types/branch-like'; -import { Issue, LinearIssueLocation, SourceLine } from '../../../types/types'; +import { LinearIssueLocation, SourceLine } from '../../../types/types'; import LocationIndex from '../../common/LocationIndex'; import Tooltip from '../../controls/Tooltip'; import { @@ -29,37 +28,26 @@ import { splitByTokens, Token } from '../helpers/highlight'; -import LineIssuesList from './LineIssuesList'; interface Props { - additionalChild?: React.ReactNode; - branchLike: BranchLike | undefined; - displayIssueLocationsCount?: boolean; - displayIssueLocationsLink?: boolean; + className?: string; displayLocationMarkers?: boolean; highlightedLocationMessage: { index: number; text: string | undefined } | undefined; highlightedSymbols: string[] | undefined; issueLocations: LinearIssueLocation[]; - issuePopup: { issue: string; name: string } | undefined; - issues: Issue[]; line: SourceLine; - onIssueChange: (issue: Issue) => void; - onIssuePopupToggle: (issue: string, popupName: string, open?: boolean) => void; - onIssueSelect: (issueKey: string) => void; onLocationSelect: ((index: number) => void) | undefined; onSymbolClick: (symbols: Array) => void; padding?: number; scroll?: (element: HTMLElement) => void; secondaryIssueLocations: LinearIssueLocation[]; - selectedIssue: string | undefined; - showIssues?: boolean; } interface State { tokens: Token[]; } -export default class LineCode extends React.PureComponent { +export default class LineCode extends React.PureComponent, State> { activeMarkerNode?: HTMLElement | null; codeNode?: HTMLElement | null; symbols?: NodeListOf; @@ -157,17 +145,14 @@ export default class LineCode extends React.PureComponent { render() { const { - additionalChild, + children, + className, highlightedLocationMessage, highlightedSymbols, - issues, issueLocations, line, - onIssueSelect, padding, - secondaryIssueLocations, - selectedIssue, - showIssues + secondaryIssueLocations } = this.props; let tokens = [...this.state.tokens]; @@ -195,10 +180,6 @@ export default class LineCode extends React.PureComponent { } } - const className = classNames('source-line-code', 'code', { - 'has-issues': issues.length > 0 - }); - const renderedTokens: React.ReactNode[] = []; // track if the first marker is displayed before the source code @@ -226,38 +207,17 @@ export default class LineCode extends React.PureComponent { }); const style = padding ? { paddingBottom: `${padding}px` } : undefined; - const filteredSelectedIssues = issues.filter(i => i.key === selectedIssue); return ( - +
 (this.codeNode = node)}>{renderedTokens}
- {showIssues && issues.length > 0 && ( - - )} - {selectedIssue && !showIssues && issueLocations.length > 0 && ( - - )} - {additionalChild} + + {children} ); } diff --git a/server/sonar-web/src/main/js/components/SourceViewer/components/LineIssuesList.tsx b/server/sonar-web/src/main/js/components/SourceViewer/components/LineIssuesList.tsx index dbb0aca4ac4..5584d032e47 100644 --- a/server/sonar-web/src/main/js/components/SourceViewer/components/LineIssuesList.tsx +++ b/server/sonar-web/src/main/js/components/SourceViewer/components/LineIssuesList.tsx @@ -19,27 +19,51 @@ */ import * as React from 'react'; import { BranchLike } from '../../../types/branch-like'; -import { Issue as TypeIssue } from '../../../types/types'; +import { Issue as TypeIssue, LinearIssueLocation, SourceLine } from '../../../types/types'; import Issue from '../../issue/Issue'; -interface Props { +export interface LineIssuesListProps { branchLike: BranchLike | undefined; + displayAllIssues?: boolean; displayIssueLocationsCount?: boolean; displayIssueLocationsLink?: boolean; + issuesForLine: TypeIssue[]; issuePopup: { issue: string; name: string } | undefined; - issues: TypeIssue[]; + issueLocationsByLine: { [line: number]: LinearIssueLocation[] }; + line: SourceLine; onIssueChange: (issue: TypeIssue) => void; onIssueClick: (issueKey: string) => void; onIssuePopupToggle: (issue: string, popupName: string, open?: boolean) => void; + openIssuesByLine: { [line: number]: boolean }; selectedIssue: string | undefined; } -export default function LineIssuesList(props: Props) { - const { issuePopup } = props; +export default function LineIssuesList(props: LineIssuesListProps) { + const { + line, + displayAllIssues, + openIssuesByLine, + selectedIssue, + issuesForLine, + issueLocationsByLine, + issuePopup + } = props; + const showIssues = openIssuesByLine[line.line] || displayAllIssues; + const issueLocations = issueLocationsByLine[line.line] || []; + let displayedIssue: TypeIssue[] = []; + if (showIssues && issuesForLine.length > 0) { + displayedIssue = issuesForLine; + } else if (selectedIssue && !showIssues && issueLocations.length) { + displayedIssue = issuesForLine.filter(i => i.key === selectedIssue); + } + + if (displayedIssue.length === 0) { + return null; + } return (
- {props.issues.map(issue => ( + {displayedIssue.map(issue => ( { function shallowRender(props: Partial = {}) { return shallow( = {}) { highlightedLocationMessage={undefined} highlightedSymbols={undefined} issueLocations={[]} - issuePopup={undefined} issues={[mockIssue(), mockIssue(false, { type: 'VULNERABILITY' })]} last={false} line={mockSourceLine()} loadDuplications={jest.fn()} - onIssueChange={jest.fn()} - onIssuePopupToggle={jest.fn()} onIssuesClose={jest.fn()} onIssueSelect={jest.fn()} onIssuesOpen={jest.fn()} @@ -95,7 +90,6 @@ function shallowRender(props: Partial = {}) { renderDuplicationPopup={jest.fn()} scroll={jest.fn()} secondaryIssueLocations={[]} - selectedIssue={undefined} {...props} /> ); diff --git a/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/LineCode-test.tsx b/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/LineCode-test.tsx index 616878e5037..8d15db4f708 100644 --- a/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/LineCode-test.tsx +++ b/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/LineCode-test.tsx @@ -19,14 +19,12 @@ */ import { shallow } from 'enzyme'; import * as React from 'react'; -import { mockBranch } from '../../../../helpers/mocks/branch-like'; -import { mockIssue, mockSourceLine } from '../../../../helpers/testMocks'; +import { mockSourceLine } from '../../../../helpers/testMocks'; import LineCode from '../LineCode'; -import LineIssuesList from '../LineIssuesList'; it('render code', () => { expect(shallowRender()).toMatchSnapshot(); - expect(shallowRender({ additionalChild:
additional child
})).toMatchSnapshot( + expect(shallowRender({ children:
additional child
})).toMatchSnapshot( 'with additional child' ); expect( @@ -38,31 +36,17 @@ it('render code', () => { ).toMatchSnapshot('with secondary location'); }); -it('should not render issue list when no issue location', () => { - const wrapper = shallowRender({ issueLocations: [], showIssues: false }); - - expect(wrapper.find(LineIssuesList).length).toBe(0); -}); - function shallowRender(props: Partial = {}) { return shallow( ); diff --git a/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/LineIssueList-test.tsx b/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/LineIssueList-test.tsx new file mode 100644 index 00000000000..70ec54f61d2 --- /dev/null +++ b/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/LineIssueList-test.tsx @@ -0,0 +1,52 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 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 { mockBranch } from '../../../../helpers/mocks/branch-like'; +import { mockIssue, mockSourceLine } from '../../../../helpers/testMocks'; +import LineIssuesList, { LineIssuesListProps } from '../LineIssuesList'; + +it('shoule render issues', () => { + const wrapper = shallowRender({ + selectedIssue: 'issue', + issueLocationsByLine: { '1': [{ from: 1, to: 1, line: 1 }] }, + line: mockSourceLine({ line: 1 }), + issuesForLine: [mockIssue(false, { key: 'issue' })] + }); + expect(wrapper).toMatchSnapshot(); +}); + +function shallowRender(props: Partial = {}) { + return shallow( + + ); +} diff --git a/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/Line-test.tsx.snap b/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/Line-test.tsx.snap index e916b9827db..d848cd62fe0 100644 --- a/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/Line-test.tsx.snap +++ b/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/Line-test.tsx.snap @@ -41,80 +41,8 @@ exports[`should render correctly for last, new, and highlighted lines 1`] = ` className="source-meta source-line-issues" /> import java.util.ArrayList;", @@ -128,14 +56,10 @@ exports[`should render correctly for last, new, and highlighted lines 1`] = ` "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0", } } - onIssueChange={[MockFunction]} - onIssuePopupToggle={[MockFunction]} - onIssueSelect={[MockFunction]} onLocationSelect={[MockFunction]} onSymbolClick={[MockFunction]} scroll={[MockFunction]} secondaryIssueLocations={Array []} - showIssues={false} /> `; diff --git a/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/LineCode-test.tsx.snap b/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/LineCode-test.tsx.snap index db64b67a1dc..fa518fddd0e 100644 --- a/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/LineCode-test.tsx.snap +++ b/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/LineCode-test.tsx.snap @@ -2,7 +2,7 @@ exports[`render code 1`] = `
- `; exports[`render code: with additional child 1`] = `
-
additional child
@@ -245,7 +93,7 @@ exports[`render code: with additional child 1`] = ` exports[`render code: with secondary location 1`] = `
- `; diff --git a/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/LineIssueList-test.tsx.snap b/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/LineIssueList-test.tsx.snap new file mode 100644 index 00000000000..eef65511cda --- /dev/null +++ b/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/LineIssueList-test.tsx.snap @@ -0,0 +1,54 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`shoule render issues 1`] = ` +
+ +
+`; diff --git a/server/sonar-web/src/main/js/components/SourceViewer/helpers/lines.ts b/server/sonar-web/src/main/js/components/SourceViewer/helpers/lines.ts index ac520aca377..ef4bcf0348c 100644 --- a/server/sonar-web/src/main/js/components/SourceViewer/helpers/lines.ts +++ b/server/sonar-web/src/main/js/components/SourceViewer/helpers/lines.ts @@ -18,7 +18,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import { intersection } from 'lodash'; -import { Issue, LinearIssueLocation } from '../../../types/types'; +import { LinearIssueLocation } from '../../../types/types'; export const LINES_TO_LOAD = 500; @@ -42,9 +42,3 @@ export function optimizeLocationMessage( ? highlightedLocationMessage : undefined; } - -export function optimizeSelectedIssue(selectedIssue: string | undefined, issuesForLine: Issue[]) { - return selectedIssue !== undefined && issuesForLine.find(issue => issue.key === selectedIssue) - ? selectedIssue - : undefined; -} -- cgit v1.2.3