],
'component.key'
)
+ },
+ {
+ issue: mockRawIssue(false, {
+ key: 'issue3',
+ component: 'project:file.bar',
+ message: 'Second issue',
+ rule: 'other',
+ textRange: {
+ startLine: 28,
+ endLine: 28,
+ startOffset: 0,
+ endOffset: 1
+ }
+ }),
+ snippets: keyBy(
+ [
+ mockSnippetsByComponent(
+ 'file.bar',
+ 'project',
+ times(40, i => i + 20)
+ )
+ ],
+ 'component.key'
+ )
}
];
(searchIssues as jest.Mock).mockImplementation(this.handleSearchIssues);
).toBeInTheDocument();
});
+it('should be able to navigate to other issue located in the same file', async () => {
+ const user = userEvent.setup();
+ renderIssueApp();
+ await user.click(await screen.findByRole('region', { name: 'Fix that' }));
+ expect(await screen.findByRole('region', { name: 'Second issue' })).toBeInTheDocument();
+ await user.click(await screen.findByRole('region', { name: 'Second issue' }));
+ expect(screen.getByRole('heading', { level: 1, name: 'Second issue' })).toBeInTheDocument();
+});
+
it('should support OWASP Top 10 version 2021', async () => {
const user = userEvent.setup();
renderIssueApp();
issues={issues}
locationsNavigator={this.state.locationsNavigator}
onIssueChange={this.handleIssueChange}
+ onIssueSelect={this.openIssue}
onLocationSelect={this.selectLocation}
openIssue={openIssue}
selectedFlowIndex={this.state.selectedFlowIndex}
issues: Issue[];
locationsNavigator: boolean;
onIssueChange: (issue: Issue) => void;
+ onIssueSelect: (issueKey: string) => void;
onLocationSelect: (index: number) => void;
openIssue: Issue;
selectedFlowIndex: number | undefined;
issues={this.props.issues}
locations={locations}
onIssueChange={this.props.onIssueChange}
+ onIssueSelect={this.props.onIssueSelect}
onLoaded={this.handleLoaded}
onLocationSelect={this.props.onLocationSelect}
scroll={this.handleScroll}
issues={[mockIssue()]}
locationsNavigator={true}
onIssueChange={jest.fn()}
+ onIssueSelect={jest.fn()}
onLocationSelect={jest.fn()}
openIssue={mockIssue()}
selectedFlowIndex={undefined}
]
}
onIssueChange={[MockFunction]}
+ onIssueSelect={[MockFunction]}
onLoaded={[Function]}
onLocationSelect={[MockFunction]}
scroll={[Function]}
]
}
onIssueChange={[MockFunction]}
+ onIssueSelect={[MockFunction]}
onLoaded={[Function]}
onLocationSelect={[MockFunction]}
scroll={[Function]}
}
locations={Array []}
onIssueChange={[MockFunction]}
+ onIssueSelect={[MockFunction]}
onLoaded={[Function]}
onLocationSelect={[MockFunction]}
scroll={[Function]}
]
}
onIssueChange={[MockFunction]}
+ onIssueSelect={[MockFunction]}
onLoaded={[Function]}
onLocationSelect={[MockFunction]}
scroll={[Function]}
import * as React from 'react';
import { getSources } from '../../../api/components';
import Issue from '../../../components/issue/Issue';
-import LineIssuesList from '../../../components/SourceViewer/components/LineIssuesList';
+import SecondaryIssue from '../../../components/issue/SecondaryIssue';
import getCoverageStatus from '../../../components/SourceViewer/helpers/getCoverageStatus';
import { locationsByLine } from '../../../components/SourceViewer/helpers/indexing';
import SourceViewerHeaderSlim from '../../../components/SourceViewer/SourceViewerHeaderSlim';
loadDuplications: (component: string, line: SourceLine) => void;
locations: FlowLocation[];
onIssueChange: (issue: TypeIssue) => void;
+ onIssueSelect: (issueKey: string) => void;
onIssuePopupToggle: (issue: string, popupName: string, open?: boolean) => void;
onLocationSelect: (index: number) => void;
renderDuplicationPopup: (
additionalLines: { [line: number]: SourceLine };
highlightedSymbols: string[];
loading: boolean;
- openIssuesByLine: Dict<boolean>;
snippets: Snippet[];
}
additionalLines: {},
highlightedSymbols: [],
loading: false,
- openIssuesByLine: {},
snippets: []
};
);
};
- handleOpenIssues = (line: SourceLine) => {
- this.setState(state => ({
- openIssuesByLine: { ...state.openIssuesByLine, [line.line]: true }
- }));
- };
-
- handleCloseIssues = (line: SourceLine) => {
- this.setState(state => ({
- openIssuesByLine: { ...state.openIssuesByLine, [line.line]: false }
- }));
- };
-
handleSymbolClick = (clickedSymbols: string[]) => {
this.setState(({ highlightedSymbols }) => {
const newHighlightedSymbols = clickedSymbols.filter(
};
renderIssuesList = (line: SourceLine) => {
- const { openIssuesByLine } = this.state;
-
- const { isLastOccurenceOfPrimaryComponent, issue, issuesByLine, snippetGroup } = this.props;
+ const {
+ isLastOccurenceOfPrimaryComponent,
+ issue,
+ issuesByLine,
+ snippetGroup,
+ branchLike
+ } = this.props;
const locations =
issue.component === snippetGroup.component.key && issue.textRange !== undefined
? locationsByLine([issue])
const isFlow = issue.secondaryLocations.length === 0;
const includeIssueLocation = isFlow ? isLastOccurenceOfPrimaryComponent : true;
-
const issuesForLine = issuesByLine[line.line] || [];
+ const issueLocations = includeIssueLocation ? locations[line.line] : [];
- const selectedIssue = issuesForLine.find(i => i.key === issue.key)?.key;
-
- const issueLocationsByLine = includeIssueLocation ? locations : {};
return (
- <LineIssuesList
- displayWhyIsThisAnIssue={false}
- issueLocationsByLine={issueLocationsByLine}
- issuesForLine={issuesForLine}
- line={line}
- openIssuesByLine={openIssuesByLine}
- branchLike={this.props.branchLike}
- issuePopup={this.props.issuePopup}
- onIssueChange={this.props.onIssueChange}
- onIssueClick={noop}
- onIssuePopupToggle={this.props.onIssuePopupToggle}
- selectedIssue={selectedIssue}
- />
+ issuesForLine.length > 0 && (
+ <div className="issue-list">
+ {issuesForLine.map(issueToDisplay => {
+ if (issueToDisplay.key === issue.key && issueLocations && issueLocations.length) {
+ return (
+ <Issue
+ branchLike={branchLike}
+ displayWhyIsThisAnIssue={false}
+ issue={issueToDisplay}
+ key={issueToDisplay.key}
+ onChange={this.props.onIssueChange}
+ onClick={noop}
+ onPopupToggle={this.props.onIssuePopupToggle}
+ openPopup={
+ this.props.issuePopup && this.props.issuePopup.issue === issueToDisplay.key
+ ? this.props.issuePopup.name
+ : undefined
+ }
+ selected={issue.key === issueToDisplay.key}
+ />
+ );
+ }
+ return (
+ <SecondaryIssue
+ key={issueToDisplay.key}
+ issue={issueToDisplay}
+ onClick={this.props.onIssueSelect}
+ />
+ );
+ })}
+ </div>
+ )
);
};
renderSnippet({
index,
- issuesByLine,
lastSnippetOfLastGroup,
locationsByLine,
snippet
}: {
index: number;
- issuesByLine: IssuesByLine;
lastSnippetOfLastGroup: boolean;
locationsByLine: { [line: number]: LinearIssueLocation[] };
snippet: SourceLine[];
duplications={this.props.duplications}
duplicationsByLine={this.props.duplicationsByLine}
expandBlock={this.expandBlock}
- handleCloseIssues={this.handleCloseIssues}
- handleOpenIssues={this.handleOpenIssues}
handleSymbolClick={this.handleSymbolClick}
highlightedLocationMessage={this.props.highlightedLocationMessage}
highlightedSymbols={this.state.highlightedSymbols}
index={index}
issue={this.props.issue}
- issuesByLine={issuesByLine}
lastSnippetOfLastGroup={lastSnippetOfLastGroup}
loadDuplications={this.loadDuplications}
locations={this.props.locations}
locationsByLine={locationsByLine}
onLocationSelect={this.props.onLocationSelect}
- openIssuesByLine={this.state.openIssuesByLine}
renderDuplicationPopup={this.renderDuplicationPopup}
scroll={this.props.scroll}
snippet={snippet}
branchLike,
isLastOccurenceOfPrimaryComponent,
issue,
- issuesByLine,
issuePopup,
lastSnippetGroup,
snippetGroup
{this.renderSnippet({
snippet,
index: snippets[index].index,
- issuesByLine,
locationsByLine: includeIssueLocation ? locations : {},
lastSnippetOfLastGroup: lastSnippetGroup && index === snippets.length - 1
})}
issues: Issue[];
locations: FlowLocation[];
onIssueChange: (issue: Issue) => void;
+ onIssueSelect: (issueKey: string) => void;
onLoaded?: () => void;
onLocationSelect: (index: number) => void;
scroll?: (element: HTMLElement) => void;
loadDuplications={this.fetchDuplications}
locations={snippetGroup.locations || []}
onIssueChange={this.props.onIssueChange}
+ onIssueSelect={this.props.onIssueSelect}
onIssuePopupToggle={this.handleIssuePopupToggle}
onLocationSelect={this.props.onLocationSelect}
renderDuplicationPopup={this.renderDuplicationPopup}
loadDuplications={this.fetchDuplications}
locations={[]}
onIssueChange={this.props.onIssueChange}
+ onIssueSelect={this.props.onIssueSelect}
onIssuePopupToggle={this.handleIssuePopupToggle}
onLocationSelect={this.props.onLocationSelect}
renderDuplicationPopup={this.renderDuplicationPopup}
import { translate } from '../../../helpers/l10n';
import { scrollHorizontally } from '../../../helpers/scrolling';
import {
- Dict,
Duplication,
ExpandDirection,
FlowLocation,
Issue,
- IssuesByLine,
LinearIssueLocation,
SourceLine,
SourceViewerFile
} from '../../../types/types';
import './SnippetViewer.css';
-import { inSnippet, LINES_BELOW_ISSUE } from './utils';
+import { LINES_BELOW_ISSUE } from './utils';
interface Props {
component: SourceViewerFile;
duplications?: Duplication[];
duplicationsByLine?: { [line: number]: number[] };
expandBlock: (snippetIndex: number, direction: ExpandDirection) => Promise<void>;
- handleCloseIssues: (line: SourceLine) => void;
- handleOpenIssues: (line: SourceLine) => void;
handleSymbolClick: (symbols: string[]) => void;
highlightedLocationMessage: { index: number; text: string | undefined } | undefined;
highlightedSymbols: string[];
index: number;
issue: Pick<Issue, 'key' | 'textRange' | 'line'>;
- issuesByLine: IssuesByLine;
lastSnippetOfLastGroup: boolean;
loadDuplications?: (line: SourceLine) => void;
locations: FlowLocation[];
locationsByLine: { [line: number]: LinearIssueLocation[] };
onLocationSelect: (index: number) => void;
- openIssuesByLine: Dict<boolean>;
renderAdditionalChildInLine?: (line: SourceLine) => React.ReactNode | undefined;
renderDuplicationPopup: (index: number, line: number) => React.ReactNode;
scroll?: (element: HTMLElement, offset?: number) => void;
displayDuplications,
displaySCM,
index,
- issuesForLine,
issueLocations,
line,
snippet,
displayDuplications: boolean;
displaySCM?: boolean;
index: number;
- issuesForLine: Issue[];
issueLocations: LinearIssueLocation[];
line: SourceLine;
snippet: SourceLine[];
const lineDuplications =
(duplicationsCount && duplicationsByLine && duplicationsByLine[line.line]) || [];
- const isSinkLine = issuesForLine.some(i => i.key === this.props.issue.key);
const firstLineNumber = snippet && snippet.length ? snippet[0].line : 0;
const noop = () => {};
return (
<Line
- displayAllIssues={false}
displayCoverage={true}
displayDuplications={displayDuplications}
- displayIssues={!isSinkLine || issuesForLine.length > 1}
+ displayIssues={false}
displayLineNumberOptions={displayLineNumberOptions}
displayLocationMarkers={true}
displaySCM={displaySCM}
)}
highlightedSymbols={optimizeHighlightedSymbols(symbols, this.props.highlightedSymbols)}
issueLocations={issueLocations}
- issues={issuesForLine}
+ issues={[]}
key={line.line}
last={false}
line={line}
loadDuplications={this.props.loadDuplications || noop}
onIssueSelect={noop}
onIssueUnselect={noop}
- onIssuesClose={this.props.handleCloseIssues}
- onIssuesOpen={this.props.handleOpenIssues}
+ onIssuesClose={noop}
+ onIssuesOpen={noop}
onLocationSelect={this.props.onLocationSelect}
onSymbolClick={this.props.handleSymbolClick}
- openIssues={this.props.openIssuesByLine[line.line]}
+ openIssues={false}
previousLine={index > 0 ? snippet[index - 1] : undefined}
renderDuplicationPopup={this.props.renderDuplicationPopup}
scroll={this.doScroll}
component,
displaySCM,
issue,
- issuesByLine = {},
lastSnippetOfLastGroup,
locationsByLine,
- openIssuesByLine,
snippet
} = this.props;
const lastLine =
const bottomLine = snippet[snippet.length - 1].line;
const issueLine = issue.textRange ? issue.textRange.endLine : issue.line;
- const lowestVisibleIssue = Math.max(
- ...Object.keys(issuesByLine)
- .map(k => parseInt(k, 10))
- .filter(l => inSnippet(l, snippet) && (l === issueLine || openIssuesByLine[l]))
- );
- const verticalBuffer = lastSnippetOfLastGroup
- ? Math.max(0, LINES_BELOW_ISSUE - (bottomLine - lowestVisibleIssue))
- : 0;
+
+ const verticalBuffer =
+ lastSnippetOfLastGroup && issueLine
+ ? Math.max(0, LINES_BELOW_ISSUE - (bottomLine - issueLine))
+ : 0;
const displayDuplications =
Boolean(this.props.loadDuplications) && snippet.some(s => !!s.duplicated);
displayDuplications,
displaySCM,
index,
- issuesForLine: issuesByLine[line.line] || [],
issueLocations: locationsByLine[line.line] || [],
line,
snippet,
expect(getSources).toHaveBeenCalledWith({ branch: 'asdf', from: 8, key: 'project:a', to: 67 });
});
-it('should handle correctly open/close issue', () => {
- const wrapper = shallowRender();
- const sourceLine = mockSourceLine();
- expect(wrapper.state('openIssuesByLine')).toEqual({});
- wrapper.instance().handleOpenIssues(sourceLine);
- expect(wrapper.state('openIssuesByLine')).toEqual({ [sourceLine.line]: true });
- wrapper.instance().handleCloseIssues(sourceLine);
- expect(wrapper.state('openIssuesByLine')).toEqual({ [sourceLine.line]: false });
-});
-
it('should handle symbol highlighting', () => {
const wrapper = shallowRender();
expect(wrapper.state('highlightedSymbols')).toEqual([]);
);
});
-it('should render correctly line with issue', () => {
- const issue = mockIssue(false, {
- textRange: { endLine: 1, startLine: 1, endOffset: 1, startOffset: 0 }
- });
- const wrapper = shallowRender({
- issue,
- issuesByLine: { '1': [issue] }
- });
- wrapper.instance().setState({ openIssuesByLine: { '1': true } });
- const wrapperLine = shallow(wrapper.instance().renderIssuesList(mockSourceLine({ line: 1 })));
- expect(wrapperLine).toMatchSnapshot();
-});
-
describe('getNodes', () => {
const snippetGroup: SnippetGroup = {
component: mockSourceViewerFile(),
loadDuplications={jest.fn()}
locations={[]}
onIssueChange={jest.fn()}
+ onIssueSelect={jest.fn()}
onIssuePopupToggle={jest.fn()}
onLocationSelect={jest.fn()}
renderDuplicationPopup={jest.fn()}
loadDuplications={jest.fn()}
locations={[]}
onIssueChange={jest.fn()}
+ onIssueSelect={jest.fn()}
onIssuePopupToggle={jest.fn()}
onLocationSelect={jest.fn()}
renderDuplicationPopup={jest.fn()}
loadDuplications={jest.fn()}
locations={[]}
onIssueChange={jest.fn()}
+ onIssueSelect={jest.fn()}
onIssuePopupToggle={jest.fn()}
onLocationSelect={jest.fn()}
renderDuplicationPopup={jest.fn()}
locations={[mockFlowLocation()]}
onIssueChange={jest.fn()}
onLoaded={jest.fn()}
+ onIssueSelect={jest.fn()}
onLocationSelect={jest.fn()}
scroll={jest.fn()}
selectedFlowIndex={0}
wrapper.instance().renderLine({
displayDuplications: false,
index: 1,
- issuesForLine: [],
issueLocations: [],
line: sourceline,
snippet: [sourceline],
duplications={undefined}
duplicationsByLine={undefined}
expandBlock={jest.fn()}
- handleCloseIssues={jest.fn()}
- handleOpenIssues={jest.fn()}
handleSymbolClick={jest.fn()}
highlightedLocationMessage={{ index: 0, text: '' }}
highlightedSymbols={[]}
index={0}
issue={mockIssue()}
- issuesByLine={{}}
lastSnippetOfLastGroup={false}
loadDuplications={jest.fn()}
locations={[]}
locationsByLine={{}}
onLocationSelect={jest.fn()}
- openIssuesByLine={{}}
renderDuplicationPopup={jest.fn()}
scroll={jest.fn()}
snippet={[]}
duplications={undefined}
duplicationsByLine={undefined}
expandBlock={jest.fn()}
- handleCloseIssues={jest.fn()}
- handleOpenIssues={jest.fn()}
handleSymbolClick={jest.fn()}
highlightedLocationMessage={{ index: 0, text: '' }}
highlightedSymbols={[]}
index={0}
issue={mockIssue()}
- issuesByLine={{}}
lastSnippetOfLastGroup={false}
loadDuplications={jest.fn()}
locations={[]}
locationsByLine={{}}
onLocationSelect={jest.fn()}
- openIssuesByLine={{}}
renderDuplicationPopup={jest.fn()}
scroll={jest.fn()}
snippet={[mockSourceLine()]}
/>
</div>
`;
-
-exports[`should render correctly line with issue 1`] = `
-<div
- className="issue-list"
->
- <Issue
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": true,
- "name": "master",
- }
- }
- displayWhyIsThisAnIssue={false}
- issue={
- Object {
- "actions": Array [],
- "component": "main.js",
- "componentLongName": "main.js",
- "componentQualifier": "FIL",
- "componentUuid": "foo1234",
- "creationDate": "2017-03-01T09:36:01+0100",
- "flows": Array [],
- "fromHotspot": false,
- "key": "AVsae-CQS-9G3txfbFN2",
- "line": 25,
- "message": "Reduce the number of conditional operators (4) used in the expression",
- "project": "myproject",
- "projectKey": "foo",
- "projectName": "Foo",
- "rule": "javascript:S1067",
- "ruleName": "foo",
- "secondaryLocations": Array [],
- "severity": "MAJOR",
- "status": "OPEN",
- "textRange": Object {
- "endLine": 1,
- "endOffset": 1,
- "startLine": 1,
- "startOffset": 0,
- },
- "transitions": Array [],
- "type": "BUG",
- }
- }
- key="AVsae-CQS-9G3txfbFN2"
- onChange={[MockFunction]}
- onClick={[Function]}
- onPopupToggle={[MockFunction]}
- selected={true}
- />
-</div>
-`;
}
onIssueChange={[MockFunction]}
onIssuePopupToggle={[Function]}
+ onIssueSelect={[MockFunction]}
onLocationSelect={[MockFunction]}
renderDuplicationPopup={[Function]}
scroll={[MockFunction]}
locations={Array []}
onIssueChange={[MockFunction]}
onIssuePopupToggle={[Function]}
+ onIssueSelect={[MockFunction]}
onLocationSelect={[MockFunction]}
renderDuplicationPopup={[Function]}
scroll={[MockFunction]}
}
onIssueChange={[MockFunction]}
onIssuePopupToggle={[Function]}
+ onIssueSelect={[MockFunction]}
onLocationSelect={[MockFunction]}
renderDuplicationPopup={[Function]}
scroll={[MockFunction]}
>
<tbody>
<Line
- displayAllIssues={false}
displayCoverage={true}
displayDuplications={false}
- displayIssues={true}
+ displayIssues={false}
displayLocationMarkers={true}
duplications={Array []}
duplicationsCount={0}
loadDuplications={[MockFunction]}
onIssueSelect={[Function]}
onIssueUnselect={[Function]}
- onIssuesClose={[MockFunction]}
- onIssuesOpen={[MockFunction]}
+ onIssuesClose={[Function]}
+ onIssuesOpen={[Function]}
onLocationSelect={[MockFunction]}
onSymbolClick={[MockFunction]}
+ openIssues={false}
renderDuplicationPopup={[MockFunction]}
scroll={[Function]}
secondaryIssueLocations={Array []}
verticalBuffer={0}
/>
<Line
- displayAllIssues={false}
displayCoverage={true}
displayDuplications={false}
- displayIssues={true}
+ displayIssues={false}
displayLocationMarkers={true}
duplications={Array []}
duplicationsCount={0}
loadDuplications={[MockFunction]}
onIssueSelect={[Function]}
onIssueUnselect={[Function]}
- onIssuesClose={[MockFunction]}
- onIssuesOpen={[MockFunction]}
+ onIssuesClose={[Function]}
+ onIssuesOpen={[Function]}
onLocationSelect={[MockFunction]}
onSymbolClick={[MockFunction]}
+ openIssues={false}
previousLine={
Object {
"code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
verticalBuffer={0}
/>
<Line
- displayAllIssues={false}
displayCoverage={true}
displayDuplications={false}
- displayIssues={true}
+ displayIssues={false}
displayLocationMarkers={true}
duplications={Array []}
duplicationsCount={0}
loadDuplications={[MockFunction]}
onIssueSelect={[Function]}
onIssueUnselect={[Function]}
- onIssuesClose={[MockFunction]}
- onIssuesOpen={[MockFunction]}
+ onIssuesClose={[Function]}
+ onIssuesOpen={[Function]}
onLocationSelect={[MockFunction]}
onSymbolClick={[MockFunction]}
+ openIssues={false}
previousLine={
Object {
"code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
>
<tbody>
<Line
- displayAllIssues={false}
displayCoverage={true}
displayDuplications={false}
- displayIssues={true}
+ displayIssues={false}
displayLocationMarkers={true}
duplications={Array []}
duplicationsCount={0}
loadDuplications={[MockFunction]}
onIssueSelect={[Function]}
onIssueUnselect={[Function]}
- onIssuesClose={[MockFunction]}
- onIssuesOpen={[MockFunction]}
+ onIssuesClose={[Function]}
+ onIssuesOpen={[Function]}
onLocationSelect={[MockFunction]}
onSymbolClick={[MockFunction]}
+ openIssues={false}
renderDuplicationPopup={[MockFunction]}
scroll={[Function]}
secondaryIssueLocations={Array []}
verticalBuffer={0}
/>
<Line
- displayAllIssues={false}
displayCoverage={true}
displayDuplications={false}
- displayIssues={true}
+ displayIssues={false}
displayLocationMarkers={true}
duplications={Array []}
duplicationsCount={0}
loadDuplications={[MockFunction]}
onIssueSelect={[Function]}
onIssueUnselect={[Function]}
- onIssuesClose={[MockFunction]}
- onIssuesOpen={[MockFunction]}
+ onIssuesClose={[Function]}
+ onIssuesOpen={[Function]}
onLocationSelect={[MockFunction]}
onSymbolClick={[MockFunction]}
+ openIssues={false}
previousLine={
Object {
"code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
verticalBuffer={0}
/>
<Line
- displayAllIssues={false}
displayCoverage={true}
displayDuplications={false}
- displayIssues={true}
+ displayIssues={false}
displayLocationMarkers={true}
duplications={Array []}
duplicationsCount={0}
loadDuplications={[MockFunction]}
onIssueSelect={[Function]}
onIssueUnselect={[Function]}
- onIssuesClose={[MockFunction]}
- onIssuesOpen={[MockFunction]}
+ onIssuesClose={[Function]}
+ onIssuesOpen={[Function]}
onLocationSelect={[MockFunction]}
onSymbolClick={[MockFunction]}
+ openIssues={false}
previousLine={
Object {
"code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
verticalBuffer={0}
/>
<Line
- displayAllIssues={false}
displayCoverage={true}
displayDuplications={false}
- displayIssues={true}
+ displayIssues={false}
displayLocationMarkers={true}
duplications={Array []}
duplicationsCount={0}
loadDuplications={[MockFunction]}
onIssueSelect={[Function]}
onIssueUnselect={[Function]}
- onIssuesClose={[MockFunction]}
- onIssuesOpen={[MockFunction]}
+ onIssuesClose={[Function]}
+ onIssuesOpen={[Function]}
onLocationSelect={[MockFunction]}
onSymbolClick={[MockFunction]}
+ openIssues={false}
previousLine={
Object {
"code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
>
<tbody>
<Line
- displayAllIssues={false}
displayCoverage={true}
displayDuplications={false}
- displayIssues={true}
+ displayIssues={false}
displayLocationMarkers={true}
duplications={Array []}
duplicationsCount={0}
loadDuplications={[MockFunction]}
onIssueSelect={[Function]}
onIssueUnselect={[Function]}
- onIssuesClose={[MockFunction]}
- onIssuesOpen={[MockFunction]}
+ onIssuesClose={[Function]}
+ onIssuesOpen={[Function]}
onLocationSelect={[MockFunction]}
onSymbolClick={[MockFunction]}
+ openIssues={false}
renderDuplicationPopup={[MockFunction]}
scroll={[Function]}
secondaryIssueLocations={Array []}
verticalBuffer={0}
/>
<Line
- displayAllIssues={false}
displayCoverage={true}
displayDuplications={false}
- displayIssues={true}
+ displayIssues={false}
displayLocationMarkers={true}
duplications={Array []}
duplicationsCount={0}
loadDuplications={[MockFunction]}
onIssueSelect={[Function]}
onIssueUnselect={[Function]}
- onIssuesClose={[MockFunction]}
- onIssuesOpen={[MockFunction]}
+ onIssuesClose={[Function]}
+ onIssuesOpen={[Function]}
onLocationSelect={[MockFunction]}
onSymbolClick={[MockFunction]}
+ openIssues={false}
previousLine={
Object {
"code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
verticalBuffer={0}
/>
<Line
- displayAllIssues={false}
displayCoverage={true}
displayDuplications={false}
- displayIssues={true}
+ displayIssues={false}
displayLocationMarkers={true}
duplications={Array []}
duplicationsCount={0}
loadDuplications={[MockFunction]}
onIssueSelect={[Function]}
onIssueUnselect={[Function]}
- onIssuesClose={[MockFunction]}
- onIssuesOpen={[MockFunction]}
+ onIssuesClose={[Function]}
+ onIssuesOpen={[Function]}
onLocationSelect={[MockFunction]}
onSymbolClick={[MockFunction]}
+ openIssues={false}
previousLine={
Object {
"code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
verticalBuffer={0}
/>
<Line
- displayAllIssues={false}
displayCoverage={true}
displayDuplications={false}
- displayIssues={true}
+ displayIssues={false}
displayLocationMarkers={true}
duplications={Array []}
duplicationsCount={0}
loadDuplications={[MockFunction]}
onIssueSelect={[Function]}
onIssueUnselect={[Function]}
- onIssuesClose={[MockFunction]}
- onIssuesOpen={[MockFunction]}
+ onIssuesClose={[Function]}
+ onIssuesOpen={[Function]}
onLocationSelect={[MockFunction]}
onSymbolClick={[MockFunction]}
+ openIssues={false}
previousLine={
Object {
"code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
verticalBuffer={0}
/>
<Line
- displayAllIssues={false}
displayCoverage={true}
displayDuplications={false}
- displayIssues={true}
+ displayIssues={false}
displayLocationMarkers={true}
duplications={Array []}
duplicationsCount={0}
loadDuplications={[MockFunction]}
onIssueSelect={[Function]}
onIssueUnselect={[Function]}
- onIssuesClose={[MockFunction]}
- onIssuesOpen={[MockFunction]}
+ onIssuesClose={[Function]}
+ onIssuesOpen={[Function]}
onLocationSelect={[MockFunction]}
onSymbolClick={[MockFunction]}
+ openIssues={false}
previousLine={
Object {
"code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
verticalBuffer={0}
/>
<Line
- displayAllIssues={false}
displayCoverage={true}
displayDuplications={false}
- displayIssues={true}
+ displayIssues={false}
displayLocationMarkers={true}
duplications={Array []}
duplicationsCount={0}
loadDuplications={[MockFunction]}
onIssueSelect={[Function]}
onIssueUnselect={[Function]}
- onIssuesClose={[MockFunction]}
- onIssuesOpen={[MockFunction]}
+ onIssuesClose={[Function]}
+ onIssuesOpen={[Function]}
onLocationSelect={[MockFunction]}
onSymbolClick={[MockFunction]}
+ openIssues={false}
previousLine={
Object {
"code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
verticalBuffer={0}
/>
<Line
- displayAllIssues={false}
displayCoverage={true}
displayDuplications={false}
- displayIssues={true}
+ displayIssues={false}
displayLocationMarkers={true}
duplications={Array []}
duplicationsCount={0}
loadDuplications={[MockFunction]}
onIssueSelect={[Function]}
onIssueUnselect={[Function]}
- onIssuesClose={[MockFunction]}
- onIssuesOpen={[MockFunction]}
+ onIssuesClose={[Function]}
+ onIssuesOpen={[Function]}
onLocationSelect={[MockFunction]}
onSymbolClick={[MockFunction]}
+ openIssues={false}
previousLine={
Object {
"code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
>
<tbody>
<Line
- displayAllIssues={false}
displayCoverage={true}
displayDuplications={false}
- displayIssues={true}
+ displayIssues={false}
displayLocationMarkers={true}
displaySCM={false}
duplications={Array []}
loadDuplications={[MockFunction]}
onIssueSelect={[Function]}
onIssueUnselect={[Function]}
- onIssuesClose={[MockFunction]}
- onIssuesOpen={[MockFunction]}
+ onIssuesClose={[Function]}
+ onIssuesOpen={[Function]}
onLocationSelect={[MockFunction]}
onSymbolClick={[MockFunction]}
+ openIssues={false}
renderDuplicationPopup={[MockFunction]}
scroll={[Function]}
secondaryIssueLocations={Array []}
verticalBuffer={0}
/>
<Line
- displayAllIssues={false}
displayCoverage={true}
displayDuplications={false}
- displayIssues={true}
+ displayIssues={false}
displayLocationMarkers={true}
displaySCM={false}
duplications={Array []}
loadDuplications={[MockFunction]}
onIssueSelect={[Function]}
onIssueUnselect={[Function]}
- onIssuesClose={[MockFunction]}
- onIssuesOpen={[MockFunction]}
+ onIssuesClose={[Function]}
+ onIssuesOpen={[Function]}
onLocationSelect={[MockFunction]}
onSymbolClick={[MockFunction]}
+ openIssues={false}
previousLine={
Object {
"code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
verticalBuffer={0}
/>
<Line
- displayAllIssues={false}
displayCoverage={true}
displayDuplications={false}
- displayIssues={true}
+ displayIssues={false}
displayLocationMarkers={true}
displaySCM={false}
duplications={Array []}
loadDuplications={[MockFunction]}
onIssueSelect={[Function]}
onIssueUnselect={[Function]}
- onIssuesClose={[MockFunction]}
- onIssuesOpen={[MockFunction]}
+ onIssuesClose={[Function]}
+ onIssuesOpen={[Function]}
onLocationSelect={[MockFunction]}
onSymbolClick={[MockFunction]}
+ openIssues={false}
previousLine={
Object {
"code": "<span class=\\"k\\">import</span> java.util.<span class=\\"sym-9 sym\\">ArrayList</span>;",
expandBlock={(_i, direction) =>
animateExpansion(scrollableRef, props.onExpandBlock, direction)
}
- handleCloseIssues={noop}
- handleOpenIssues={noop}
handleSymbolClick={props.onSymbolClick}
highlightedLocationMessage={highlightedLocation}
highlightedSymbols={highlightedSymbols}
index={0}
issue={hotspot}
- issuesByLine={{}}
lastSnippetOfLastGroup={false}
locations={secondaryLocations}
locationsByLine={primaryLocations}
onLocationSelect={props.onLocationSelect}
- openIssuesByLine={{}}
renderAdditionalChildInLine={renderHotspotBoxInLine}
renderDuplicationPopup={noop}
snippet={sourceLines}
displayLineNumberOptions={false}
displaySCM={false}
expandBlock={[Function]}
- handleCloseIssues={[Function]}
- handleOpenIssues={[Function]}
handleSymbolClick={[MockFunction]}
highlightedSymbols={Array []}
index={0}
],
}
}
- issuesByLine={Object {}}
lastSnippetOfLastGroup={false}
locations={Array []}
locationsByLine={Object {}}
onLocationSelect={[MockFunction]}
- openIssuesByLine={Object {}}
renderAdditionalChildInLine={[Function]}
renderDuplicationPopup={[Function]}
scroll={[Function]}
--- /dev/null
+/*
+ * 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 * as React from 'react';
+import { colors } from '../../app/theme';
+import { Issue as TypeIssue } from '../../types/types';
+import IssueTypeIcon from '../icons/IssueTypeIcon';
+import './Issue.css';
+
+export interface SecondaryIssueProps {
+ issue: TypeIssue;
+ onClick: (issueKey: string) => void;
+}
+
+export default function SecondaryIssue(props: SecondaryIssueProps) {
+ const { issue } = props;
+ return (
+ <div
+ className="issue display-flex-row display-flex-center padded-right"
+ key={issue.key}
+ onClick={() => props.onClick(issue.key)}
+ role="region"
+ aria-label={issue.message}>
+ <IssueTypeIcon
+ className="big-spacer-right spacer-left"
+ fill={colors.baseFontColor}
+ query={issue.type}
+ />
+ {issue.message}
+ </div>
+ );
+}