From 567ff7d183d5fb025abcad808fcd3cb5e8d5bb2e Mon Sep 17 00:00:00 2001 From: David Cho-Lerat Date: Wed, 6 Dec 2023 12:22:51 +0100 Subject: [PATCH] SONAR-21200 Activity page: don't show data from default branch on refresh --- .../main/js/apps/code/components/CodeApp.tsx | 8 +---- .../components/ComponentMeasuresApp.tsx | 6 ++-- .../components/ProjectActivityApp.tsx | 33 ++++++++++++++----- .../__tests__/ProjectActivityApp-it.tsx | 27 ++++++++++++--- .../sonar-web/src/main/js/queries/branch.tsx | 14 ++++---- 5 files changed, 57 insertions(+), 31 deletions(-) diff --git a/server/sonar-web/src/main/js/apps/code/components/CodeApp.tsx b/server/sonar-web/src/main/js/apps/code/components/CodeApp.tsx index 9343d730df2..a7b8a1244f1 100644 --- a/server/sonar-web/src/main/js/apps/code/components/CodeApp.tsx +++ b/server/sonar-web/src/main/js/apps/code/components/CodeApp.tsx @@ -22,8 +22,7 @@ import withComponentContext from '../../../app/components/componentContext/withC import withMetricsContext from '../../../app/components/metrics/withMetricsContext'; import { Location, Router, withRouter } from '../../../components/hoc/withRouter'; import { CodeScope, getCodeUrl, getProjectUrl } from '../../../helpers/urls'; -import { useBranchesQuery } from '../../../queries/branch'; -import { BranchLike } from '../../../types/branch-like'; +import { WithBranchLikesProps, useBranchesQuery } from '../../../queries/branch'; import { ComponentQualifier, isPortfolioLike } from '../../../types/component'; import { Breadcrumb, Component, ComponentMeasure, Dict, Metric } from '../../../types/types'; import { addComponent, addComponentBreadcrumbs, clearBucket } from '../bucket'; @@ -225,11 +224,6 @@ class CodeApp extends React.Component { } } -interface WithBranchLikesProps { - branchLikes?: BranchLike[]; - branchLike?: BranchLike; -} - function withBranchLikes

