From 3c8133f5f9a2591a69df8fa32b23ae9ed5d5e93f Mon Sep 17 00:00:00 2001 From: David Cho-Lerat Date: Tue, 11 Jul 2023 13:58:44 +0200 Subject: [PATCH] SONAR-19754 Lock application hotspots when reindexing --- .../security-hotspots/SecurityHotspotsApp.tsx | 27 +++++++++--- .../__tests__/withIndexationGuard-test.tsx | 41 ++++++++----------- .../js/components/hoc/withIndexationGuard.tsx | 23 +++++------ 3 files changed, 49 insertions(+), 42 deletions(-) diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/SecurityHotspotsApp.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/SecurityHotspotsApp.tsx index 795d7fc2ed7..b9c9a1947cd 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/SecurityHotspotsApp.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/SecurityHotspotsApp.tsx @@ -24,6 +24,7 @@ import { getMeasures } from '../../api/measures'; import { getSecurityHotspotList, getSecurityHotspots } from '../../api/security-hotspots'; import withComponentContext from '../../app/components/componentContext/withComponentContext'; import withCurrentUserContext from '../../app/components/current-user/withCurrentUserContext'; +import withIndexationGuard from '../../components/hoc/withIndexationGuard'; import { Location, Router, withRouter } from '../../components/hoc/withRouter'; import { getLeakValue } from '../../components/measure/utils'; import { getBranchLikeQuery, isPullRequest, isSameBranchLike } from '../../helpers/branch-like'; @@ -32,6 +33,7 @@ import { KeyboardKeys } from '../../helpers/keycodes'; import { getStandards } from '../../helpers/security-standard'; import { withBranchLikes } from '../../queries/branch'; import { BranchLike } from '../../types/branch-like'; +import { ComponentQualifier } from '../../types/component'; import { MetricKey } from '../../types/metrics'; import { SecurityStandard, Standards } from '../../types/security'; import { @@ -108,7 +110,9 @@ export class SecurityHotspotsApp extends React.PureComponent { componentDidMount() { this.mounted = true; + this.fetchInitialData(); + this.registerKeyboardEvents(); } @@ -472,12 +476,12 @@ export class SecurityHotspotsApp extends React.PureComponent { this.props.router.push({ pathname: this.props.location.pathname, query: { + assignedToMe: undefined, file: undefined, fileUuid: undefined, hotspots: [], - sinceLeakPeriod: undefined, - assignedToMe: undefined, id: this.props.component.key, + sinceLeakPeriod: undefined, }, }); }; @@ -551,6 +555,7 @@ export class SecurityHotspotsApp extends React.PureComponent { render() { const { branchLike, component } = this.props; + const { filterByCategory, filterByCWE, @@ -572,10 +577,10 @@ export class SecurityHotspotsApp extends React.PureComponent { { loadingMeasure={loadingMeasure} loadingMore={loadingMore} onChangeFilters={this.handleChangeFilters} - onShowAllHotspots={this.handleShowAllHotspots} onHotspotClick={this.handleHotspotClick} onLoadMore={this.handleLoadMore} + onLocationClick={this.handleLocationClick} + onShowAllHotspots={this.handleShowAllHotspots} onSwitchStatusFilter={this.handleChangeStatusFilter} onUpdateHotspot={this.handleHotspotUpdate} - onLocationClick={this.handleLocationClick} securityCategories={standards[SecurityStandard.SONARSOURCE]} selectedHotspot={selectedHotspot} selectedHotspotLocation={selectedHotspotLocationIndex} @@ -602,5 +607,15 @@ export class SecurityHotspotsApp extends React.PureComponent { } export default withRouter( - withComponentContext(withCurrentUserContext(withBranchLikes(SecurityHotspotsApp))) + withComponentContext( + withCurrentUserContext( + withBranchLikes( + withIndexationGuard({ + Component: SecurityHotspotsApp, + showIndexationMessage: ({ component }) => + !!(component.qualifier === ComponentQualifier.Application && component.needIssueSync), + }) + ) + ) + ) ); diff --git a/server/sonar-web/src/main/js/components/hoc/__tests__/withIndexationGuard-test.tsx b/server/sonar-web/src/main/js/components/hoc/__tests__/withIndexationGuard-test.tsx index 39cab4e402e..13683555887 100644 --- a/server/sonar-web/src/main/js/components/hoc/__tests__/withIndexationGuard-test.tsx +++ b/server/sonar-web/src/main/js/components/hoc/__tests__/withIndexationGuard-test.tsx @@ -17,37 +17,34 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { mount } from 'enzyme'; + +import { render, screen } from '@testing-library/react'; import * as React from 'react'; import { IndexationContext } from '../../../app/components/indexation/IndexationContext'; -import { IndexationContextInterface } from '../../../types/indexation'; import withIndexationGuard from '../withIndexationGuard'; -it('should not render children because indexation is in progress', () => { - const wrapper = mountRender(); - expect(wrapper.find(TestComponent).exists()).toBe(false); -}); +describe('withIndexationGuard', () => { + it('should render indexation message when showIndexationMessage returns true', () => { + renderComponentWithIndexationGuard(() => true); + expect(screen.getByText(/indexation\.page_unavailable\.description/)).toBeInTheDocument(); + }); -it('should not render children because indexation has failures', () => { - const wrapper = mountRender({ - status: { isCompleted: true, percentCompleted: 100, hasFailures: true }, + it('should render children when showIndexationMessage returns false', () => { + renderComponentWithIndexationGuard(() => false); + expect(screen.getByText('TestComponent')).toBeInTheDocument(); }); - expect(wrapper.find(TestComponent).exists()).toBe(false); }); -it('should render children because indexation is completed without failures', () => { - const wrapper = mountRender({ - status: { isCompleted: true, percentCompleted: 100, hasFailures: false }, +function renderComponentWithIndexationGuard(showIndexationMessage: () => boolean) { + const TestComponentWithGuard = withIndexationGuard({ + Component: TestComponent, + showIndexationMessage, }); - expect(wrapper.find(TestComponent).exists()).toBe(true); -}); -function mountRender(context?: Partial) { - return mount( + return render( @@ -55,10 +52,6 @@ function mountRender(context?: Partial) { ); } -class TestComponent extends React.PureComponent { - render() { - return

TestComponent

; - } +function TestComponent() { + return

TestComponent

; } - -const TestComponentWithGuard = withIndexationGuard(TestComponent); diff --git a/server/sonar-web/src/main/js/components/hoc/withIndexationGuard.tsx b/server/sonar-web/src/main/js/components/hoc/withIndexationGuard.tsx index b70ee49246c..f3b882132d4 100644 --- a/server/sonar-web/src/main/js/components/hoc/withIndexationGuard.tsx +++ b/server/sonar-web/src/main/js/components/hoc/withIndexationGuard.tsx @@ -19,21 +19,20 @@ */ import * as React from 'react'; -import { IndexationContext } from '../../app/components/indexation/IndexationContext'; import PageUnavailableDueToIndexation from '../../app/components/indexation/PageUnavailableDueToIndexation'; -export default function withIndexationGuard

(WrappedComponent: React.ComponentType

) { +export default function withIndexationGuard

({ + Component, + showIndexationMessage, +}: { + Component: React.ComponentType

; + showIndexationMessage: (props: P) => boolean; +}) { return function WithIndexationGuard(props: React.PropsWithChildren

) { - return ( - - {(context) => - context?.status.isCompleted && !context?.status.hasFailures ? ( - - ) : ( - - ) - } - + return showIndexationMessage(props) ? ( + + ) : ( + ); }; } -- 2.39.5