}
createSnippetsFromProps() {
+ const { issue, snippetGroup } = this.props;
+
const snippets = createSnippets({
- locations: this.props.snippetGroup.locations,
- issue: this.props.issue,
- addIssueLocation: this.props.issue.secondaryLocations.length > 0
+ locations: snippetGroup.locations,
+ issue,
+ addIssueLocation:
+ issue.secondaryLocations.length > 0 && snippetGroup.component.key === issue.component
});
this.setState({ snippets });
render() {
const { branchLike, duplications, issue, issuesByLine, last, snippetGroup } = this.props;
const { additionalLines, loading, snippets } = this.state;
- const locations = locationsByLine([issue]);
+ const locations =
+ issue.component === snippetGroup.component.key ? locationsByLine([issue]) : {};
const fullyShown =
snippets.length === 1 &&
...additionalLines
});
+ const isFlow = issue.secondaryLocations.length === 0;
+ const includeIssueLocation = (index: number) =>
+ isFlow ? last && index === snippets.length - 1 : index === 0;
+
return (
<div
className={classNames('component-source-container', {
{this.renderSnippet({
snippet,
index: snippets[index].index,
- issuesByLine: last ? issuesByLine : {},
- locationsByLine: last && index === snippets.length - 1 ? locations : {},
+ issuesByLine,
+ locationsByLine: includeIssueLocation(index) ? locations : {},
last: last && index === snippets.length - 1
})}
</div>
isDuplicationBlockInRemovedComponent
} from '../../../components/SourceViewer/helpers/duplications';
import {
- duplicationsByLine,
+ duplicationsByLine as getDuplicationsByLine,
issuesByComponentAndLine
} from '../../../components/SourceViewer/helpers/indexing';
import { SourceViewerContext } from '../../../components/SourceViewer/SourceViewerContext';
this.setState(state => ({
duplicatedFiles: r.files,
duplications: r.duplications,
- duplicationsByLine: duplicationsByLine(r.duplications),
+ duplicationsByLine: getDuplicationsByLine(r.duplications),
linePopup:
r.duplications.length === 1
? { component, index: 0, line: line.line, name: 'duplications' }
);
}
+ const { issue, locations } = this.props;
const { components, duplications, duplicationsByLine, linePopup } = this.state;
const issuesByComponent = issuesByComponentAndLine(this.props.issues);
- const locationsByComponent = groupLocationsByComponent(this.props.locations, components);
+ const locationsByComponent = groupLocationsByComponent(issue, locations, components);
return (
<div>
}
return (
<SourceViewerContext.Provider
- key={`${this.props.issue.key}-${this.props.selectedFlowIndex || 0}-${i}`}
+ // eslint-disable-next-line react/no-array-index-key
+ key={`${issue.key}-${this.props.selectedFlowIndex || 0}-${i}`}
value={{ branchLike: this.props.branchLike, file: snippetGroup.component }}>
<ComponentSourceSnippetViewer
branchLike={this.props.branchLike}
highlightedLocationMessage={this.props.highlightedLocationMessage}
- issue={this.props.issue}
+ issue={issue}
issuePopup={this.state.issuePopup}
issuesByLine={issuesByComponent[snippetGroup.component.key] || {}}
last={i === locationsByComponent.length - 1}
const snippetGroup: T.SnippetGroup = {
locations: [
mockFlowLocation({
- component: 'a',
+ component: issue.component,
textRange: { startLine: 34, endLine: 34, startOffset: 0, endOffset: 0 }
}),
mockFlowLocation({
- component: 'a',
+ component: issue.component,
textRange: { startLine: 74, endLine: 74, startOffset: 0, endOffset: 0 }
})
],
- ...mockSnippetsByComponent('a', [...range(2, 17), ...range(29, 39), ...range(69, 79)])
+ ...mockSnippetsByComponent(issue.component, [
+ ...range(2, 17),
+ ...range(29, 39),
+ ...range(69, 79)
+ ])
};
const wrapper = shallowRender({ issue, snippetGroup });
expect(wrapper.state('snippets')).toHaveLength(3);
expect(wrapper.state('snippets')[2]).toEqual({ index: 2, start: 69, end: 79 });
});
+it('should render correctly with flows', () => {
+ // issue with flows but no secondary locations
+ const issue = mockIssue(true, {
+ secondaryLocations: [],
+ textRange: { startLine: 7, endLine: 7, startOffset: 5, endOffset: 10 }
+ });
+
+ const snippetGroup: T.SnippetGroup = {
+ locations: [
+ mockFlowLocation({
+ component: issue.component,
+ textRange: { startLine: 34, endLine: 34, startOffset: 0, endOffset: 0 }
+ }),
+ mockFlowLocation({
+ component: issue.component,
+ textRange: { startLine: 74, endLine: 74, startOffset: 0, endOffset: 0 }
+ })
+ ],
+ ...mockSnippetsByComponent(issue.component, [
+ ...range(2, 17),
+ ...range(29, 39),
+ ...range(69, 79)
+ ])
+ };
+ const wrapper = shallowRender({ issue, snippetGroup });
+ expect(wrapper.state('snippets')).toHaveLength(2);
+ expect(wrapper.state('snippets')[0]).toEqual({ index: 0, start: 29, end: 39 });
+ expect(wrapper.state('snippets')[1]).toEqual({ index: 1, start: 69, end: 79 });
+});
+
it('should expand block', async () => {
(getSources as jest.Mock).mockResolvedValueOnce(
Object.values(mockSnippetsByComponent('a', range(6, 59)).sources)
describe('groupLocationsByComponent', () => {
it('should handle empty args', () => {
- expect(groupLocationsByComponent([], {})).toEqual([]);
+ expect(groupLocationsByComponent(mockIssue(), [], {})).toEqual([]);
});
it('should group correctly', () => {
const results = groupLocationsByComponent(
+ mockIssue(),
[
mockFlowLocation({
textRange: { startLine: 16, startOffset: 10, endLine: 16, endOffset: 14 }
it('should preserve step order when jumping between files', () => {
const results = groupLocationsByComponent(
+ mockIssue(),
[
mockFlowLocation({
component: 'A.js',
return !(startA > endB + MERGE_DISTANCE || endA < startB - MERGE_DISTANCE);
}
-function getPrimaryLocation(issue: T.Issue): T.FlowLocation {
+export function getPrimaryLocation(issue: T.Issue): T.FlowLocation {
return {
component: issue.component,
textRange: issue.textRange || {
}
export function groupLocationsByComponent(
+ issue: T.Issue,
locations: T.FlowLocation[],
components: { [key: string]: T.SnippetsByComponent }
) {
let currentGroup: T.SnippetGroup;
const groups: T.SnippetGroup[] = [];
+ const addGroup = (loc: T.FlowLocation) => {
+ currentGroup = {
+ ...(components[loc.component] || unknownComponent(loc.component)),
+ locations: []
+ };
+ groups.push(currentGroup);
+ currentComponent = loc.component;
+ };
+
+ if (
+ issue.secondaryLocations.length > 0 &&
+ locations.every(loc => loc.component !== issue.component)
+ ) {
+ addGroup(getPrimaryLocation(issue));
+ }
+
locations.forEach((loc, index) => {
if (loc.component !== currentComponent) {
- currentGroup = {
- ...(components[loc.component] || unknownComponent(loc.component)),
- locations: []
- };
- groups.push(currentGroup);
- currentComponent = loc.component;
+ addGroup(loc);
}
loc.index = index;
currentGroup.locations.push(loc);