*/
import getCoverageStatus from '../components/SourceViewer/helpers/getCoverageStatus';
import { throwGlobalError } from '../helpers/error';
-import { getJSON, post, postJSON, RequestData } from '../helpers/request';
+import {
+ get,
+ getJSON,
+ HttpStatus,
+ parseJSON,
+ post,
+ postJSON,
+ RequestData
+} from '../helpers/request';
import { IssueResponse, RawIssuesResponse } from '../types/issues';
import { Dict, FacetValue, IssueChangelog, SnippetsByComponent, SourceLine } from '../types/types';
}
export function getIssueFlowSnippets(issueKey: string): Promise<Dict<SnippetsByComponent>> {
- return getJSON('/api/sources/issue_snippets', { issueKey }).then(result => {
- Object.keys(result).forEach(k => {
- if (result[k].sources) {
- result[k].sources = result[k].sources.reduce(
- (lineMap: Dict<SourceLine>, line: SourceLine) => {
- line.coverageStatus = getCoverageStatus(line);
- lineMap[line.line] = line;
- return lineMap;
- },
- {}
- );
+ return get('/api/sources/issue_snippets', { issueKey })
+ .then(r => {
+ if (r.status === HttpStatus.NoContent) {
+ return {} as any;
}
+ return parseJSON(r);
+ })
+ .then(result => {
+ Object.keys(result).forEach(k => {
+ if (result[k].sources) {
+ result[k].sources = result[k].sources.reduce(
+ (lineMap: Dict<SourceLine>, line: SourceLine) => {
+ line.coverageStatus = getCoverageStatus(line);
+ lineMap[line.line] = line;
+ return lineMap;
+ },
+ {}
+ );
+ }
+ });
+ return result;
});
- return result;
- });
}
);
};
- fetchIssuesForComponent = (_component: string, _from: number, to: number) => {
- const { issues, openIssue, paging } = this.state;
-
- if (!openIssue || !paging) {
- return Promise.reject(undefined);
- }
-
- const isSameComponent = (issue: Issue) => issue.component === openIssue.component;
-
- const done = (pageIssues: Issue[], p: Paging) => {
- const lastIssue = pageIssues[pageIssues.length - 1];
- if (p.total <= p.pageIndex * p.pageSize) {
- return true;
- }
- if (lastIssue.component !== openIssue.component) {
- return true;
- }
- return lastIssue.textRange !== undefined && lastIssue.textRange.endLine > to;
- };
-
- if (done(issues, paging)) {
- return Promise.resolve(issues.filter(isSameComponent));
- }
-
- this.setState({ loading: true });
- return this.fetchIssuesUntil(paging.pageIndex + 1, done).then(
- response => {
- const nextIssues = [...issues, ...response.issues];
- if (this.mounted) {
- this.setState({
- issues: nextIssues,
- loading: false,
- paging: response.paging
- });
- }
- return nextIssues.filter(isSameComponent);
- },
- () => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- return [];
- }
- );
- };
-
fetchFacet = (facet: string) => {
return this.fetchIssues({ ps: 1, facets: facet }, false).then(
({ facets, ...other }) => {
<IssuesSourceViewer
branchLike={fillBranchLike(openIssue.branch, openIssue.pullRequest)}
issues={issues}
- loadIssues={this.fetchIssuesForComponent}
locationsNavigator={this.state.locationsNavigator}
onIssueChange={this.handleIssueChange}
- onIssueSelect={this.openIssue}
onLocationSelect={this.selectLocation}
openIssue={openIssue}
selectedFlowIndex={this.state.selectedFlowIndex}
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import SourceViewer from '../../../components/SourceViewer/SourceViewer';
import { scrollToElement } from '../../../helpers/scrolling';
import { BranchLike } from '../../../types/branch-like';
import { Issue } from '../../../types/types';
interface Props {
branchLike: BranchLike | undefined;
issues: Issue[];
- loadIssues: (component: string, from: number, to: number) => Promise<Issue[]>;
locationsNavigator: boolean;
onIssueChange: (issue: Issue) => void;
- onIssueSelect: (issueKey: string) => void;
onLocationSelect: (index: number) => void;
openIssue: Issue;
selectedFlowIndex: number | undefined;
? selectedLocation && { index: selectedLocationIndex, text: selectedLocation.msg }
: undefined;
- const startLines = locations.map(l => l.textRange.startLine);
- const showCrossComponentSourceViewer =
- startLines.length > 0 ? Math.max(...startLines) !== Math.min(...startLines) : false;
-
- if (showCrossComponentSourceViewer) {
- return (
- <div ref={node => (this.node = node)}>
- <CrossComponentSourceViewer
- branchLike={this.props.branchLike}
- highlightedLocationMessage={highlightedLocationMessage}
- issue={openIssue}
- issues={this.props.issues}
- locations={locations}
- onIssueChange={this.props.onIssueChange}
- onLoaded={this.handleLoaded}
- onLocationSelect={this.props.onLocationSelect}
- scroll={this.handleScroll}
- selectedFlowIndex={selectedFlowIndex}
- />
- </div>
- );
- } else {
- // if location is selected, show (and load) code around it
- // otherwise show code around the open issue
- const aroundLine = selectedLocation
- ? selectedLocation.textRange.startLine
- : openIssue.textRange && openIssue.textRange.endLine;
-
- const component = selectedLocation ? selectedLocation.component : openIssue.component;
- const allMessagesEmpty =
- locations !== undefined && locations.every(location => !location.msg);
-
- const highlightedLocations = locations.filter(location => location.component === component);
-
- // do not load issues when open another file for a location
- const loadIssues =
- component === openIssue.component ? this.props.loadIssues : () => Promise.resolve([]);
- const selectedIssue = component === openIssue.component ? openIssue.key : undefined;
-
- return (
- <div ref={node => (this.node = node)}>
- <SourceViewer
- aroundLine={aroundLine}
- branchLike={this.props.branchLike}
- component={component}
- displayAllIssues={true}
- displayIssueLocationsCount={true}
- displayIssueLocationsLink={false}
- displayLocationMarkers={!allMessagesEmpty}
- highlightedLocationMessage={highlightedLocationMessage}
- highlightedLocations={highlightedLocations}
- loadIssues={loadIssues}
- onIssueChange={this.props.onIssueChange}
- onIssueSelect={this.props.onIssueSelect}
- onLoaded={this.handleLoaded}
- onLocationSelect={this.props.onLocationSelect}
- scroll={this.handleScroll}
- selectedIssue={selectedIssue}
- slimHeader={true}
- />
- </div>
- );
- }
+ return (
+ <div ref={node => (this.node = node)}>
+ <CrossComponentSourceViewer
+ branchLike={this.props.branchLike}
+ highlightedLocationMessage={highlightedLocationMessage}
+ issue={openIssue}
+ issues={this.props.issues}
+ locations={locations}
+ onIssueChange={this.props.onIssueChange}
+ onLoaded={this.handleLoaded}
+ onLocationSelect={this.props.onLocationSelect}
+ scroll={this.handleScroll}
+ selectedFlowIndex={selectedFlowIndex}
+ />
+ </div>
+ );
}
}
expect(wrapper.find('#issues-bulk-change')).toMatchSnapshot();
});
-it('should fetch issues for component', async () => {
- (searchIssues as jest.Mock).mockImplementation(mockSearchIssuesResponse());
- const wrapper = shallowRender({
- location: mockLocation({
- query: { open: '0' }
- })
- });
- const instance = wrapper.instance();
- await waitAndUpdate(wrapper);
- expect(wrapper.state('issues')).toHaveLength(2);
-
- await instance.fetchIssuesForComponent('', 0, 30);
- expect(wrapper.state('issues')).toHaveLength(6);
-});
-
it('should display the right facets open', () => {
expect(
shallowRender({
<IssuesSourceViewer
branchLike={mockMainBranch()}
issues={[mockIssue()]}
- loadIssues={jest.fn()}
locationsNavigator={true}
onIssueChange={jest.fn()}
- onIssueSelect={jest.fn()}
onLocationSelect={jest.fn()}
openIssue={mockIssue()}
selectedFlowIndex={undefined}
exports[`should render SourceViewer correctly: all secondary locations on same line 1`] = `
<div>
- <SourceViewer
- aroundLine={26}
+ <CrossComponentSourceViewer
branchLike={
Object {
"analysisDate": "2018-01-01",
"name": "master",
}
}
- component="main.js"
- displayAllIssues={true}
- displayIssueLocationsCount={true}
- displayIssueLocationsLink={false}
- displayLocationMarkers={false}
- highlightedLocations={
+ issue={
+ Object {
+ "actions": Array [],
+ "component": "main.js",
+ "componentLongName": "main.js",
+ "componentQualifier": "FIL",
+ "componentUuid": "foo1234",
+ "creationDate": "2017-03-01T09:36:01+0100",
+ "flows": Array [
+ Array [
+ Object {
+ "component": "main.js",
+ "index": 0,
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ Object {
+ "component": "main.js",
+ "index": 1,
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ Object {
+ "component": "main.js",
+ "index": 2,
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ ],
+ ],
+ "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 [
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ ],
+ "severity": "MAJOR",
+ "status": "OPEN",
+ "textRange": Object {
+ "endLine": 26,
+ "endOffset": 15,
+ "startLine": 25,
+ "startOffset": 0,
+ },
+ "transitions": Array [],
+ "type": "BUG",
+ }
+ }
+ issues={
+ Array [
+ Object {
+ "actions": Array [],
+ "component": "main.js",
+ "componentLongName": "main.js",
+ "componentQualifier": "FIL",
+ "componentUuid": "foo1234",
+ "creationDate": "2017-03-01T09:36:01+0100",
+ "flows": Array [
+ Array [
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ ],
+ Array [
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ ],
+ ],
+ "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 [
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ ],
+ "severity": "MAJOR",
+ "status": "OPEN",
+ "textRange": Object {
+ "endLine": 26,
+ "endOffset": 15,
+ "startLine": 25,
+ "startOffset": 0,
+ },
+ "transitions": Array [],
+ "type": "BUG",
+ },
+ ]
+ }
+ locations={
Array [
Object {
"component": "main.js",
},
]
}
- loadIssues={[MockFunction]}
onIssueChange={[MockFunction]}
- onIssueSelect={[MockFunction]}
onLoaded={[Function]}
onLocationSelect={[MockFunction]}
scroll={[Function]}
- selectedIssue="AVsae-CQS-9G3txfbFN2"
- slimHeader={true}
/>
</div>
`;
exports[`should render SourceViewer correctly: default 1`] = `
<div>
- <SourceViewer
- aroundLine={26}
+ <CrossComponentSourceViewer
branchLike={
Object {
"analysisDate": "2018-01-01",
"name": "master",
}
}
- component="main.js"
- displayAllIssues={true}
- displayIssueLocationsCount={true}
- displayIssueLocationsLink={false}
- displayLocationMarkers={false}
- highlightedLocations={Array []}
- loadIssues={[MockFunction]}
+ 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": 26,
+ "endOffset": 15,
+ "startLine": 25,
+ "startOffset": 0,
+ },
+ "transitions": Array [],
+ "type": "BUG",
+ }
+ }
+ issues={
+ Array [
+ 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": 26,
+ "endOffset": 15,
+ "startLine": 25,
+ "startOffset": 0,
+ },
+ "transitions": Array [],
+ "type": "BUG",
+ },
+ ]
+ }
+ locations={Array []}
onIssueChange={[MockFunction]}
- onIssueSelect={[MockFunction]}
onLoaded={[Function]}
onLocationSelect={[MockFunction]}
scroll={[Function]}
- selectedIssue="AVsae-CQS-9G3txfbFN2"
- slimHeader={true}
/>
</div>
`;
exports[`should render SourceViewer correctly: single secondary location 1`] = `
<div>
- <SourceViewer
- aroundLine={26}
+ <CrossComponentSourceViewer
branchLike={
Object {
"analysisDate": "2018-01-01",
"name": "master",
}
}
- component="main.js"
- displayAllIssues={true}
- displayIssueLocationsCount={true}
- displayIssueLocationsLink={false}
- displayLocationMarkers={false}
- highlightedLocations={
+ issue={
+ Object {
+ "actions": Array [],
+ "component": "main.js",
+ "componentLongName": "main.js",
+ "componentQualifier": "FIL",
+ "componentUuid": "foo1234",
+ "creationDate": "2017-03-01T09:36:01+0100",
+ "flows": Array [
+ Array [
+ Object {
+ "component": "main.js",
+ "index": 0,
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ ],
+ ],
+ "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 [
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ ],
+ "severity": "MAJOR",
+ "status": "OPEN",
+ "textRange": Object {
+ "endLine": 26,
+ "endOffset": 15,
+ "startLine": 25,
+ "startOffset": 0,
+ },
+ "transitions": Array [],
+ "type": "BUG",
+ }
+ }
+ issues={
+ Array [
+ Object {
+ "actions": Array [],
+ "component": "main.js",
+ "componentLongName": "main.js",
+ "componentQualifier": "FIL",
+ "componentUuid": "foo1234",
+ "creationDate": "2017-03-01T09:36:01+0100",
+ "flows": Array [
+ Array [
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ ],
+ Array [
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ ],
+ ],
+ "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 [
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ ],
+ "severity": "MAJOR",
+ "status": "OPEN",
+ "textRange": Object {
+ "endLine": 26,
+ "endOffset": 15,
+ "startLine": 25,
+ "startOffset": 0,
+ },
+ "transitions": Array [],
+ "type": "BUG",
+ },
+ ]
+ }
+ locations={
Array [
Object {
"component": "main.js",
},
]
}
- loadIssues={[MockFunction]}
onIssueChange={[MockFunction]}
- onIssueSelect={[MockFunction]}
onLoaded={[Function]}
onLocationSelect={[MockFunction]}
scroll={[Function]}
- selectedIssue="AVsae-CQS-9G3txfbFN2"
- slimHeader={true}
/>
</div>
`;
const issueLocationsByLine = includeIssueLocation ? locations : {};
return (
<LineIssuesList
+ displayWhyIsThisAnIssue={false}
issueLocationsByLine={issueLocationsByLine}
issuesForLine={issuesForLine}
line={line}
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { findLastIndex } from 'lodash';
+import { findLastIndex, keyBy } from 'lodash';
import * as React from 'react';
-import { getDuplications } from '../../../api/components';
+import { getComponentForSourceViewer, getDuplications, getSources } from '../../../api/components';
import { getIssueFlowSnippets } from '../../../api/issues';
import DuplicationPopup from '../../../components/SourceViewer/components/DuplicationPopup';
import {
import { throwGlobalError } from '../../../helpers/error';
import { translate } from '../../../helpers/l10n';
import { BranchLike } from '../../../types/branch-like';
+import { isFile } from '../../../types/component';
import {
Dict,
DuplicatedFile,
SourceViewerFile
} from '../../../types/types';
import ComponentSourceSnippetGroupViewer from './ComponentSourceSnippetGroupViewer';
-import { groupLocationsByComponent } from './utils';
+import { getPrimaryLocation, groupLocationsByComponent } from './utils';
interface Props {
branchLike: BranchLike | undefined;
componentDidMount() {
this.mounted = true;
- this.fetchIssueFlowSnippets(this.props.issue.key);
+ this.fetchIssueFlowSnippets();
}
componentDidUpdate(prevProps: Props) {
if (prevProps.issue.key !== this.props.issue.key) {
- this.fetchIssueFlowSnippets(this.props.issue.key);
+ this.fetchIssueFlowSnippets();
}
}
);
};
- fetchIssueFlowSnippets(issueKey: string) {
+ async fetchIssueFlowSnippets() {
+ const { issue, branchLike } = this.props;
this.setState({ loading: true });
- getIssueFlowSnippets(issueKey).then(
- components => {
- if (this.mounted) {
- this.setState({
- components,
- issuePopup: undefined,
- loading: false
- });
- if (this.props.onLoaded) {
- this.props.onLoaded();
- }
- }
- },
- (response: Response) => {
- if (response.status !== 403) {
- throwGlobalError(response);
+
+ try {
+ const components = await getIssueFlowSnippets(issue.key);
+ if (components[issue.component] === undefined) {
+ const issueComponent = await getComponentForSourceViewer({
+ component: issue.component,
+ ...getBranchLikeQuery(branchLike)
+ });
+ components[issue.component] = { component: issueComponent, sources: [] };
+ if (isFile(issueComponent.q)) {
+ const sources = await getSources({
+ key: issueComponent.key,
+ ...getBranchLikeQuery(branchLike),
+ from: 1,
+ to: 10
+ }).then(lines => keyBy(lines, 'line'));
+ components[issue.component].sources = sources;
}
- if (this.mounted) {
- this.setState({ loading: false, notAccessible: response.status === 403 });
+ }
+ if (this.mounted) {
+ this.setState({
+ components,
+ issuePopup: undefined,
+ loading: false
+ });
+ if (this.props.onLoaded) {
+ this.props.onLoaded();
}
}
- );
+ } catch (response) {
+ const rsp = response as Response;
+ if (rsp.status !== 403) {
+ throwGlobalError(response);
+ }
+ if (this.mounted) {
+ this.setState({ loading: false, notAccessible: rsp.status === 403 });
+ }
+ }
}
handleIssuePopupToggle = (issue: string, popupName: string, open?: boolean) => {
({ component }) => component.key === issue.component
);
+ if (components[issue.component] === undefined) {
+ return null;
+ }
+
return (
<div>
{locationsByComponent.map((snippetGroup, i) => {
</SourceViewerContext.Provider>
);
})}
+
+ {locationsByComponent.length === 0 && (
+ <ComponentSourceSnippetGroupViewer
+ branchLike={this.props.branchLike}
+ duplications={duplications}
+ duplicationsByLine={duplicationsByLine}
+ highlightedLocationMessage={this.props.highlightedLocationMessage}
+ issue={issue}
+ issuePopup={this.state.issuePopup}
+ issuesByLine={issuesByComponent[issue.component] || {}}
+ isLastOccurenceOfPrimaryComponent={true}
+ lastSnippetGroup={true}
+ loadDuplications={this.fetchDuplications}
+ locations={[]}
+ onIssueChange={this.props.onIssueChange}
+ onIssuePopupToggle={this.handleIssuePopupToggle}
+ onLocationSelect={this.props.onLocationSelect}
+ renderDuplicationPopup={this.renderDuplicationPopup}
+ scroll={this.props.scroll}
+ snippetGroup={{
+ locations: [getPrimaryLocation(issue)],
+ ...components[issue.component]
+ }}
+ />
+ )}
</div>
);
}
});
jest.mock('../../../../api/components', () => ({
- getDuplications: jest.fn().mockResolvedValue({})
+ getDuplications: jest.fn().mockResolvedValue({}),
+ getComponentForSourceViewer: jest.fn().mockResolvedValue({})
}));
beforeEach(() => {
});
it('should render correctly', async () => {
- const wrapper = shallowRender();
+ let wrapper = shallowRender();
expect(wrapper).toMatchSnapshot();
await waitAndUpdate(wrapper);
expect(wrapper).toMatchSnapshot();
+
+ wrapper = shallowRender({ issue: mockIssue(true, { component: 'test.js', key: 'unknown' }) });
+ await waitAndUpdate(wrapper);
+
+ expect(wrapper).toMatchSnapshot('no component found');
});
it('Should fetch data', async () => {
const wrapper = shallowRender();
- wrapper.instance().fetchIssueFlowSnippets('124');
+ wrapper.instance().fetchIssueFlowSnippets();
await waitAndUpdate(wrapper);
expect(getIssueFlowSnippets).toHaveBeenCalledWith('1');
- expect(wrapper.state('components')).toEqual({ 'main.js': mockSnippetsByComponent() });
+ expect(wrapper.state('components')).toEqual(
+ expect.objectContaining({ 'main.js': mockSnippetsByComponent() })
+ );
(getIssueFlowSnippets as jest.Mock).mockClear();
wrapper.setProps({ issue: mockIssue(true, { key: 'foo' }) });
"name": "master",
}
}
+ displayWhyIsThisAnIssue={false}
issue={
Object {
"actions": Array [],
</ContextProvider>
</div>
`;
+
+exports[`should render correctly: no component found 1`] = `
+<div>
+ <ContextProvider
+ key="unknown-0-0"
+ value={
+ Object {
+ "branchLike": undefined,
+ "file": Object {},
+ }
+ }
+ >
+ <ComponentSourceSnippetGroupViewer
+ duplicationsByLine={Object {}}
+ isLastOccurenceOfPrimaryComponent={false}
+ issue={
+ Object {
+ "actions": Array [],
+ "component": "test.js",
+ "componentLongName": "main.js",
+ "componentQualifier": "FIL",
+ "componentUuid": "foo1234",
+ "creationDate": "2017-03-01T09:36:01+0100",
+ "flows": Array [
+ Array [
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ ],
+ Array [
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ ],
+ ],
+ "fromHotspot": false,
+ "key": "unknown",
+ "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 [
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ ],
+ "severity": "MAJOR",
+ "status": "OPEN",
+ "textRange": Object {
+ "endLine": 26,
+ "endOffset": 15,
+ "startLine": 25,
+ "startOffset": 0,
+ },
+ "transitions": Array [],
+ "type": "BUG",
+ }
+ }
+ issuesByLine={Object {}}
+ lastSnippetGroup={false}
+ loadDuplications={[Function]}
+ locations={Array []}
+ onIssueChange={[MockFunction]}
+ onIssuePopupToggle={[Function]}
+ onLocationSelect={[MockFunction]}
+ renderDuplicationPopup={[Function]}
+ scroll={[MockFunction]}
+ snippetGroup={
+ Object {
+ "component": Object {},
+ "locations": Array [],
+ "sources": Array [],
+ }
+ }
+ />
+ </ContextProvider>
+ <ContextProvider
+ key="unknown-0-1"
+ value={
+ Object {
+ "branchLike": undefined,
+ "file": Object {
+ "key": "main.js",
+ "measures": Object {
+ "coverage": "85.2",
+ "duplicationDensity": "1.0",
+ "issues": "12",
+ "lines": "56",
+ },
+ "path": "main.js",
+ "project": "my-project",
+ "projectName": "MyProject",
+ "q": "FIL",
+ "uuid": "foo-bar",
+ },
+ }
+ }
+ >
+ <ComponentSourceSnippetGroupViewer
+ duplicationsByLine={Object {}}
+ isLastOccurenceOfPrimaryComponent={false}
+ issue={
+ Object {
+ "actions": Array [],
+ "component": "test.js",
+ "componentLongName": "main.js",
+ "componentQualifier": "FIL",
+ "componentUuid": "foo1234",
+ "creationDate": "2017-03-01T09:36:01+0100",
+ "flows": Array [
+ Array [
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ ],
+ Array [
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ ],
+ ],
+ "fromHotspot": false,
+ "key": "unknown",
+ "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 [
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ Object {
+ "component": "main.js",
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ ],
+ "severity": "MAJOR",
+ "status": "OPEN",
+ "textRange": Object {
+ "endLine": 26,
+ "endOffset": 15,
+ "startLine": 25,
+ "startOffset": 0,
+ },
+ "transitions": Array [],
+ "type": "BUG",
+ }
+ }
+ issuesByLine={Object {}}
+ lastSnippetGroup={true}
+ loadDuplications={[Function]}
+ locations={
+ Array [
+ Object {
+ "component": "main.js",
+ "index": 0,
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ ]
+ }
+ onIssueChange={[MockFunction]}
+ onIssuePopupToggle={[Function]}
+ onLocationSelect={[MockFunction]}
+ renderDuplicationPopup={[Function]}
+ scroll={[MockFunction]}
+ snippetGroup={
+ Object {
+ "component": Object {
+ "key": "main.js",
+ "measures": Object {
+ "coverage": "85.2",
+ "duplicationDensity": "1.0",
+ "issues": "12",
+ "lines": "56",
+ },
+ "path": "main.js",
+ "project": "my-project",
+ "projectName": "MyProject",
+ "q": "FIL",
+ "uuid": "foo-bar",
+ },
+ "locations": Array [
+ Object {
+ "component": "main.js",
+ "index": 0,
+ "textRange": Object {
+ "endLine": 2,
+ "endOffset": 2,
+ "startLine": 1,
+ "startOffset": 1,
+ },
+ },
+ ],
+ "sources": Object {
+ "16": 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": 16,
+ "scmAuthor": "simon.brandhof@sonarsource.com",
+ "scmDate": "2018-12-11T10:48:39+0100",
+ "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0",
+ },
+ },
+ }
+ }
+ />
+ </ContextProvider>
+</div>
+`;
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { ComponentQualifier } from '../../../types/component';
import {
ExpandDirection,
FlowLocation,
path: '',
project: '',
projectName: '',
- q: 'FIL',
+ q: ComponentQualifier.File,
uuid: ''
},
sources: []
scrollToUncoveredLine={scrollToUncoveredLine}
secondaryIssueLocations={secondaryIssueLocations}>
<LineIssuesList
+ displayWhyIsThisAnIssue={true}
displayAllIssues={displayAllIssues}
issueLocationsByLine={issueLocationsByLine}
issuesForLine={issuesForLine}
import * as React from 'react';
import { mockMainBranch } from '../../../helpers/mocks/branch-like';
import { mockSourceViewerFile } from '../../../helpers/testMocks';
+import { ComponentQualifier } from '../../../types/component';
import { MetricKey } from '../../../types/metrics';
import { Measure } from '../../../types/types';
import SourceViewerHeader from '../SourceViewerHeader';
expect(
shallowRender({
showMeasures: true,
- sourceViewerFile: mockSourceViewerFile({ q: 'UTS', measures: { tests: '12' } })
+ sourceViewerFile: mockSourceViewerFile({
+ q: ComponentQualifier.TestFile,
+ measures: { tests: '12' }
+ })
})
).toMatchSnapshot();
});
export interface LineIssuesListProps {
branchLike: BranchLike | undefined;
displayAllIssues?: boolean;
+ displayWhyIsThisAnIssue: boolean;
displayIssueLocationsCount?: boolean;
displayIssueLocationsLink?: boolean;
issuesForLine: TypeIssue[];
export default function LineIssuesList(props: LineIssuesListProps) {
const {
line,
+ displayWhyIsThisAnIssue,
displayAllIssues,
openIssuesByLine,
selectedIssue,
{displayedIssue.map(issue => (
<Issue
branchLike={props.branchLike}
+ displayWhyIsThisAnIssue={displayWhyIsThisAnIssue}
displayLocationsCount={props.displayIssueLocationsCount}
displayLocationsLink={props.displayIssueLocationsLink}
issue={issue}
import { mockIssue, mockSourceLine } from '../../../../helpers/testMocks';
import LineIssuesList, { LineIssuesListProps } from '../LineIssuesList';
-it('shoule render issues', () => {
+it('should render issues', () => {
const wrapper = shallowRender({
selectedIssue: 'issue',
issueLocationsByLine: { '1': [{ from: 1, to: 1, line: 1 }] },
return shallow(
<LineIssuesList
selectedIssue=""
+ displayWhyIsThisAnIssue={true}
onIssueChange={jest.fn()}
onIssueClick={jest.fn()}
onIssuePopupToggle={jest.fn()}
import * as React from 'react';
import { mockBranch } from '../../../../helpers/mocks/branch-like';
import { click, waitAndUpdate } from '../../../../helpers/testUtils';
+import { ComponentQualifier } from '../../../../types/component';
import { MetricKey } from '../../../../types/metrics';
import { SourceViewerFile } from '../../../../types/types';
import MeasuresOverlay from '../MeasuresOverlay';
path: 'src/file.js',
project: 'project-key',
projectName: 'Project Name',
- q: 'FIL',
+ q: ComponentQualifier.File,
subProject: 'sub-project-key',
subProjectName: 'Sub-Project Name',
uuid: 'abcd123'
});
it('should render test file', async () => {
- const wrapper = shallowRender({ sourceViewerFile: { ...sourceViewerFile, q: 'UTS' } });
+ const wrapper = shallowRender({
+ sourceViewerFile: { ...sourceViewerFile, q: ComponentQualifier.TestFile }
+ });
await waitAndUpdate(wrapper);
expect(wrapper).toMatchSnapshot();
});
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`shoule render issues 1`] = `
+exports[`should render issues 1`] = `
<div
className="issue-list"
>
"name": "branch-6.7",
}
}
+ displayWhyIsThisAnIssue={true}
issue={
Object {
"actions": Array [],
interface Props {
branchLike?: BranchLike;
checked?: boolean;
+ displayWhyIsThisAnIssue?: boolean;
displayLocationsCount?: boolean;
displayLocationsLink?: boolean;
issue: TypeIssue;
branchLike={this.props.branchLike}
checked={this.props.checked}
currentPopup={this.props.openPopup}
+ displayWhyIsThisAnIssue={this.props.displayWhyIsThisAnIssue}
displayLocationsCount={this.props.displayLocationsCount}
displayLocationsLink={this.props.displayLocationsLink}
issue={this.props.issue}
branchLike?: BranchLike;
checked?: boolean;
currentPopup?: string;
+ displayWhyIsThisAnIssue?: boolean;
displayLocationsCount?: boolean;
displayLocationsLink?: boolean;
issue: Issue;
};
render() {
- const { issue } = this.props;
+ const {
+ issue,
+ branchLike,
+ checked,
+ currentPopup,
+ displayWhyIsThisAnIssue,
+ displayLocationsLink,
+ displayLocationsCount
+ } = this.props;
const hasCheckbox = this.props.onCheck != null;
role="region"
aria-label={issue.message}>
<IssueTitleBar
- branchLike={this.props.branchLike}
- currentPopup={this.props.currentPopup}
- displayLocationsCount={this.props.displayLocationsCount}
- displayLocationsLink={this.props.displayLocationsLink}
+ branchLike={branchLike}
+ currentPopup={currentPopup}
+ displayLocationsCount={displayLocationsCount}
+ displayLocationsLink={displayLocationsLink}
+ displayWhyIsThisAnIssue={displayWhyIsThisAnIssue}
issue={issue}
onFilter={this.props.onFilter}
togglePopup={this.props.togglePopup}
/>
<IssueActionsBar
- currentPopup={this.props.currentPopup}
+ currentPopup={currentPopup}
issue={issue}
onAssign={this.props.onAssign}
onChange={this.props.onChange}
)}
{hasCheckbox && (
<Checkbox
- checked={this.props.checked || false}
+ checked={checked || false}
className="issue-checkbox-container"
onCheck={this.handleCheck}
title={translate('issues.action_select')}
import { RuleStatus } from '../../../types/rules';
import DocumentationTooltip from '../../common/DocumentationTooltip';
import SonarLintIcon from '../../icons/SonarLintIcon';
-import { WorkspaceContextShape } from '../../workspace/context';
+import { WorkspaceContext } from '../../workspace/context';
export interface IssueMessageProps {
engine?: string;
- engineName?: string;
quickFixAvailable?: boolean;
+ displayWhyIsThisAnIssue?: boolean;
manualVulnerability: boolean;
message: string;
- onOpenRule: WorkspaceContextShape['openRule'];
ruleKey: string;
ruleStatus?: RuleStatus;
}
export default function IssueMessage(props: IssueMessageProps) {
const {
engine,
- engineName,
quickFixAvailable,
manualVulnerability,
message,
ruleKey,
- ruleStatus
+ ruleStatus,
+ displayWhyIsThisAnIssue
} = props;
- const ruleEngine = engineName ? engineName : engine;
+
+ const { externalRulesRepoNames, openRule } = React.useContext(WorkspaceContext);
+ const ruleEngine = (engine && externalRulesRepoNames && externalRulesRepoNames[engine]) || engine;
return (
<>
</Tooltip>
)}
</div>
- <ButtonLink
- aria-label={translate('issue.why_this_issue.long')}
- className="issue-see-rule spacer-right text-baseline"
- onClick={() =>
- props.onOpenRule({
- key: ruleKey
- })
- }>
- {translate('issue.why_this_issue')}
- </ButtonLink>
+ {displayWhyIsThisAnIssue && (
+ <ButtonLink
+ aria-label={translate('issue.why_this_issue.long')}
+ className="issue-see-rule spacer-right text-baseline"
+ onClick={() =>
+ openRule({
+ key: ruleKey
+ })
+ }>
+ {translate('issue.why_this_issue')}
+ </ButtonLink>
+ )}
</>
);
}
import { RuleStatus } from '../../../types/rules';
import { Issue } from '../../../types/types';
import LocationIndex from '../../common/LocationIndex';
-import { WorkspaceContext } from '../../workspace/context';
import IssueChangelog from './IssueChangelog';
import IssueMessage from './IssueMessage';
import SimilarIssuesFilter from './SimilarIssuesFilter';
export interface IssueTitleBarProps {
branchLike?: BranchLike;
currentPopup?: string;
+ displayWhyIsThisAnIssue?: boolean;
displayLocationsCount?: boolean;
displayLocationsLink?: boolean;
issue: Issue;
}
export default function IssueTitleBar(props: IssueTitleBarProps) {
- const { issue } = props;
+ const { issue, displayWhyIsThisAnIssue } = props;
const hasSimilarIssuesFilter = props.onFilter != null;
const locationsCount =
return (
<div className="issue-row">
- <WorkspaceContext.Consumer>
- {({ externalRulesRepoNames, openRule }) => (
- <IssueMessage
- engine={issue.externalRuleEngine}
- engineName={
- issue.externalRuleEngine &&
- externalRulesRepoNames &&
- externalRulesRepoNames[issue.externalRuleEngine]
- }
- quickFixAvailable={issue.quickFixAvailable}
- manualVulnerability={issue.fromHotspot && issue.type === 'VULNERABILITY'}
- message={issue.message}
- onOpenRule={openRule}
- ruleKey={issue.rule}
- ruleStatus={issue.ruleStatus as RuleStatus | undefined}
- />
- )}
- </WorkspaceContext.Consumer>
-
+ <IssueMessage
+ engine={issue.externalRuleEngine}
+ quickFixAvailable={issue.quickFixAvailable}
+ displayWhyIsThisAnIssue={displayWhyIsThisAnIssue}
+ manualVulnerability={issue.fromHotspot && issue.type === 'VULNERABILITY'}
+ message={issue.message}
+ ruleKey={issue.rule}
+ ruleStatus={issue.ruleStatus as RuleStatus | undefined}
+ />
<div className="issue-row-meta">
<div className="issue-meta-list">
<div className="issue-meta">
*/
import { shallow } from 'enzyme';
import * as React from 'react';
-import { ButtonLink } from '../../../../components/controls/buttons';
-import { click } from '../../../../helpers/testUtils';
import { RuleStatus } from '../../../../types/rules';
+import { ButtonLink } from '../../../controls/buttons';
import IssueMessage, { IssueMessageProps } from '../IssueMessage';
+jest.mock('react', () => {
+ return {
+ ...jest.requireActual('react'),
+ useContext: jest
+ .fn()
+ .mockImplementation(() => ({ externalRulesRepoNames: {}, openRule: jest.fn() }))
+ };
+});
+
it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot('default');
expect(shallowRender({ engine: 'js' })).toMatchSnapshot('with engine info');
expect(shallowRender({ quickFixAvailable: true })).toMatchSnapshot('with quick fix');
- expect(shallowRender({ engineName: 'JS' })).toMatchSnapshot('with engine name');
expect(shallowRender({ manualVulnerability: true })).toMatchSnapshot('is manual vulnerability');
expect(shallowRender({ ruleStatus: RuleStatus.Deprecated })).toMatchSnapshot(
'is deprecated rule'
);
expect(shallowRender({ ruleStatus: RuleStatus.Removed })).toMatchSnapshot('is removed rule');
+ expect(shallowRender({ displayWhyIsThisAnIssue: false })).toMatchSnapshot(
+ 'hide why is it an issue'
+ );
});
-it('should handle click correctly', () => {
- const onOpenRule = jest.fn();
- const wrapper = shallowRender({ onOpenRule });
- click(wrapper.find(ButtonLink));
- expect(onOpenRule).toBeCalledWith({
- key: 'javascript:S1067'
- });
+it('should open why is this an issue workspace', () => {
+ const openRule = jest.fn();
+ (React.useContext as jest.Mock).mockImplementationOnce(() => ({
+ externalRulesRepoNames: {},
+ openRule
+ }));
+ const wrapper = shallowRender();
+ wrapper.find(ButtonLink).simulate('click');
+
+ expect(openRule).toBeCalled();
});
function shallowRender(props: Partial<IssueMessageProps> = {}) {
<IssueMessage
manualVulnerability={false}
message="Reduce the number of conditional operators (4) used in the expression"
- onOpenRule={jest.fn()}
+ displayWhyIsThisAnIssue={true}
ruleKey="javascript:S1067"
{...props}
/>
import * as React from 'react';
import { mockBranch } from '../../../../helpers/mocks/branch-like';
import { mockIssue } from '../../../../helpers/testMocks';
-import { WorkspaceContext } from '../../../workspace/context';
import IssueTitleBar, { IssueTitleBarProps } from '../IssueTitleBar';
it('should render correctly', () => {
issue: mockIssue(true)
})
).toMatchSnapshot('with multi locations and link');
- expect(
- shallowRender()
- .find(WorkspaceContext.Consumer)
- .dive()
- ).toMatchSnapshot('issue message');
});
function shallowRender(props: Partial<IssueTitleBarProps> = {}) {
</Fragment>
`;
+exports[`should render correctly: hide why is it an issue 1`] = `
+<Fragment>
+ <div
+ className="display-inline-flex-center issue-message break-word"
+ >
+ <span
+ className="spacer-right"
+ >
+ Reduce the number of conditional operators (4) used in the expression
+ </span>
+ </div>
+</Fragment>
+`;
+
exports[`should render correctly: is deprecated rule 1`] = `
<Fragment>
<div
</Fragment>
`;
-exports[`should render correctly: with engine name 1`] = `
-<Fragment>
- <div
- className="display-inline-flex-center issue-message break-word"
- >
- <span
- className="spacer-right"
- >
- Reduce the number of conditional operators (4) used in the expression
- </span>
- <Tooltip
- overlay="issue.from_external_rule_engine.JS"
- >
- <div
- className="badge spacer-right text-baseline"
- >
- JS
- </div>
- </Tooltip>
- </div>
- <ButtonLink
- aria-label="issue.why_this_issue.long"
- className="issue-see-rule spacer-right text-baseline"
- onClick={[Function]}
- >
- issue.why_this_issue
- </ButtonLink>
-</Fragment>
-`;
-
exports[`should render correctly: with quick fix 1`] = `
<Fragment>
<div
<div
className="issue-row"
>
- <ContextConsumer>
- <Component />
- </ContextConsumer>
+ <IssueMessage
+ engine="foo"
+ manualVulnerability={false}
+ message="Reduce the number of conditional operators (4) used in the expression"
+ ruleKey="javascript:S1067"
+ />
<div
className="issue-row-meta"
>
</div>
`;
-exports[`should render correctly: issue message 1`] = `
-<IssueMessage
- engine="foo"
- manualVulnerability={false}
- message="Reduce the number of conditional operators (4) used in the expression"
- onOpenRule={[Function]}
- ruleKey="javascript:S1067"
-/>
-`;
-
exports[`should render correctly: with filter 1`] = `
<div
className="issue-row"
>
- <ContextConsumer>
- <Component />
- </ContextConsumer>
+ <IssueMessage
+ engine="foo"
+ manualVulnerability={false}
+ message="Reduce the number of conditional operators (4) used in the expression"
+ ruleKey="javascript:S1067"
+ />
<div
className="issue-row-meta"
>
<div
className="issue-row"
>
- <ContextConsumer>
- <Component />
- </ContextConsumer>
+ <IssueMessage
+ manualVulnerability={false}
+ message="Reduce the number of conditional operators (4) used in the expression"
+ ruleKey="javascript:S1067"
+ />
<div
className="issue-row-meta"
>
<div
className="issue-row"
>
- <ContextConsumer>
- <Component />
- </ContextConsumer>
+ <IssueMessage
+ manualVulnerability={false}
+ message="Reduce the number of conditional operators (4) used in the expression"
+ ruleKey="javascript:S1067"
+ />
<div
className="issue-row-meta"
>
export enum HttpStatus {
Ok = 200,
Created = 201,
+ NoContent = 204,
MultipleChoices = 300,
MovedPermanently = 301,
Found = 302,
import { Exporter, Profile } from '../apps/quality-profiles/types';
import { AppState } from '../types/appstate';
import { RuleRepository } from '../types/coding-rules';
+import { ComponentQualifier } from '../types/component';
import { EditionKey } from '../types/editions';
import { RawIssue } from '../types/issues';
import { Language } from '../types/languages';
path: 'foo/bar.ts',
project: 'my-project',
projectName: 'MyProject',
- q: 'FIL',
+ q: ComponentQualifier.File,
uuid: 'foo-bar',
...overrides
};
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { ComponentQualifier } from './component';
import { UserActive, UserBase } from './users';
export type Dict<T> = { [key: string]: T };
path: string;
project: string;
projectName: string;
- q: string;
+ q: ComponentQualifier;
subProject?: string;
subProjectName?: string;
uuid: string;