diff options
13 files changed, 40 insertions, 109 deletions
diff --git a/server/sonar-web/src/main/js/apps/issues/conciseIssuesList/ConciseIssueBox.tsx b/server/sonar-web/src/main/js/apps/issues/conciseIssuesList/ConciseIssueBox.tsx index 4cadb1885df..a0e5ba847a1 100644 --- a/server/sonar-web/src/main/js/apps/issues/conciseIssuesList/ConciseIssueBox.tsx +++ b/server/sonar-web/src/main/js/apps/issues/conciseIssuesList/ConciseIssueBox.tsx @@ -114,7 +114,6 @@ export default class ConciseIssueBox extends React.PureComponent<Props> { {selected && ( <LocationsList locations={locations} - uniqueKey={issue.key} isCrossFile={isCrossFile} onLocationSelect={this.props.onLocationSelect} scroll={this.props.scroll} diff --git a/server/sonar-web/src/main/js/apps/issues/conciseIssuesList/__tests__/__snapshots__/ConciseIssueBox-test.tsx.snap b/server/sonar-web/src/main/js/apps/issues/conciseIssuesList/__tests__/__snapshots__/ConciseIssueBox-test.tsx.snap index a3239afee18..074a4498639 100644 --- a/server/sonar-web/src/main/js/apps/issues/conciseIssuesList/__tests__/__snapshots__/ConciseIssueBox-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/issues/conciseIssuesList/__tests__/__snapshots__/ConciseIssueBox-test.tsx.snap @@ -61,7 +61,6 @@ exports[`should render correctly 1`] = ` onLocationSelect={[MockFunction]} scroll={[MockFunction]} selectedLocationIndex={0} - uniqueKey="AVsae-CQS-9G3txfbFN2" /> </div> `; @@ -226,7 +225,6 @@ exports[`should render correctly 2`] = ` onLocationSelect={[MockFunction]} scroll={[MockFunction]} selectedLocationIndex={0} - uniqueKey="AVsae-CQS-9G3txfbFN2" /> </div> `; diff --git a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/CrossComponentSourceViewerWrapper.tsx b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/CrossComponentSourceViewerWrapper.tsx index 2bd9406c410..5117ef3b3fc 100644 --- a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/CrossComponentSourceViewerWrapper.tsx +++ b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/CrossComponentSourceViewerWrapper.tsx @@ -88,9 +88,9 @@ export default class CrossComponentSourceViewerWrapper extends React.PureCompone this.fetchIssueFlowSnippets(this.props.issue.key); } - componentWillReceiveProps(newProps: Props) { - if (newProps.issue.key !== this.props.issue.key) { - this.fetchIssueFlowSnippets(newProps.issue.key); + componentDidUpdate(prevProps: Props) { + if (prevProps.issue.key !== this.props.issue.key) { + this.fetchIssueFlowSnippets(this.props.issue.key); } } diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotListItem.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotListItem.tsx index 3391ea13931..1df6caa33f4 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotListItem.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotListItem.tsx @@ -62,7 +62,6 @@ export default function HotspotListItem(props: HotspotListItemProps) { <LocationsList locations={locations} isCrossFile={false} // Currently we are not supporting cross file for security hotspot - uniqueKey={hotspot.key} onLocationSelect={props.onLocationClick} selectedLocationIndex={selectedHotspotLocation} scroll={props.onScroll} diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotListItem-test.tsx.snap b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotListItem-test.tsx.snap index 1da226e22ca..0d13bbb6774 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotListItem-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotListItem-test.tsx.snap @@ -62,7 +62,6 @@ exports[`should render correctly 2`] = ` locations={Array []} onLocationSelect={[Function]} scroll={[MockFunction]} - uniqueKey="01fc972e-2a3c-433e-bcae-0bd7f88f5123" /> </a> `; diff --git a/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerBase.tsx b/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerBase.tsx index ba2f5faee85..93950d7fff7 100644 --- a/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerBase.tsx +++ b/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerBase.tsx @@ -156,24 +156,13 @@ export default class SourceViewerBase extends React.PureComponent<Props, State> this.fetchComponent(); } - componentWillReceiveProps(nextProps: Props) { - // if a component or a branch has changed, - // set `loading: true` immediately to avoid unwanted scrolling in `LineCode` - if ( - nextProps.component !== this.props.component || - !isSameBranchLike(nextProps.branchLike, this.props.branchLike) - ) { - this.setState({ loading: true }); - } + componentDidUpdate(prevProps: Props) { if ( - nextProps.onIssueSelect !== undefined && - nextProps.selectedIssue !== this.props.selectedIssue + this.props.onIssueSelect !== undefined && + this.props.selectedIssue !== prevProps.selectedIssue ) { - this.setState({ selectedIssue: nextProps.selectedIssue }); + this.setState({ selectedIssue: this.props.selectedIssue }); } - } - - componentDidUpdate(prevProps: Props) { if ( prevProps.component !== this.props.component || !isSameBranchLike(prevProps.branchLike, this.props.branchLike) 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 21736e0cdff..f9216d65d18 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 @@ -22,12 +22,7 @@ import * as React from 'react'; import { LinearIssueLocation, SourceLine } from '../../../types/types'; import LocationIndex from '../../common/LocationIndex'; import Tooltip from '../../controls/Tooltip'; -import { - highlightIssueLocations, - highlightSymbol, - splitByTokens, - Token -} from '../helpers/highlight'; +import { highlightIssueLocations, highlightSymbol, splitByTokens } from '../helpers/highlight'; interface Props { className?: string; @@ -43,43 +38,17 @@ interface Props { secondaryIssueLocations: LinearIssueLocation[]; } -interface State { - tokens: Token[]; -} - -export default class LineCode extends React.PureComponent<React.PropsWithChildren<Props>, State> { +export default class LineCode extends React.PureComponent<React.PropsWithChildren<Props>> { activeMarkerNode?: HTMLElement | null; - codeNode?: HTMLElement | null; symbols?: NodeListOf<HTMLElement>; - constructor(props: Props) { - super(props); - this.state = { - tokens: splitByTokens(props.line.code || '') - }; - } - componentDidMount() { - this.attachEvents(); if (this.props.highlightedLocationMessage && this.activeMarkerNode && this.props.scroll) { this.props.scroll(this.activeMarkerNode); } } - componentWillReceiveProps(nextProps: Props) { - if (nextProps.line.code !== this.props.line.code) { - this.setState({ - tokens: splitByTokens(nextProps.line.code || '') - }); - } - } - - componentWillUpdate() { - this.detachEvents(); - } - componentDidUpdate(prevProps: Props) { - this.attachEvents(); if ( this.props.highlightedLocationMessage && (!prevProps.highlightedLocationMessage || @@ -92,18 +61,20 @@ export default class LineCode extends React.PureComponent<React.PropsWithChildre } } - componentWillUnmount() { - this.detachEvents(); - } + nodeNodeRef = (el: HTMLElement | null) => { + if (el) { + this.attachEvents(el); + } else { + this.detachEvents(); + } + }; - attachEvents() { - if (this.codeNode) { - this.symbols = this.codeNode.querySelectorAll('.sym'); - if (this.symbols) { - for (let i = 0; i < this.symbols.length; i++) { - const symbol = this.symbols[i]; - symbol.addEventListener('click', this.handleSymbolClick); - } + attachEvents(codeNode: HTMLElement) { + this.symbols = codeNode.querySelectorAll('.sym'); + if (this.symbols) { + for (let i = 0; i < this.symbols.length; i++) { + const symbol = this.symbols[i]; + symbol.addEventListener('click', this.handleSymbolClick); } } } @@ -155,7 +126,7 @@ export default class LineCode extends React.PureComponent<React.PropsWithChildre secondaryIssueLocations } = this.props; - let tokens = [...this.state.tokens]; + let tokens = splitByTokens(this.props.line.code || ''); if (highlightedSymbols) { highlightedSymbols.forEach(symbol => { @@ -214,7 +185,7 @@ export default class LineCode extends React.PureComponent<React.PropsWithChildre data-line-number={line.line} style={style}> <div className="source-line-code-inner"> - <pre ref={node => (this.codeNode = node)}>{renderedTokens}</pre> + <pre ref={this.nodeNodeRef}>{renderedTokens}</pre> </div> {children} diff --git a/server/sonar-web/src/main/js/components/issue/Issue.tsx b/server/sonar-web/src/main/js/components/issue/Issue.tsx index ffdcd52f6d1..0d4c0d01ed7 100644 --- a/server/sonar-web/src/main/js/components/issue/Issue.tsx +++ b/server/sonar-web/src/main/js/components/issue/Issue.tsx @@ -52,15 +52,11 @@ export default class Issue extends React.PureComponent<Props> { } } - componentWillUpdate(nextProps: Props) { - if (!nextProps.selected && this.props.selected) { - this.unbindShortcuts(); - } - } - componentDidUpdate(prevProps: Props) { if (!prevProps.selected && this.props.selected) { this.bindShortcuts(); + } else if (prevProps.selected && !this.props.selected) { + this.unbindShortcuts(); } } diff --git a/server/sonar-web/src/main/js/components/locations/CrossFileLocationNavigator.tsx b/server/sonar-web/src/main/js/components/locations/CrossFileLocationNavigator.tsx index bf6074b5a54..8254d91ef50 100644 --- a/server/sonar-web/src/main/js/components/locations/CrossFileLocationNavigator.tsx +++ b/server/sonar-web/src/main/js/components/locations/CrossFileLocationNavigator.tsx @@ -20,12 +20,11 @@ import * as React from 'react'; import { translateWithParameters } from '../../helpers/l10n'; import { collapsePath } from '../../helpers/path'; -import SingleFileLocationNavigator from './SingleFileLocationNavigator'; -import './CrossFileLocationNavigator.css'; import { FlowLocation } from '../../types/types'; +import './CrossFileLocationNavigator.css'; +import SingleFileLocationNavigator from './SingleFileLocationNavigator'; interface Props { - uniqueKey: string; locations: FlowLocation[]; onLocationSelect: (index: number) => void; scroll: (element: Element) => void; @@ -48,18 +47,14 @@ const MAX_PATH_LENGTH = 15; export default class CrossFileLocationNavigator extends React.PureComponent<Props, State> { state: State = { collapsed: true }; - componentWillReceiveProps(nextProps: Props) { - if (nextProps.uniqueKey !== this.props.uniqueKey) { - this.setState({ collapsed: true }); - } - - // expand locations list as soon as a location in the middle of the list is selected - const { locations: nextLocations } = nextProps; + componentDidUpdate() { + const { locations, selectedLocationIndex } = this.props; if ( - nextProps.selectedLocationIndex && - nextProps.selectedLocationIndex > 0 && - nextLocations !== undefined && - nextProps.selectedLocationIndex < nextLocations.length - 1 + selectedLocationIndex && + selectedLocationIndex > 0 && + locations !== undefined && + selectedLocationIndex < locations.length - 1 && + this.state.collapsed ) { this.setState({ collapsed: false }); } diff --git a/server/sonar-web/src/main/js/components/locations/LocationsList.tsx b/server/sonar-web/src/main/js/components/locations/LocationsList.tsx index 19e52f004c0..65e3c6ebdf2 100644 --- a/server/sonar-web/src/main/js/components/locations/LocationsList.tsx +++ b/server/sonar-web/src/main/js/components/locations/LocationsList.tsx @@ -24,7 +24,6 @@ import SingleFileLocationNavigator from './SingleFileLocationNavigator'; interface Props { isCrossFile: boolean; - uniqueKey: string; locations: FlowLocation[]; onLocationSelect: (index: number) => void; scroll: (element: Element) => void; @@ -33,7 +32,7 @@ interface Props { export default class LocationsList extends React.PureComponent<Props> { render() { - const { isCrossFile, locations, uniqueKey, selectedLocationIndex } = this.props; + const { isCrossFile, locations, selectedLocationIndex } = this.props; if (!locations || locations.length === 0 || locations.every(location => !location.msg)) { return null; @@ -42,7 +41,6 @@ export default class LocationsList extends React.PureComponent<Props> { if (isCrossFile) { return ( <CrossFileLocationNavigator - uniqueKey={uniqueKey} locations={locations} onLocationSelect={this.props.onLocationSelect} scroll={this.props.scroll} diff --git a/server/sonar-web/src/main/js/components/locations/__tests__/CrossFileLocationsNavigator-test.tsx b/server/sonar-web/src/main/js/components/locations/__tests__/CrossFileLocationsNavigator-test.tsx index a5f7cd136d3..2147bba7ad4 100644 --- a/server/sonar-web/src/main/js/components/locations/__tests__/CrossFileLocationsNavigator-test.tsx +++ b/server/sonar-web/src/main/js/components/locations/__tests__/CrossFileLocationsNavigator-test.tsx @@ -19,8 +19,8 @@ */ import { shallow } from 'enzyme'; import * as React from 'react'; -import { click } from '../../../helpers/testUtils'; import { mockFlowLocation } from '../../../helpers/testMocks'; +import { click } from '../../../helpers/testUtils'; import { FlowLocation } from '../../../types/types'; import CrossFileLocationsNavigator from '../CrossFileLocationNavigator'; @@ -77,20 +77,9 @@ it('should expand all locations', () => { expect(wrapper.find('SingleFileLocationNavigator').length).toBe(3); }); -it('should collapse locations when issue changes', () => { - const wrapper = shallowRender(); - - wrapper.setProps({ selectedLocationIndex: 1 }); - expect(wrapper.find('SingleFileLocationNavigator').length).toBe(3); - - wrapper.setProps({ uniqueKey: 'def', selectedLocationIndex: undefined }); - expect(wrapper.find('SingleFileLocationNavigator').length).toBe(2); -}); - function shallowRender(props: Partial<CrossFileLocationsNavigator['props']> = {}) { return shallow<CrossFileLocationsNavigator>( <CrossFileLocationsNavigator - uniqueKey="abcd" locations={[location1, location2, location3]} onLocationSelect={jest.fn()} scroll={jest.fn()} diff --git a/server/sonar-web/src/main/js/components/locations/__tests__/LocationsList-test.tsx b/server/sonar-web/src/main/js/components/locations/__tests__/LocationsList-test.tsx index 3f525e8845c..a5edeafdcf8 100644 --- a/server/sonar-web/src/main/js/components/locations/__tests__/LocationsList-test.tsx +++ b/server/sonar-web/src/main/js/components/locations/__tests__/LocationsList-test.tsx @@ -46,23 +46,22 @@ const location3: FlowLocation = { it('should render locations in the same file', () => { const locations = [location1, location2]; - expect(shallowRender({ uniqueKey: '', locations, isCrossFile: false })).toMatchSnapshot(); + expect(shallowRender({ locations, isCrossFile: false })).toMatchSnapshot(); }); it('should render flow locations in different file', () => { const locations = [location1, location3]; - expect(shallowRender({ uniqueKey: '', locations, isCrossFile: true })).toMatchSnapshot(); + expect(shallowRender({ locations, isCrossFile: true })).toMatchSnapshot(); }); it('should not render locations', () => { - const wrapper = shallowRender({ uniqueKey: '', locations: [] }); + const wrapper = shallowRender({ locations: [] }); expect(wrapper.type()).toBeNull(); }); function shallowRender(overrides: Partial<LocationsList['props']> = {}) { return shallow<LocationsList>( <LocationsList - uniqueKey={mockIssue().key} locations={mockIssue().secondaryLocations} isCrossFile={true} onLocationSelect={jest.fn()} diff --git a/server/sonar-web/src/main/js/components/locations/__tests__/__snapshots__/LocationsList-test.tsx.snap b/server/sonar-web/src/main/js/components/locations/__tests__/__snapshots__/LocationsList-test.tsx.snap index 9cb465ba244..eb41475e47b 100644 --- a/server/sonar-web/src/main/js/components/locations/__tests__/__snapshots__/LocationsList-test.tsx.snap +++ b/server/sonar-web/src/main/js/components/locations/__tests__/__snapshots__/LocationsList-test.tsx.snap @@ -30,7 +30,6 @@ exports[`should render flow locations in different file 1`] = ` } onLocationSelect={[MockFunction]} scroll={[MockFunction]} - uniqueKey="" /> `; |