( WrappedComponent: React.ComponentType>, ): React.ComponentType>> { diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/ComponentMeasuresApp.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/ComponentMeasuresApp.tsx index 9054885817c..d2f773deb92 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/components/ComponentMeasuresApp.tsx +++ b/server/sonar-web/src/main/js/apps/component-measures/components/ComponentMeasuresApp.tsx @@ -40,8 +40,7 @@ import { enhanceMeasure } from '../../../components/measure/utils'; import '../../../components/search-navigator.css'; import { getBranchLikeQuery, isPullRequest, isSameBranchLike } from '../../../helpers/branch-like'; import { translate } from '../../../helpers/l10n'; -import { useBranchesQuery } from '../../../queries/branch'; -import { BranchLike } from '../../../types/branch-like'; +import { WithBranchLikesProps, useBranchesQuery } from '../../../queries/branch'; import { ComponentQualifier, isPortfolioLike } from '../../../types/component'; import { MeasurePageView } from '../../../types/measures'; import { MetricKey } from '../../../types/metrics'; @@ -66,8 +65,7 @@ import MeasureContent from './MeasureContent'; import MeasureOverviewContainer from './MeasureOverviewContainer'; import MeasuresEmpty from './MeasuresEmpty'; -interface Props { - branchLike?: BranchLike; +interface Props extends WithBranchLikesProps { component: ComponentMeasure; location: Location; router: Router; diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityApp.tsx b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityApp.tsx index 8a93f70b458..35c328e4365 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityApp.tsx +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityApp.tsx @@ -38,12 +38,11 @@ import { isCustomGraph, } from '../../../components/activity-graph/utils'; import { Location, Router, withRouter } from '../../../components/hoc/withRouter'; -import { getBranchLikeQuery } from '../../../helpers/branch-like'; +import { getBranchLikeQuery, isSameBranchLike } from '../../../helpers/branch-like'; import { HIDDEN_METRICS } from '../../../helpers/constants'; import { parseDate } from '../../../helpers/dates'; import { serializeStringArray } from '../../../helpers/query'; -import { withBranchLikes } from '../../../queries/branch'; -import { BranchLike } from '../../../types/branch-like'; +import { WithBranchLikesProps, withBranchLikes } from '../../../queries/branch'; import { ComponentQualifier, isApplication, @@ -68,8 +67,7 @@ import { } from '../utils'; import ProjectActivityAppRenderer from './ProjectActivityAppRenderer'; -interface Props { - branchLike?: BranchLike; +interface Props extends WithBranchLikesProps { component: Component; location: Location; metrics: Dict; @@ -109,13 +107,26 @@ class ProjectActivityApp extends React.PureComponent { componentDidMount() { this.mounted = true; - this.firstLoadData(this.state.query, this.props.component); + if (this.isBranchReady()) { + this.firstLoadData(this.state.query, this.props.component); + } } componentDidUpdate(prevProps: Props) { - if (prevProps.location.query !== this.props.location.query) { - const query = parseQuery(this.props.location.query); - if (query.graph !== this.state.query.graph || customMetricsChanged(this.state.query, query)) { + const unparsedQuery = this.props.location.query; + + const hasQueryChanged = prevProps.location.query !== unparsedQuery; + + const hasBranchChanged = !isSameBranchLike(prevProps.branchLike, this.props.branchLike); + + if (this.isBranchReady() && (hasBranchChanged || hasQueryChanged)) { + const query = parseQuery(unparsedQuery); + + if ( + query.graph !== this.state.query.graph || + customMetricsChanged(this.state.query, query) || + hasBranchChanged + ) { if (this.state.initialized) { this.updateGraphData(query.graph || DEFAULT_GRAPH, query.customMetrics); } else { @@ -130,6 +141,10 @@ class ProjectActivityApp extends React.PureComponent { this.mounted = false; } + isBranchReady = () => + isPortfolioLike(this.props.component.qualifier) || + (this.props.branchLike !== undefined && !this.props.isFetchingBranch); + handleAddCustomEvent = (analysisKey: string, name: string, category?: string) => { return createEvent(analysisKey, name, category).then(({ analysis, ...event }) => { if (this.mounted) { diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityApp-it.tsx b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityApp-it.tsx index 87a5e0bcd94..b627ccb82fa 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityApp-it.tsx +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityApp-it.tsx @@ -26,6 +26,7 @@ import { Route } from 'react-router-dom'; import ApplicationServiceMock from '../../../../api/mocks/ApplicationServiceMock'; import { ProjectActivityServiceMock } from '../../../../api/mocks/ProjectActivityServiceMock'; import { TimeMachineServiceMock } from '../../../../api/mocks/TimeMachineServiceMock'; +import { mockBranchList } from '../../../../api/mocks/data/branches'; import { parseDate } from '../../../../helpers/dates'; import { mockComponent } from '../../../../helpers/mocks/component'; import { @@ -56,11 +57,22 @@ jest.mock('../../../../helpers/storage', () => ({ save: jest.fn(), })); +jest.mock('../../../../api/branches', () => ({ + getBranches: () => { + isBranchReady = true; + return Promise.resolve(mockBranchList()); + }, +})); + const applicationHandler = new ApplicationServiceMock(); const projectActivityHandler = new ProjectActivityServiceMock(); const timeMachineHandler = new TimeMachineServiceMock(); +let isBranchReady = false; + beforeEach(() => { + isBranchReady = false; + jest.clearAllMocks(); applicationHandler.reset(); projectActivityHandler.reset(); @@ -139,7 +151,8 @@ describe('rendering', () => { breadcrumbs: [{ key: 'breadcrumb', name: 'breadcrumb', qualifier }], }), ); - await ui.appLoaded(); + + await ui.appLoaded({ doNotWaitForBranch: true }); expect(ui.newCodeLegend.query()).not.toBeInTheDocument(); }, @@ -360,7 +373,7 @@ describe('data loading', () => { }), ); - await ui.appLoaded(); + await ui.appLoaded({ doNotWaitForBranch: true }); // If it didn't fail, it means we correctly queried for project "foo". expect(ui.activityItem.getAll().length).toBe(4); @@ -548,10 +561,16 @@ function getPageObject() { user, ui: { ...ui, - async appLoaded() { + async appLoaded({ doNotWaitForBranch }: { doNotWaitForBranch?: boolean } = {}) { await waitFor(() => { expect(ui.loading.query()).not.toBeInTheDocument(); }); + + if (!doNotWaitForBranch) { + await waitFor(() => { + expect(isBranchReady).toBe(true); + }); + } }, async changeGraphType(type: GraphType) { @@ -681,7 +700,7 @@ function renderProjectActivityAppContainer( }), ) { return renderAppWithComponentContext( - 'project/activity', + `project/activity?id=${component.key}`, () => } />, { metrics: keyBy( diff --git a/server/sonar-web/src/main/js/queries/branch.tsx b/server/sonar-web/src/main/js/queries/branch.tsx index 31ca666967f..79345116acd 100644 --- a/server/sonar-web/src/main/js/queries/branch.tsx +++ b/server/sonar-web/src/main/js/queries/branch.tsx @@ -326,14 +326,14 @@ export function useRefreshBranches() { }; } +export interface WithBranchLikesProps { + branchLikes?: BranchLike[]; + branchLike?: BranchLike; + isFetchingBranch?: boolean; +} + export function withBranchLikes

( - WrappedComponent: React.ComponentType< - React.PropsWithChildren< - React.PropsWithChildren< - P & { branchLikes?: BranchLike[]; branchLike?: BranchLike; isFetchingBranch?: boolean } - > - > - >, + WrappedComponent: React.ComponentType>, ): React.ComponentType>> { return function WithBranchLike(p: P) { const { data, isFetching } = useBranchesQuery(p.component); -- 2.39.5