From: Ambroise C Date: Tue, 18 Jul 2023 15:23:24 +0000 (+0200) Subject: SONAR-19728 Unlock project issues page while reindexing issues X-Git-Tag: 10.2.0.77647~344 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=a451c69c4fddd6f8ac8412a551a6baaa01bd11cc;p=sonarqube.git SONAR-19728 Unlock project issues page while reindexing issues --- diff --git a/server/sonar-web/src/main/js/api/issues.ts b/server/sonar-web/src/main/js/api/issues.ts index af5ee866a1c..23e47c35d88 100644 --- a/server/sonar-web/src/main/js/api/issues.ts +++ b/server/sonar-web/src/main/js/api/issues.ts @@ -28,7 +28,7 @@ import { postJSON, RequestData, } from '../helpers/request'; -import { IssueResponse, RawIssuesResponse } from '../types/issues'; +import { IssueResponse, ListIssuesResponse, RawIssuesResponse } from '../types/issues'; import { Dict, FacetValue, IssueChangelog, SnippetsByComponent, SourceLine } from '../types/types'; type FacetName = @@ -55,6 +55,10 @@ export function searchIssues(query: RequestData): Promise { return getJSON('/api/issues/search', query).catch(throwGlobalError); } +export function listIssues(query: RequestData): Promise { + return getJSON('/api/issues/list', query).catch(throwGlobalError); +} + export function getFacets( query: RequestData, facets: FacetName[] diff --git a/server/sonar-web/src/main/js/api/mocks/IssuesServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/IssuesServiceMock.ts index 080d3b941e9..efaf2bd2c70 100644 --- a/server/sonar-web/src/main/js/api/mocks/IssuesServiceMock.ts +++ b/server/sonar-web/src/main/js/api/mocks/IssuesServiceMock.ts @@ -32,6 +32,7 @@ import { IssueStatus, IssueTransition, IssueType, + ListIssuesResponse, RawFacet, RawIssue, RawIssuesResponse, @@ -49,6 +50,7 @@ import { editIssueComment, getIssueChangelog, getIssueFlowSnippets, + listIssues, searchIssueAuthors, searchIssueTags, searchIssues, @@ -116,6 +118,7 @@ export default class IssuesServiceMock { jest.mocked(getIssueChangelog).mockImplementation(this.handleGetIssueChangelog); jest.mocked(getIssueFlowSnippets).mockImplementation(this.handleGetIssueFlowSnippets); jest.mocked(getRuleDetails).mockImplementation(this.handleGetRuleDetails); + jest.mocked(listIssues).mockImplementation(this.handleListIssues); jest.mocked(searchIssueAuthors).mockImplementation(this.handleSearchIssueAuthors); jest.mocked(searchIssues).mockImplementation(this.handleSearchIssues); jest.mocked(searchIssueTags).mockImplementation(this.handleSearchIssueTags); @@ -379,6 +382,32 @@ export default class IssuesServiceMock { }); }; + handleListIssues = (query: RequestData): Promise => { + const filteredList = this.list + .filter((item) => !query.types || query.types.split(',').includes(item.issue.type)) + .filter( + (item) => + !query.inNewCodePeriod || new Date(item.issue.creationDate) > new Date('2023-01-10') + ); + + // Splice list items according to paging using a fixed page size + const pageIndex = query.p || 1; + const pageSize = 7; + const listItems = filteredList.slice((pageIndex - 1) * pageSize, pageIndex * pageSize); + + // Generate response + return this.reply({ + components: generateReferenceComponentsForIssues(filteredList), + issues: listItems.map((line) => line.issue), + paging: mockPaging({ + pageIndex, + pageSize, + total: filteredList.length, + }), + rules: this.rulesList, + }); + }; + handleSearchIssues = (query: RequestData): Promise => { const facets = this.mockFacetDetailResponse(query); diff --git a/server/sonar-web/src/main/js/apps/issues/__tests__/IssuesApp-it.tsx b/server/sonar-web/src/main/js/apps/issues/__tests__/IssuesApp-it.tsx index 7d726e9492d..b70a6cdc61c 100644 --- a/server/sonar-web/src/main/js/apps/issues/__tests__/IssuesApp-it.tsx +++ b/server/sonar-web/src/main/js/apps/issues/__tests__/IssuesApp-it.tsx @@ -957,3 +957,30 @@ describe('Activity', () => { ).toBeInTheDocument(); }); }); + +describe('issues app when reindexing', () => { + it('should display only some facets while reindexing is in progress', async () => { + issuesHandler.setIsAdmin(true); + renderProjectIssuesApp(undefined, { needIssueSync: true }); + + // Enabled facets + expect(ui.inNewCodeFilter.get()).toBeInTheDocument(); + expect(ui.typeFacet.get()).toBeInTheDocument(); + + // Disabled facets + expect(await ui.assigneeFacet.query()).not.toBeInTheDocument(); + expect(await ui.authorFacet.query()).not.toBeInTheDocument(); + expect(await ui.codeVariantsFacet.query()).not.toBeInTheDocument(); + expect(await ui.creationDateFacet.query()).not.toBeInTheDocument(); + expect(await ui.languageFacet.query()).not.toBeInTheDocument(); + expect(await ui.projectFacet.query()).not.toBeInTheDocument(); + expect(await ui.resolutionFacet.query()).not.toBeInTheDocument(); + expect(await ui.ruleFacet.query()).not.toBeInTheDocument(); + expect(await ui.scopeFacet.query()).not.toBeInTheDocument(); + expect(await ui.statusFacet.query()).not.toBeInTheDocument(); + expect(await ui.tagFacet.query()).not.toBeInTheDocument(); + + // Indexation message + expect(screen.getByText(/indexation\.filters_unavailable/)).toBeInTheDocument(); + }); +}); diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/Sidebar.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/Sidebar.tsx index 8e06b68f8d9..6e0262b31a3 100644 --- a/server/sonar-web/src/main/js/apps/issues/sidebar/Sidebar.tsx +++ b/server/sonar-web/src/main/js/apps/issues/sidebar/Sidebar.tsx @@ -18,10 +18,12 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { BasicSeparator } from 'design-system'; +import { BasicSeparator, FlagMessage, Link } from 'design-system'; import * as React from 'react'; +import { FormattedMessage } from 'react-intl'; import withAppStateContext from '../../../app/components/app-state/withAppStateContext'; import { isBranch, isPullRequest } from '../../../helpers/branch-like'; +import { translate } from '../../../helpers/l10n'; import { AppState } from '../../../types/appstate'; import { BranchLike } from '../../../types/branch-like'; import { @@ -167,6 +169,8 @@ export class SidebarClass extends React.PureComponent { const displayPeriodFilter = component !== undefined && !isPortfolioLike(component.qualifier); const displayProjectsFacet = !component || isView(component.qualifier); + const needIssueSync = component?.needIssueSync; + return ( <> {displayPeriodFilter && ( @@ -178,6 +182,7 @@ export class SidebarClass extends React.PureComponent { { types={query.types} /> - - - - - - - - - - - - - + {!needIssueSync && ( + <> + - + - + - + - + - + - + - + - + - + - + - + - {displayProjectsFacet && ( - <> - - - )} - - {this.renderComponentFacets()} - {!this.props.myIssues && !disableDeveloperAggregatedInfo && ( - <> - + + {!disableDeveloperAggregatedInfo && ( + <> + + + + + {displayProjectsFacet && ( + <> + + + + + )} + + {this.renderComponentFacets()} + + {!this.props.myIssues && ( + <> + + + + + )} + + + + + + )} )} - {!disableDeveloperAggregatedInfo && ( + {needIssueSync && ( <> - + +
+ {translate('indexation.page_unavailable.description')} + + + {translate('learn_more')} + + ), + }} + /> + +
+
)} diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/TypeFacet.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/TypeFacet.tsx index 36b0a91c484..cacde371aaa 100644 --- a/server/sonar-web/src/main/js/apps/issues/sidebar/TypeFacet.tsx +++ b/server/sonar-web/src/main/js/apps/issues/sidebar/TypeFacet.tsx @@ -30,6 +30,7 @@ import { MultipleSelectionHint } from './MultipleSelectionHint'; interface Props { fetching: boolean; + needIssueSync?: boolean; onChange: (changes: Partial) => void; onToggle: (property: string) => void; open: boolean; @@ -79,6 +80,7 @@ export class TypeFacet extends React.PureComponent { } renderItem = (type: string) => { + const { needIssueSync } = this.props; const active = this.isFacetItemActive(type); const stat = this.getStat(type); @@ -94,7 +96,7 @@ export class TypeFacet extends React.PureComponent { key={type} name={translate('issue.type', type)} onClick={this.handleItemClick} - stat={formatFacetStat(stat) ?? 0} + stat={(!needIssueSync && formatFacetStat(stat)) ?? 0} value={type} /> ); diff --git a/server/sonar-web/src/main/js/apps/issues/test-utils.tsx b/server/sonar-web/src/main/js/apps/issues/test-utils.tsx index 77f8033af10..439fa6b2519 100644 --- a/server/sonar-web/src/main/js/apps/issues/test-utils.tsx +++ b/server/sonar-web/src/main/js/apps/issues/test-utils.tsx @@ -67,6 +67,7 @@ export const ui = { scopeFacet: byRole('button', { name: 'issues.facet.scopes' }), statusFacet: byRole('button', { name: 'issues.facet.statuses' }), tagFacet: byRole('button', { name: 'issues.facet.tags' }), + typeFacet: byRole('button', { name: 'issues.facet.types' }), clearAssigneeFacet: byTestId('clear-issues.facet.assignees'), clearAuthorFacet: byTestId('clear-issues.facet.authors'), diff --git a/server/sonar-web/src/main/js/apps/issues/utils.ts b/server/sonar-web/src/main/js/apps/issues/utils.ts index d2aee46d244..9638728d3ab 100644 --- a/server/sonar-web/src/main/js/apps/issues/utils.ts +++ b/server/sonar-web/src/main/js/apps/issues/utils.ts @@ -169,7 +169,7 @@ export function serializeQuery(query: Query): RawQuery { export const areQueriesEqual = (a: RawQuery, b: RawQuery) => queriesEqual(parseQuery(a), parseQuery(b)); -export function parseFacets(facets: RawFacet[]): Dict { +export function parseFacets(facets?: RawFacet[]): Dict { if (!facets) { return {}; } diff --git a/server/sonar-web/src/main/js/helpers/branch-like.ts b/server/sonar-web/src/main/js/helpers/branch-like.ts index f5c6f5d5f51..342c09ea859 100644 --- a/server/sonar-web/src/main/js/helpers/branch-like.ts +++ b/server/sonar-web/src/main/js/helpers/branch-like.ts @@ -113,8 +113,11 @@ export function getBrancheLikesAsTree(branchLikes: BranchLike[]): BranchLikeTree } } -export function getBranchLikeQuery(branchLike?: BranchLike): BranchParameters { - if (isBranch(branchLike) && !isMainBranch(branchLike)) { +export function getBranchLikeQuery( + branchLike?: BranchLike, + includeMainBranch = false +): BranchParameters { + if (isBranch(branchLike) && (includeMainBranch || !isMainBranch(branchLike))) { return { branch: branchLike.name }; } else if (isPullRequest(branchLike)) { return { pullRequest: branchLike.key }; diff --git a/server/sonar-web/src/main/js/types/issues.ts b/server/sonar-web/src/main/js/types/issues.ts index 7b55991936b..57ce60737e1 100644 --- a/server/sonar-web/src/main/js/types/issues.ts +++ b/server/sonar-web/src/main/js/types/issues.ts @@ -153,15 +153,28 @@ export interface RawIssuesResponse { users?: UserBase[]; } -export interface FetchIssuesPromise { +export interface ListIssuesResponse { components: ReferencedComponent[]; - effortTotal: number; - facets: RawFacet[]; + issues: RawIssue[]; + paging: Paging; + rules?: Array<{}>; +} + +export interface FetchIssuesPromise { + components?: ReferencedComponent[]; + effortTotal?: number; + facets?: RawFacet[]; + issues: Issue[]; + languages?: ReferencedLanguage[]; + paging: Paging; + rules: ReferencedRule[]; + users?: UserBase[]; +} + +export interface ListIssuesPromise { issues: Issue[]; - languages: ReferencedLanguage[]; paging: Paging; rules: ReferencedRule[]; - users: UserBase[]; } export interface ReferencedComponent { diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index b43d1ea5fc3..e7b5f022536 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -4741,6 +4741,8 @@ indexation.page_unavailable.description.additional_information=This page is unav indexation.filter_unavailable.description=This filter is unavailable until this process is complete. indexation.learn_more=Learn more: indexation.reindexing=Reindexing +indexation.filters_unavailable=Some filters are unavailable until this process is complete. {link} + #------------------------------------------------------------------------------ #