From bae60bb896fb02d58245889bc896c06b62e96cab Mon Sep 17 00:00:00 2001 From: Jay Date: Wed, 11 Sep 2024 09:33:38 +0200 Subject: [PATCH] SONAR-22970 Improve branch queries and fix loading conflict --- .../js/app/components/ComponentContainer.tsx | 4 +- .../extensions/ProjectAdminPageExtension.tsx | 2 +- .../extensions/ProjectPageExtension.tsx | 7 +- .../components/nav/component/ComponentNav.tsx | 23 ++- .../js/app/components/nav/component/Menu.tsx | 7 +- .../branch-like/BranchLikeNavigation.tsx | 7 +- .../main/js/apps/code/components/CodeApp.tsx | 29 ++- .../components/ComponentMeasuresApp.tsx | 5 +- .../components/MeasureContent.tsx | 4 +- .../components/MeasureOverview.tsx | 4 +- .../sidebar/SubnavigationMeasureValue.tsx | 7 +- .../IssueSourceViewerHeader.tsx | 6 +- .../branches/__tests__/BranchOverview-it.tsx | 4 + .../components/AnalysisErrorMessage.tsx | 4 +- .../components/AnalysisWarningsModal.tsx | 2 +- .../main/js/apps/overview/components/App.tsx | 14 +- .../overview/components/EmptyOverview.tsx | 6 +- .../__tests__/PullRequestOverview-it.tsx | 4 + .../components/ProjectActivityApp.tsx | 4 +- .../components/BranchLikeTabs.tsx | 2 +- .../components/HotspotHeader.tsx | 2 +- .../components/HotspotViewerTabs.tsx | 2 +- .../components/activity-graph/EventInner.tsx | 4 +- .../src/main/js/components/issue/Issue.tsx | 5 +- .../tutorials/TutorialSelectionRenderer.tsx | 2 +- .../sonar-web/src/main/js/queries/branch.tsx | 186 +++++++++++------- .../src/main/js/queries/project-analyses.ts | 4 +- 27 files changed, 205 insertions(+), 145 deletions(-) diff --git a/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx b/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx index 8bfe5f83eca..5df87de7d47 100644 --- a/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx +++ b/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx @@ -33,7 +33,7 @@ import { getComponentNavigation } from '../../api/navigation'; import { translateWithParameters } from '../../helpers/l10n'; import { HttpStatus } from '../../helpers/request'; import { getPortfolioUrl, getProjectUrl, getPullRequestUrl } from '../../helpers/urls'; -import { useBranchesQuery } from '../../queries/branch'; +import { useCurrentBranchQuery } from '../../queries/branch'; import { useIsLegacyCCTMode } from '../../queries/settings'; import { ProjectAlmBindingConfigurationErrors } from '../../types/alm-settings'; import { Branch } from '../../types/branch-like'; @@ -69,7 +69,7 @@ function ComponentContainer({ hasFeature }: Readonly React.useState(); const [loading, setLoading] = React.useState(true); const [isPending, setIsPending] = React.useState(false); - const { data: { branchLike } = {}, isFetching } = useBranchesQuery( + const { data: branchLike, isFetching } = useCurrentBranchQuery( fixedInPullRequest ? component : undefined, ); diff --git a/server/sonar-web/src/main/js/app/components/extensions/ProjectAdminPageExtension.tsx b/server/sonar-web/src/main/js/app/components/extensions/ProjectAdminPageExtension.tsx index 2d97554b7d8..b25d4659cbc 100644 --- a/server/sonar-web/src/main/js/app/components/extensions/ProjectAdminPageExtension.tsx +++ b/server/sonar-web/src/main/js/app/components/extensions/ProjectAdminPageExtension.tsx @@ -29,7 +29,7 @@ export default function ProjectAdminPageExtension() { const { component, onComponentChange } = React.useContext(ComponentContext); // We keep that for compatibility but ideally should advocate to use tanstack query - const onBranchesChange = useRefreshBranches(); + const onBranchesChange = useRefreshBranches(component?.key); const extension = component?.configuration?.extensions?.find( (p) => p.key === `${pluginKey}/${extensionKey}`, diff --git a/server/sonar-web/src/main/js/app/components/extensions/ProjectPageExtension.tsx b/server/sonar-web/src/main/js/app/components/extensions/ProjectPageExtension.tsx index 025a9a20529..c4d6598aef6 100644 --- a/server/sonar-web/src/main/js/app/components/extensions/ProjectPageExtension.tsx +++ b/server/sonar-web/src/main/js/app/components/extensions/ProjectPageExtension.tsx @@ -19,7 +19,7 @@ */ import * as React from 'react'; import { useParams } from 'react-router-dom'; -import { useBranchesQuery } from '../../../queries/branch'; +import { useCurrentBranchQuery } from '../../../queries/branch'; import NotFound from '../NotFound'; import { ComponentContext } from '../componentContext/ComponentContext'; import Extension from './Extension'; @@ -34,13 +34,12 @@ export interface ProjectPageExtensionProps { export default function ProjectPageExtension({ params }: ProjectPageExtensionProps) { const { extensionKey, pluginKey } = useParams(); const { component } = React.useContext(ComponentContext); - const { data } = useBranchesQuery(component); + const { data: branchLike, isLoading } = useCurrentBranchQuery(component); - if (component === undefined || data === undefined) { + if (component === undefined || isLoading) { return null; } - const { branchLike } = data; const fullKey = params !== undefined ? `${params.pluginKey}/${params.extensionKey}` diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.tsx b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.tsx index 7a668ce3d26..29c0ecc681d 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.tsx @@ -21,10 +21,11 @@ import { TopBar } from 'design-system'; import * as React from 'react'; import { ComponentQualifier } from '~sonar-aligned/types/component'; import NCDAutoUpdateMessage from '../../../../components/new-code-definition/NCDAutoUpdateMessage'; +import { getBranchLikeDisplayName } from '../../../../helpers/branch-like'; import { translate } from '../../../../helpers/l10n'; -import { withBranchLikes } from '../../../../queries/branch'; +import { isDefined } from '../../../../helpers/types'; +import { useCurrentBranchQuery } from '../../../../queries/branch'; import { ProjectAlmBindingConfigurationErrors } from '../../../../types/alm-settings'; -import { Branch } from '../../../../types/branch-like'; import { Feature } from '../../../../types/features'; import { Component } from '../../../../types/types'; import RecentHistory from '../../RecentHistory'; @@ -36,7 +37,6 @@ import Header from './Header'; import Menu from './Menu'; export interface ComponentNavProps extends WithAvailableFeaturesProps { - branchLike?: Branch; component: Component; isInProgress?: boolean; isPending?: boolean; @@ -44,8 +44,9 @@ export interface ComponentNavProps extends WithAvailableFeaturesProps { } function ComponentNav(props: Readonly) { - const { branchLike, component, hasFeature, isInProgress, isPending, projectBindingErrors } = - props; + const { component, hasFeature, isInProgress, isPending, projectBindingErrors } = props; + + const { data: branchLike } = useCurrentBranchQuery(component); React.useEffect(() => { const { breadcrumbs, key, name } = component; @@ -61,6 +62,11 @@ function ComponentNav(props: Readonly) { } }, [component, component.key]); + const branchName = + hasFeature(Feature.BranchSupport) || !isDefined(branchLike) + ? undefined + : getBranchLikeDisplayName(branchLike); + return ( <> @@ -69,10 +75,7 @@ function ComponentNav(props: Readonly) { - + {projectBindingErrors !== undefined && ( )} @@ -80,4 +83,4 @@ function ComponentNav(props: Readonly) { ); } -export default withAvailableFeatures(withBranchLikes(ComponentNav)); +export default withAvailableFeatures(ComponentNav); diff --git a/server/sonar-web/src/main/js/app/components/nav/component/Menu.tsx b/server/sonar-web/src/main/js/app/components/nav/component/Menu.tsx index dd5d943ff8d..6b06dd7ea5b 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/Menu.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/Menu.tsx @@ -29,7 +29,7 @@ import { ComponentQualifier } from '~sonar-aligned/types/component'; import { DEFAULT_ISSUES_QUERY } from '../../../../components/shared/utils'; import { hasMessage, translate, translateWithParameters } from '../../../../helpers/l10n'; import { getPortfolioUrl, getProjectQueryUrl } from '../../../../helpers/urls'; -import { useBranchesQuery } from '../../../../queries/branch'; +import { useBranchesQuery, useCurrentBranchQuery } from '../../../../queries/branch'; import { isApplication, isProject } from '../../../../types/component'; import { Feature } from '../../../../types/features'; import { Component, Dict, Extension } from '../../../../types/types'; @@ -64,7 +64,10 @@ type Query = BranchParameters & { id: string }; export function Menu(props: Readonly) { const { component, isInProgress, isPending } = props; const { extensions = [], canBrowseAllChildProjects, qualifier, configuration = {} } = component; - const { data: { branchLikes, branchLike } = { branchLikes: [] } } = useBranchesQuery(component); + + const { data: branchLikes = [] } = useBranchesQuery(component); + const { data: branchLike } = useCurrentBranchQuery(component); + const isApplicationChildInaccessble = isApplication(qualifier) && !canBrowseAllChildProjects; const location = useLocation(); diff --git a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/BranchLikeNavigation.tsx b/server/sonar-web/src/main/js/app/components/nav/component/branch-like/BranchLikeNavigation.tsx index e4cd9332aa9..86f2fcf9d8a 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/BranchLikeNavigation.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/branch-like/BranchLikeNavigation.tsx @@ -25,7 +25,7 @@ import { ComponentQualifier } from '~sonar-aligned/types/component'; import EscKeydownHandler from '../../../../../components/controls/EscKeydownHandler'; import FocusOutHandler from '../../../../../components/controls/FocusOutHandler'; import OutsideClickHandler from '../../../../../components/controls/OutsideClickHandler'; -import { useBranchesQuery } from '../../../../../queries/branch'; +import { useBranchesQuery, useCurrentBranchQuery } from '../../../../../queries/branch'; import { Feature } from '../../../../../types/features'; import { Component } from '../../../../../types/types'; import withAvailableFeatures, { @@ -46,8 +46,9 @@ export function BranchLikeNavigation(props: BranchLikeNavigationProps) { component: { configuration }, } = props; - const { data: { branchLikes, branchLike: currentBranchLike } = { branchLikes: [] } } = - useBranchesQuery(component); + const { data: branchLikes } = useBranchesQuery(component); + const { data: currentBranchLike } = useCurrentBranchQuery(component); + const [isMenuOpen, setIsMenuOpen] = React.useState(false); if (currentBranchLike === undefined) { 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 e91bfd4b08d..5c5e4384619 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 @@ -17,15 +17,16 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import { Spinner } from '@sonarsource/echoes-react'; import * as React from 'react'; import { withRouter } from '~sonar-aligned/components/hoc/withRouter'; -import { isPortfolioLike } from '~sonar-aligned/helpers/component'; import { ComponentQualifier } from '~sonar-aligned/types/component'; import { Location, Router } from '~sonar-aligned/types/router'; import withComponentContext from '../../../app/components/componentContext/withComponentContext'; import withMetricsContext from '../../../app/components/metrics/withMetricsContext'; +import { isDefined } from '../../../helpers/types'; import { CodeScope, getCodeUrl, getProjectUrl } from '../../../helpers/urls'; -import { WithBranchLikesProps, useBranchesQuery } from '../../../queries/branch'; +import { WithBranchLikesProps, useCurrentBranchQuery } from '../../../queries/branch'; import { useComponentBreadcrumbsQuery, useComponentQuery } from '../../../queries/component'; import { useComponentTreeQuery } from '../../../queries/measures'; import { getBranchLikeQuery } from '../../../sonar-aligned/helpers/branch-like'; @@ -33,7 +34,7 @@ import { Component, ComponentMeasure, Dict, Metric } from '../../../types/types' import { getCodeMetrics } from '../utils'; import CodeAppRenderer from './CodeAppRenderer'; -interface Props extends WithBranchLikesProps { +interface Props { component: Component; location: Location; metrics: Dict; @@ -43,11 +44,13 @@ interface Props extends WithBranchLikesProps { const PAGE_SIZE = 100; function CodeApp(props: Readonly) { - const { component, metrics, router, location, branchLike } = props; + const { component, metrics, router, location } = props; const [highlighted, setHighlighted] = React.useState(); const [newCodeSelected, setNewCodeSelected] = React.useState(true); const [searchResults, setSearchResults] = React.useState(); + const { data: branchLike } = useCurrentBranchQuery(component); + const { data: breadcrumbs, isLoading: isBreadcrumbsLoading } = useComponentBreadcrumbsQuery({ component: location.query.selected ?? component.key, ...getBranchLikeQuery(branchLike), @@ -161,22 +164,16 @@ function CodeApp(props: Readonly) { ); } -function withBranchLikes

( +function withComponentGuard

( WrappedComponent: React.ComponentType>, ): React.ComponentType>> { - return function WithBranchLike(p: P) { - const { data, isFetching } = useBranchesQuery(p.component); - + return function WithBranchLike(props: P) { return ( - (isPortfolioLike(p.component?.qualifier) || !isFetching) && ( - - ) + + + ); }; } -export default withRouter(withComponentContext(withMetricsContext(withBranchLikes(CodeApp)))); +export default withRouter(withComponentContext(withMetricsContext(withComponentGuard(CodeApp)))); 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 af0e880606f..bd7e35b6aa6 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 @@ -48,8 +48,9 @@ import { areCCTMeasuresComputed, areSoftwareQualityRatingsComputed, } from '../../../helpers/measures'; -import { useBranchesQuery } from '../../../queries/branch'; +import { useCurrentBranchQuery } from '../../../queries/branch'; import { useMeasuresComponentQuery } from '../../../queries/measures'; + import { MeasurePageView } from '../../../types/measures'; import { useBubbleChartMetrics } from '../hooks'; import Sidebar from '../sidebar/Sidebar'; @@ -73,7 +74,7 @@ import MeasuresEmpty from './MeasuresEmpty'; export default function ComponentMeasuresApp() { const { component } = React.useContext(ComponentContext); - const { data: { branchLike } = {} } = useBranchesQuery(component); + const { data: branchLike } = useCurrentBranchQuery(component); const { query: rawQuery, pathname } = useLocation(); const query = parseQuery(rawQuery); const router = useRouter(); diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureContent.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureContent.tsx index e3dd0120797..95165e1448a 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureContent.tsx +++ b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureContent.tsx @@ -34,7 +34,7 @@ import { getCCTMeasureValue, isDiffMetric } from '../../../helpers/measures'; import { RequestData } from '../../../helpers/request'; import { isDefined } from '../../../helpers/types'; import { getProjectUrl } from '../../../helpers/urls'; -import { useBranchesQuery } from '../../../queries/branch'; +import { useCurrentBranchQuery } from '../../../queries/branch'; import { useComponentTreeQuery, useMeasuresComponentQuery } from '../../../queries/measures'; import { useIsLegacyCCTMode } from '../../../queries/settings'; import { useLocation, useRouter } from '../../../sonar-aligned/components/hoc/withRouter'; @@ -68,7 +68,7 @@ export default function MeasureContent(props: Readonly) { const { leakPeriod, requestedMetric, rootComponent, updateQuery } = props; const metrics = useMetrics(); const { query: rawQuery } = useLocation(); - const { data: { branchLike } = {} } = useBranchesQuery(); + const { data: branchLike } = useCurrentBranchQuery(rootComponent); const router = useRouter(); const query = parseQuery(rawQuery); const { data: isLegacy } = useIsLegacyCCTMode(); diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverview.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverview.tsx index 52ad7565a03..6a939589dc3 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverview.tsx +++ b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverview.tsx @@ -22,7 +22,7 @@ import * as React from 'react'; import { useMetrics } from '../../../app/components/metrics/withMetricsContext'; import SourceViewer from '../../../components/SourceViewer/SourceViewer'; import { getProjectUrl } from '../../../helpers/urls'; -import { useBranchesQuery } from '../../../queries/branch'; +import { useCurrentBranchQuery } from '../../../queries/branch'; import { useComponentDataQuery } from '../../../queries/component'; import { useComponentTreeQuery } from '../../../queries/measures'; import A11ySkipTarget from '../../../sonar-aligned/components/a11y/A11ySkipTarget'; @@ -54,7 +54,7 @@ interface Props { export default function MeasureOverview(props: Readonly) { const { leakPeriod, updateQuery, rootComponent, bubblesByDomain } = props; const metrics = useMetrics(); - const { data: { branchLike } = {} } = useBranchesQuery(); + const { data: branchLike } = useCurrentBranchQuery(rootComponent); const router = useRouter(); const { query } = useLocation(); const { selected, metric: domain } = parseQuery(query); diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/SubnavigationMeasureValue.tsx b/server/sonar-web/src/main/js/apps/component-measures/sidebar/SubnavigationMeasureValue.tsx index d6c55e29188..368ceb42fb4 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/sidebar/SubnavigationMeasureValue.tsx +++ b/server/sonar-web/src/main/js/apps/component-measures/sidebar/SubnavigationMeasureValue.tsx @@ -20,8 +20,9 @@ import { Note } from 'design-system'; import React from 'react'; import Measure from '~sonar-aligned/components/measure/Measure'; +import { useComponent } from '../../../app/components/componentContext/withComponentContext'; import { isDiffMetric } from '../../../helpers/measures'; -import { useBranchesQuery } from '../../../queries/branch'; +import { useCurrentBranchQuery } from '../../../queries/branch'; import { MeasureEnhanced } from '../../../types/types'; interface Props { @@ -30,8 +31,10 @@ interface Props { } export default function SubnavigationMeasureValue({ measure, componentKey }: Readonly) { + const { component } = useComponent(); + const isDiff = isDiffMetric(measure.metric.key); - const { data: { branchLike } = {} } = useBranchesQuery(); + const { data: branchLike } = useCurrentBranchQuery(component); const value = isDiff ? measure.leak : measure.value; return ( diff --git a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/IssueSourceViewerHeader.tsx b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/IssueSourceViewerHeader.tsx index 58ce845ca3e..08c95db1ca8 100644 --- a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/IssueSourceViewerHeader.tsx +++ b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/IssueSourceViewerHeader.tsx @@ -40,7 +40,7 @@ import { DEFAULT_ISSUES_QUERY } from '../../../components/shared/utils'; import { translate } from '../../../helpers/l10n'; import { collapsedDirFromPath, fileFromPath } from '../../../helpers/path'; import { getBranchLikeUrl } from '../../../helpers/urls'; -import { useBranchesQuery } from '../../../queries/branch'; +import { useCurrentBranchQuery } from '../../../queries/branch'; import { SourceViewerFile } from '../../../types/types'; import { isLoggedIn } from '../../../types/users'; import { IssueOpenInIdeButton } from '../components/IssueOpenInIdeButton'; @@ -79,7 +79,7 @@ export function IssueSourceViewerHeader(props: Readonly) { const { measures, path, project, projectName, q } = sourceViewerFile; const { component } = React.useContext(ComponentContext); - const { data: branchData, isLoading: isLoadingBranches } = useBranchesQuery( + const { data: branchLike, isLoading: isLoadingBranches } = useCurrentBranchQuery( component ?? { key: project, name: projectName, @@ -89,8 +89,6 @@ export function IssueSourceViewerHeader(props: Readonly) { const { currentUser } = useCurrentUser(); const theme = useTheme(); - const branchLike = branchData?.branchLike; - const isProjectRoot = q === ComponentQualifier.Project; const borderColor = themeColor('codeLineBorder')({ theme }); diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-it.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-it.tsx index e79b7b7126a..4a99bdfa447 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-it.tsx +++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-it.tsx @@ -61,6 +61,10 @@ let usersHandler: UsersServiceMock; let timeMarchineHandler: TimeMachineServiceMock; let qualityGatesHandler: QualityGatesServiceMock; +jest.mock('../../../../api/ce', () => ({ + getAnalysisStatus: jest.fn().mockResolvedValue({ component: { warnings: [] } }), +})); + beforeAll(() => { branchesHandler = new BranchesServiceMock(); measuresHandler = new MeasuresServiceMock(); diff --git a/server/sonar-web/src/main/js/apps/overview/components/AnalysisErrorMessage.tsx b/server/sonar-web/src/main/js/apps/overview/components/AnalysisErrorMessage.tsx index 212cb7725c1..a5daa75ba3d 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/AnalysisErrorMessage.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/AnalysisErrorMessage.tsx @@ -24,7 +24,7 @@ import { useLocation } from 'react-router-dom'; import { isBranch, isMainBranch, isPullRequest } from '~sonar-aligned/helpers/branch-like'; import { hasMessage, translate } from '../../../helpers/l10n'; import { getComponentBackgroundTaskUrl } from '../../../helpers/urls'; -import { useBranchesQuery } from '../../../queries/branch'; +import { useCurrentBranchQuery } from '../../../queries/branch'; import { BranchLike } from '../../../types/branch-like'; import { Task } from '../../../types/tasks'; import { Component } from '../../../types/types'; @@ -52,7 +52,7 @@ function isSameBranch(task: Task, branchLike?: BranchLike) { export function AnalysisErrorMessage(props: Props) { const { component, currentTask } = props; - const { data: { branchLike } = {} } = useBranchesQuery(component); + const { data: branchLike } = useCurrentBranchQuery(component); const currentTaskOnSameBranch = isSameBranch(currentTask, branchLike); const location = useLocation(); diff --git a/server/sonar-web/src/main/js/apps/overview/components/AnalysisWarningsModal.tsx b/server/sonar-web/src/main/js/apps/overview/components/AnalysisWarningsModal.tsx index 3efcac9115c..5a4daac6b9e 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/AnalysisWarningsModal.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/AnalysisWarningsModal.tsx @@ -38,7 +38,7 @@ interface Props { export function AnalysisWarningsModal(props: Props) { const { component, currentUser, warnings } = props; - const { mutate, isPending, variables } = useDismissBranchWarningMutation(); + const { mutate, isPending, variables } = useDismissBranchWarningMutation(component.key); const handleDismissMessage = (messageKey: string) => { mutate({ component, key: messageKey }); diff --git a/server/sonar-web/src/main/js/apps/overview/components/App.tsx b/server/sonar-web/src/main/js/apps/overview/components/App.tsx index ead3f2d259e..89e87134d9a 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/App.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/App.tsx @@ -28,7 +28,7 @@ import withAvailableFeatures, { import withComponentContext from '../../../app/components/componentContext/withComponentContext'; import Suggestions from '../../../components/embed-docs-modal/Suggestions'; import { translate } from '../../../helpers/l10n'; -import { useBranchesQuery } from '../../../queries/branch'; +import { useCurrentBranchQuery } from '../../../queries/branch'; import { Feature } from '../../../types/features'; import { Component } from '../../../types/types'; import BranchOverview from '../branches/BranchOverview'; @@ -42,14 +42,12 @@ interface AppProps extends WithAvailableFeaturesProps { export function App(props: AppProps) { const { component } = props; const branchSupportEnabled = props.hasFeature(Feature.BranchSupport); - const { data } = useBranchesQuery(component); + const { data: branchLike } = useCurrentBranchQuery(component); - if (isPortfolioLike(component.qualifier) || !data) { + if (isPortfolioLike(component.qualifier) || !branchLike) { return null; } - const { branchLike, branchLikes } = data; - return ( <> @@ -63,11 +61,7 @@ export function App(props: AppProps) { {!component.analysisDate && ( - + )} {component.analysisDate && ( diff --git a/server/sonar-web/src/main/js/apps/overview/components/EmptyOverview.tsx b/server/sonar-web/src/main/js/apps/overview/components/EmptyOverview.tsx index a8df895e419..3f52c59c316 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/EmptyOverview.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/EmptyOverview.tsx @@ -31,6 +31,7 @@ import { getBranchLikeDisplayName } from '../../../helpers/branch-like'; import { translate, translateWithParameters } from '../../../helpers/l10n'; import { getProjectTutorialLocation } from '../../../helpers/urls'; import { hasGlobalPermission } from '../../../helpers/users'; +import { useBranchesQuery } from '../../../queries/branch'; import { useTaskForComponentQuery } from '../../../queries/component'; import { AlmKeys } from '../../../types/alm-settings'; import { BranchLike } from '../../../types/branch-like'; @@ -41,13 +42,14 @@ import { CurrentUser, isLoggedIn } from '../../../types/users'; export interface EmptyOverviewProps { branchLike?: BranchLike; - branchLikes: BranchLike[]; component: Component; currentUser: CurrentUser; } export function EmptyOverview(props: Readonly) { - const { branchLike, branchLikes, component, currentUser } = props; + const { branchLike, component, currentUser } = props; + + const { data: branchLikes } = useBranchesQuery(component); const [currentUserCanScanProject, setCurrentUserCanScanProject] = React.useState( hasGlobalPermission(currentUser, Permissions.Scan), diff --git a/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/PullRequestOverview-it.tsx b/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/PullRequestOverview-it.tsx index 5aecfd6063b..f6952019b2b 100644 --- a/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/PullRequestOverview-it.tsx +++ b/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/PullRequestOverview-it.tsx @@ -39,6 +39,10 @@ import { CaycStatus } from '../../../../types/types'; import { NoticeType } from '../../../../types/users'; import PullRequestOverview from '../PullRequestOverview'; +jest.mock('../../../../api/ce', () => ({ + getAnalysisStatus: jest.fn().mockResolvedValue({ component: { warnings: [] } }), +})); + jest.mock('../../../../api/measures', () => { return { ...jest.requireActual('../../../../sonar-aligned/types/metrics'), 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 ee3b1c026d0..21cc693dd84 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 @@ -35,7 +35,7 @@ import { mergeRatingMeasureHistory } from '../../../helpers/activity-graph'; import { SOFTWARE_QUALITY_RATING_METRICS } from '../../../helpers/constants'; import { parseDate } from '../../../helpers/dates'; import useApplicationLeakQuery from '../../../queries/applications'; -import { useBranchesQuery } from '../../../queries/branch'; +import { useCurrentBranchQuery } from '../../../queries/branch'; import { useAllMeasuresHistoryQuery } from '../../../queries/measures'; import { useAllProjectAnalysesQuery } from '../../../queries/project-analyses'; import { useIsLegacyCCTMode } from '../../../queries/settings'; @@ -62,7 +62,7 @@ export function ProjectActivityApp() { const router = useRouter(); const { component } = useComponent(); const metrics = useMetrics(); - const { data: { branchLike } = {}, isFetching: isFetchingBranch } = useBranchesQuery(component); + const { data: branchLike, isFetching: isFetchingBranch } = useCurrentBranchQuery(component); const enabled = component?.key !== undefined && (isPortfolioLike(component?.qualifier) || (Boolean(branchLike) && !isFetchingBranch)); diff --git a/server/sonar-web/src/main/js/apps/projectBranches/components/BranchLikeTabs.tsx b/server/sonar-web/src/main/js/apps/projectBranches/components/BranchLikeTabs.tsx index d7d49d8fad1..51aaf5af4de 100644 --- a/server/sonar-web/src/main/js/apps/projectBranches/components/BranchLikeTabs.tsx +++ b/server/sonar-web/src/main/js/apps/projectBranches/components/BranchLikeTabs.tsx @@ -92,7 +92,7 @@ export default function BranchLikeTabs(props: Props) { } }; - const { data: { branchLikes } = { branchLikes: [] } } = useBranchesQuery(component); + const { data: branchLikes = [] } = useBranchesQuery(component); const isBranchMode = currentTab === Tabs.Branch; const branchLikesToDisplay: BranchLike[] = isBranchMode diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotHeader.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotHeader.tsx index 72771d94b84..a1ad559a864 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotHeader.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotHeader.tsx @@ -49,7 +49,7 @@ export interface HotspotHeaderProps { export function HotspotHeader(props: HotspotHeaderProps) { const { branchLike, component, hotspot, standards } = props; const { message, messageFormattings, rule, key } = hotspot; - const refreshBranchStatus = useRefreshBranchStatus(); + const refreshBranchStatus = useRefreshBranchStatus(component.key); const permalink = getPathUrlAsString( getComponentSecurityHotspotsUrl(component.key, branchLike, { diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerTabs.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerTabs.tsx index 22801e6f3f5..5044e1aba97 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerTabs.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerTabs.tsx @@ -80,7 +80,7 @@ export default function HotspotViewerTabs(props: Props) { branchLike, } = props; - const refreshBranchStatus = useRefreshBranchStatus(); + const refreshBranchStatus = useRefreshBranchStatus(component.key); const isSticky = useStickyDetection('.hotspot-tabs', { offset: TABS_OFFSET, }); diff --git a/server/sonar-web/src/main/js/components/activity-graph/EventInner.tsx b/server/sonar-web/src/main/js/components/activity-graph/EventInner.tsx index 3996d5e2125..68d72ffc5b9 100644 --- a/server/sonar-web/src/main/js/components/activity-graph/EventInner.tsx +++ b/server/sonar-web/src/main/js/components/activity-graph/EventInner.tsx @@ -21,7 +21,7 @@ import { Note } from 'design-system'; import * as React from 'react'; import { ComponentContext } from '../../app/components/componentContext/ComponentContext'; import { translate } from '../../helpers/l10n'; -import { useBranchesQuery } from '../../queries/branch'; +import { useCurrentBranchQuery } from '../../queries/branch'; import { AnalysisEvent, ProjectAnalysisEventCategory } from '../../types/project-activity'; import Tooltip from '../controls/Tooltip'; import { DefinitionChangeEventInner, isDefinitionChangeEvent } from './DefinitionChangeEventInner'; @@ -39,7 +39,7 @@ export interface EventInnerProps { export default function EventInner({ event, readonly }: EventInnerProps) { const { component } = React.useContext(ComponentContext); - const { data: { branchLike } = {} } = useBranchesQuery(component); + const { data: branchLike } = useCurrentBranchQuery(component); if (isRichQualityGateEvent(event)) { return ; } else if (isDefinitionChangeEvent(event)) { 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 980f08ef931..5a9d5807fbf 100644 --- a/server/sonar-web/src/main/js/components/issue/Issue.tsx +++ b/server/sonar-web/src/main/js/components/issue/Issue.tsx @@ -21,6 +21,7 @@ import { flow } from 'lodash'; import * as React from 'react'; import { useCallback } from 'react'; import { setIssueAssignee } from '../../api/issues'; +import { useComponent } from '../../app/components/componentContext/withComponentContext'; import { isInput, isShortcut } from '../../helpers/keyboardEventHelpers'; import { KeyboardKeys } from '../../helpers/keycodes'; import { getKeyboardShortcutEnabled } from '../../helpers/preferences'; @@ -55,7 +56,9 @@ export default function Issue(props: Props) { onPopupToggle, } = props; - const refreshStatus = useRefreshBranchStatus(); + const { component } = useComponent(); + + const refreshStatus = useRefreshBranchStatus(component?.key); const onChange = flow([props.onChange, refreshStatus]); diff --git a/server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx b/server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx index 8209418f3cd..d45e49f4606 100644 --- a/server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx +++ b/server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx @@ -98,7 +98,7 @@ export default function TutorialSelectionRenderer(props: TutorialSelectionRender willRefreshAutomatically, } = props; - const { data: { branchLikes } = { branchLikes: [] } } = useBranchesQuery(component); + const { data: branchLikes = [] } = useBranchesQuery(component); const mainBranchName = (branchLikes.find((b) => isMainBranch(b)) as MainBranch | undefined)?.name || diff --git a/server/sonar-web/src/main/js/queries/branch.tsx b/server/sonar-web/src/main/js/queries/branch.tsx index 5b6fd07edbc..6c25f797988 100644 --- a/server/sonar-web/src/main/js/queries/branch.tsx +++ b/server/sonar-web/src/main/js/queries/branch.tsx @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { queryOptions, useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { debounce, flatten } from 'lodash'; import * as React from 'react'; import { useCallback, useContext } from 'react'; @@ -39,14 +39,14 @@ import { import { dismissAnalysisWarning, getAnalysisStatus } from '../api/ce'; import { getQualityGateProjectStatus } from '../api/quality-gates'; import { AvailableFeaturesContext } from '../app/components/available-features/AvailableFeaturesContext'; +import { useComponent } from '../app/components/componentContext/withComponentContext'; import { extractStatusConditionsFromProjectStatus } from '../helpers/qualityGates'; +import { isDefined } from '../helpers/types'; import { Branch, BranchLike } from '../types/branch-like'; import { isApplication, isProject } from '../types/component'; import { Feature } from '../types/features'; import { Component } from '../types/types'; - -// This will prevent refresh when navigating from page to page. -const BRANCHES_STALE_TIME = 30_000; +import { StaleTime } from './common'; enum InnerState { Details = 'details', @@ -54,7 +54,11 @@ enum InnerState { Status = 'status', } -function useBranchesQueryKey(innerState: InnerState, defaultId?: string) { +/** + * @deprecated This is a legacy way of organizing branch keys + * It was introduced as a step to remove branch fetching from ComponentContainer. + */ +function useBranchesQueryKey(innerState: InnerState, componentKey?: string) { // Currently, we do not have the component in a react-state ready // Once we refactor we will be able to fetch it from query state. // We will be able to make sure that the component is not a portfolio. @@ -63,38 +67,72 @@ function useBranchesQueryKey(innerState: InnerState, defaultId?: string) { const { search } = useLocation(); const searchParams = new URLSearchParams(search); - if (searchParams.has('pullRequest') && searchParams.has('id')) { + if (!isDefined(componentKey)) { + return ['branches']; + } + + if (searchParams.has('pullRequest')) { return [ 'branches', - searchParams.get('id') as string, + componentKey, 'pull-request', searchParams.get('pullRequest') as string, innerState, ] as const; - } else if (searchParams.has('branch') && searchParams.has('id')) { + } + + if (searchParams.has('branch')) { return [ 'branches', - searchParams.get('id') as string, + componentKey, 'branch', searchParams.get('branch') as string, innerState, ] as const; - } else if (searchParams.has('fixedInPullRequest') && searchParams.has('id')) { + } + + if (searchParams.has('fixedInPullRequest')) { return [ 'branches', - searchParams.get('id') as string, + componentKey, 'fixedInPullRequest', searchParams.get('fixedInPullRequest') as string, innerState, ] as const; - } else if (searchParams.has('id')) { - return ['branches', searchParams.get('id') as string, innerState] as const; - } else if (defaultId !== undefined) { - return ['branches', defaultId, innerState]; } - return ['branches']; + + return ['branches', componentKey, innerState] as const; } +function branchesQuery( + component: LightComponent | undefined, + branchSupportFeatureEnabled: boolean, +) { + return queryOptions({ + // we don't care about branchSupportFeatureEnabled in the key, as it never changes during a user session + queryKey: ['branches', 'list', component?.key], + queryFn: async ({ queryKey: [, , key] }) => { + if (component === undefined || key === undefined || isPortfolioLike(component.qualifier)) { + return [] as BranchLike[]; + } + + // Pull Requests exist only for projects and if [branch-support] is enabled + const branchLikesPromise = + isProject(component.qualifier) && branchSupportFeatureEnabled + ? [getBranches(key), getPullRequests(key)] + : [getBranches(key)]; + const branchLikes = await Promise.all(branchLikesPromise).then(flatten); + + return branchLikes; + }, + enabled: isDefined(component), + }); +} + +/** + * @deprecated This is a legacy way of organizing branch keys + * It was introduce as a step to remove branch fetching from ComponentContainer. + */ function useMutateBranchQueryKey() { const { search } = useLocation(); const searchParams = new URLSearchParams(search); @@ -119,53 +157,55 @@ function getContext(key: ReturnType, branchLike?: Br return { componentKey, query: {} }; } -export function useBranchesQuery(component?: LightComponent, refetchInterval?: number) { +export function useBranchesQuery(component: LightComponent | undefined) { const features = useContext(AvailableFeaturesContext); - const key = useBranchesQueryKey(InnerState.Details, component?.key); return useQuery({ - queryKey: key, - queryFn: async ({ queryKey: [, key, prOrBranch, name] }) => { - if (component === undefined || key === undefined) { - return { branchLikes: [] }; - } - if (isPortfolioLike(component.qualifier)) { - return { branchLikes: [] }; - } - - const branchLikesPromise = - isProject(component.qualifier) && features.includes(Feature.BranchSupport) - ? [getBranches(key), getPullRequests(key)] - : [getBranches(key)]; - const branchLikes = await Promise.all(branchLikesPromise).then(flatten); + ...branchesQuery(component, features.includes(Feature.BranchSupport)), + initialData: [], + staleTime: StaleTime.SHORT, + }); +} - let branchLike = branchLikes.find((b) => isBranch(b) && b.isMain); +export function useCurrentBranchQuery(component: LightComponent | undefined) { + const features = useContext(AvailableFeaturesContext); + const { search } = useLocation(); - if (prOrBranch === 'pull-request') { - branchLike = branchLikes.find((b) => isPullRequest(b) && b.key === name); - } else if (prOrBranch === 'branch') { - branchLike = branchLikes.find((b) => isBranch(b) && b.name === name); - } else if (prOrBranch === 'fixedInPullRequest') { - const targetBranch = branchLikes.filter(isPullRequest).find((b) => b.key === name)?.target; - branchLike = branchLikes.find((b) => isBranch(b) && b.name === targetBranch); + const select = useCallback( + (branchLikes: BranchLike[]) => { + const searchParams = new URLSearchParams(search); + if (searchParams.has('branch')) { + return branchLikes.find((b) => isBranch(b) && b.name === searchParams.get('branch')); + } else if (searchParams.has('pullRequest')) { + return branchLikes.find( + (b) => isPullRequest(b) && b.key === searchParams.get('pullRequest'), + ); + } else if (searchParams.has('fixedInPullRequest')) { + const targetBranch = branchLikes + .filter(isPullRequest) + .find((b) => b.key === searchParams.get('fixedInPullRequest'))?.target; + return branchLikes.find((b) => isBranch(b) && b.name === targetBranch); } - return { branchLikes, branchLike }; + return branchLikes.find((b) => isBranch(b) && b.isMain); }, - // The check of the key must disappear once component state is in react-query - enabled: !!component && component.key === key[1], - staleTime: refetchInterval ?? BRANCHES_STALE_TIME, - refetchInterval, + [search], + ); + + return useQuery({ + ...branchesQuery(component, features.includes(Feature.BranchSupport)), + select, + staleTime: StaleTime.LIVE, }); } export function useBranchStatusQuery(component: Component) { - const branchQuery = useBranchesQuery(component); - const key = useBranchesQueryKey(InnerState.Status); + const { data: branchLike } = useCurrentBranchQuery(component); + const key = useBranchesQueryKey(InnerState.Status, component.key); return useQuery({ queryKey: key, queryFn: async ({ queryKey }) => { - const { query } = getContext(queryKey, branchQuery.data?.branchLike); + const { query } = getContext(queryKey, branchLike); if (!isProject(component.qualifier)) { return {}; } @@ -186,14 +226,13 @@ export function useBranchStatusQuery(component: Component) { }; }, enabled: isProject(component.qualifier) || isApplication(component.qualifier), - staleTime: BRANCHES_STALE_TIME, + staleTime: StaleTime.SHORT, }); } export function useBranchWarningQuery(component: Component) { - const branchQuery = useBranchesQuery(component); - const branchLike = branchQuery.data?.branchLike; - const key = useBranchesQueryKey(InnerState.Warning); + const { data: branchLike } = useCurrentBranchQuery(component); + const key = useBranchesQueryKey(InnerState.Warning, component.key); return useQuery({ queryKey: key, queryFn: async ({ queryKey }) => { @@ -205,20 +244,21 @@ export function useBranchWarningQuery(component: Component) { return branchStatus.warnings; }, enabled: !!branchLike && isProject(component.qualifier) && component.key === key[1], - staleTime: BRANCHES_STALE_TIME, + staleTime: StaleTime.SHORT, }); } -export function useDismissBranchWarningMutation() { +export function useDismissBranchWarningMutation(componentKey: string | undefined) { type DismissArg = { component: Component; key: string }; const queryClient = useQueryClient(); - const invalidateKey = useBranchesQueryKey(InnerState.Warning); + const invalidateKey = useBranchesQueryKey(InnerState.Warning, componentKey); return useMutation({ mutationFn: async ({ component, key }: DismissArg) => { await dismissAnalysisWarning(component.key, key); }, - onSuccess() { + onSuccess(_1, { component }) { + queryClient.invalidateQueries({ queryKey: ['branches', 'list', component.key] }); queryClient.invalidateQueries({ queryKey: invalidateKey }); }, }); @@ -234,7 +274,8 @@ export function useExcludeFromPurgeMutation() { mutationFn: async ({ component, key, exclude }: ExcludeFromPurgeArg) => { await excludeBranchFromPurge(component.key, key, exclude); }, - onSuccess() { + onSuccess(_1, { component }) { + queryClient.invalidateQueries({ queryKey: ['branches', 'list', component.key] }); queryClient.invalidateQueries({ queryKey: invalidateKey }); }, }); @@ -277,8 +318,9 @@ export function useDeletBranchMutation() { } return { navigate: false }; }, - onSuccess({ navigate }) { + onSuccess({ navigate }, { component }) { if (!navigate) { + queryClient.invalidateQueries({ queryKey: ['branches', 'list', component.key] }); queryClient.invalidateQueries({ queryKey: invalidateKey }); } }, @@ -294,7 +336,8 @@ export function useRenameMainBranchMutation() { mutationFn: async ({ component, name }: RenameMainBranchArg) => { await renameBranch(component.key, name); }, - onSuccess() { + onSuccess(_1, { component }) { + queryClient.invalidateQueries({ queryKey: ['branches', 'list', component.key] }); queryClient.invalidateQueries({ queryKey: invalidateKey }); }, }); @@ -309,7 +352,8 @@ export function useSetMainBranchMutation() { mutationFn: async ({ component, branchName }: SetAsMainBranchArg) => { await setMainBranch(component.key, branchName); }, - onSuccess() { + onSuccess(_1, { component }) { + queryClient.invalidateQueries({ queryKey: ['branches', 'list', component.key] }); queryClient.invalidateQueries({ queryKey: invalidateKey }); }, }); @@ -321,13 +365,14 @@ export function useSetMainBranchMutation() { */ const REFRESH_INTERVAL = 1_000; -export function useRefreshBranchStatus(): () => void { +export function useRefreshBranchStatus(componentKey: string | undefined): () => void { const queryClient = useQueryClient(); - const invalidateStatusKey = useBranchesQueryKey(InnerState.Status); - const invalidateDetailsKey = useBranchesQueryKey(InnerState.Details); + const invalidateStatusKey = useBranchesQueryKey(InnerState.Status, componentKey); + const invalidateDetailsKey = useBranchesQueryKey(InnerState.Details, componentKey); return useCallback( debounce(() => { + queryClient.invalidateQueries({ queryKey: ['branches', 'list', componentKey] }); queryClient.invalidateQueries({ queryKey: invalidateStatusKey, }); @@ -339,11 +384,12 @@ export function useRefreshBranchStatus(): () => void { ); } -export function useRefreshBranches() { +export function useRefreshBranches(componentKey: string | undefined) { const queryClient = useQueryClient(); const invalidateKey = useMutateBranchQueryKey(); return () => { + queryClient.invalidateQueries({ queryKey: ['branches', 'list', componentKey] }); queryClient.invalidateQueries({ queryKey: invalidateKey }); }; } @@ -358,12 +404,13 @@ export function withBranchLikes

( WrappedComponent: React.ComponentType>, ): React.ComponentType>> { return function WithBranchLike(p: P) { - const { data, isFetching } = useBranchesQuery(p.component); + const { data: branchLikes, isLoading } = useBranchesQuery(p.component); + const { data: branchLike, isFetching } = useCurrentBranchQuery(p.component); return ( ); @@ -376,7 +423,8 @@ export function withBranchStatusRefresh< WrappedComponent: React.ComponentType>, ): React.ComponentType>> { return function WithBranchStatusRefresh(props: P) { - const refresh = useRefreshBranchStatus(); + const { component } = useComponent(); + const refresh = useRefreshBranchStatus(component?.key); return ; }; diff --git a/server/sonar-web/src/main/js/queries/project-analyses.ts b/server/sonar-web/src/main/js/queries/project-analyses.ts index 02186c97420..ee6fe2a0e73 100644 --- a/server/sonar-web/src/main/js/queries/project-analyses.ts +++ b/server/sonar-web/src/main/js/queries/project-analyses.ts @@ -37,14 +37,14 @@ import { import { parseDate } from '../helpers/dates'; import { serializeStringArray } from '../helpers/query'; import { ParsedAnalysis } from '../types/project-activity'; -import { useBranchesQuery } from './branch'; +import { useCurrentBranchQuery } from './branch'; const ACTIVITY_PAGE_SIZE = 500; function useProjectActivityQueryKey() { const { component } = useComponent(); const componentKey = useTopLevelComponentKey(); - const { data: { branchLike } = {} } = useBranchesQuery(component); + const { data: branchLike } = useCurrentBranchQuery(component); const branchParams = getBranchLikeQuery(branchLike); return ['activity', 'list', componentKey, branchParams] as [ -- 2.39.5