From cbb3b4fe0351462a3c8cacdd3f6ea18c10b956d3 Mon Sep 17 00:00:00 2001 From: Mathieu Suen Date: Tue, 3 Oct 2023 17:06:07 +0200 Subject: [PATCH] SONAR-20655 Redirect to the first branch being analysed when on tutorials page --- .../tutorials/TutorialSelectionRenderer.tsx | 26 ++++++++++++++++--- .../__tests__/TutorialSelection-it.tsx | 11 +++++--- .../sonar-web/src/main/js/queries/branch.tsx | 5 ++-- 3 files changed, 34 insertions(+), 8 deletions(-) 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 2c78e3da34d..0cd87ad6b9e 100644 --- a/server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx +++ b/server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx @@ -28,13 +28,14 @@ import { Title, } from 'design-system'; import * as React from 'react'; -import { isMainBranch } from '../../helpers/branch-like'; +import { useNavigate } from 'react-router-dom'; +import { getBranchLikeQuery, isMainBranch } from '../../helpers/branch-like'; import { translate } from '../../helpers/l10n'; import { getBaseUrl } from '../../helpers/system'; import { getProjectTutorialLocation } from '../../helpers/urls'; import { useBranchesQuery } from '../../queries/branch'; import { AlmKeys, AlmSettingsInstance, ProjectAlmBindingResponse } from '../../types/alm-settings'; -import { MainBranch } from '../../types/branch-like'; +import { BranchLike, MainBranch } from '../../types/branch-like'; import { Component } from '../../types/types'; import { LoggedInUser } from '../../types/users'; import { Alert } from '../ui/Alert'; @@ -81,6 +82,8 @@ function renderAlm(mode: TutorialModes, project: string, icon?: React.ReactNode) ); } +const CHECKING_NEW_BRANCH = 5_000; + export default function TutorialSelectionRenderer(props: TutorialSelectionRendererProps) { const { almBinding, @@ -94,7 +97,24 @@ export default function TutorialSelectionRenderer(props: TutorialSelectionRender willRefreshAutomatically, } = props; - const { data: { branchLikes } = { branchLikes: [] } } = useBranchesQuery(component); + const { data: { branchLikes } = { branchLikes: [] as BranchLike[] } } = useBranchesQuery( + component, + CHECKING_NEW_BRANCH, + ); + + const navigate = useNavigate(); + + const firstAnalysedBranch = branchLikes.find((b) => b.analysisDate !== undefined); + + if (firstAnalysedBranch) { + navigate({ + pathname: '/dashboard', + search: new URLSearchParams({ + id: component.key, + ...getBranchLikeQuery(firstAnalysedBranch), + }).toString(), + }); + } const mainBranchName = (branchLikes.find((b) => isMainBranch(b)) as MainBranch | undefined)?.name || diff --git a/server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelection-it.tsx b/server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelection-it.tsx index c8a296e6bbb..636bce0f5de 100644 --- a/server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelection-it.tsx +++ b/server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelection-it.tsx @@ -23,6 +23,7 @@ import { UserEvent } from '@testing-library/user-event/dist/types/setup/setup'; import * as React from 'react'; import { getScannableProjects } from '../../../api/components'; import AlmSettingsServiceMock from '../../../api/mocks/AlmSettingsServiceMock'; +import BranchesServiceMock from '../../../api/mocks/BranchesServiceMock'; import SettingsServiceMock from '../../../api/mocks/SettingsServiceMock'; import UserTokensMock from '../../../api/mocks/UserTokensMock'; import { mockComponent } from '../../../helpers/mocks/component'; @@ -39,8 +40,6 @@ import { TutorialModes } from '../types'; jest.mock('../../../api/user-tokens'); -jest.mock('../../../api/branches'); - jest.mock('../../../helpers/urls', () => ({ ...jest.requireActual('../../../helpers/urls'), getHostUrl: jest.fn().mockReturnValue('http://host.url'), @@ -53,20 +52,26 @@ jest.mock('../../../api/components', () => ({ let settingsMock: SettingsServiceMock; let tokenMock: UserTokensMock; let almMock: AlmSettingsServiceMock; +let branchesMock: BranchesServiceMock; beforeAll(() => { settingsMock = new SettingsServiceMock(); tokenMock = new UserTokensMock(); almMock = new AlmSettingsServiceMock(); + branchesMock = new BranchesServiceMock(); }); afterEach(() => { tokenMock.reset(); settingsMock.reset(); almMock.reset(); + branchesMock.reset(); }); -beforeEach(jest.clearAllMocks); +beforeEach(() => { + branchesMock.emptyBranchesAndPullRequest(); + jest.clearAllMocks(); +}); const ui = { loading: byLabelText('loading'), diff --git a/server/sonar-web/src/main/js/queries/branch.tsx b/server/sonar-web/src/main/js/queries/branch.tsx index 5ccfcec4087..4f3a95be6cf 100644 --- a/server/sonar-web/src/main/js/queries/branch.tsx +++ b/server/sonar-web/src/main/js/queries/branch.tsx @@ -104,7 +104,7 @@ function getContext(key: ReturnType) { return { componentKey, query: {} }; } -export function useBranchesQuery(component?: Component) { +export function useBranchesQuery(component?: Component, refetchInterval?: number) { const features = useContext(AvailableFeaturesContext); const key = useBranchesQueryKey(InnerState.Details); return useQuery({ @@ -132,7 +132,8 @@ export function useBranchesQuery(component?: Component) { }, // The check of the key must desapear once component state is in react-query enabled: !!component && component.key === key[1], - staleTime: BRANCHES_STALE_TIME, + staleTime: refetchInterval ?? BRANCHES_STALE_TIME, + refetchInterval, }); } -- 2.39.5