From 43238579b4e2755ce8186b4a17c7f5efeb90add4 Mon Sep 17 00:00:00 2001 From: vikvorona Date: Fri, 21 Apr 2023 09:21:18 +0200 Subject: [PATCH] SONAR-19036 Facets should update their content even if they are collapsed (#8109) --- .../main/js/api/mocks/IssuesServiceMock.ts | 19 +++++++++---- .../js/apps/issues/__tests__/IssuesApp-it.tsx | 27 +++++++++++++++++++ .../js/apps/issues/components/IssuesApp.tsx | 12 ++++----- .../src/main/js/apps/issues/test-utils.tsx | 2 ++ 4 files changed, 49 insertions(+), 11 deletions(-) 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 ec11f62ad5b..46bedfce13d 100644 --- a/server/sonar-web/src/main/js/api/mocks/IssuesServiceMock.ts +++ b/server/sonar-web/src/main/js/api/mocks/IssuesServiceMock.ts @@ -620,8 +620,12 @@ export default class IssuesServiceMock { }); }; - mockFacetDetailResponse = (facetsQuery: string): RawFacet[] => { - return facetsQuery.split(',').map((name: string): RawFacet => { + mockFacetDetailResponse = (query: RequestData): RawFacet[] => { + const facets = (query.facets ?? '').split(','); + const types: Exclude[] = ( + query.types ?? 'BUG,CODE_SMELL,VULNERABILITY' + ).split(','); + return facets.map((name: string): RawFacet => { if (name === 'owaspTop10-2021') { return this.owasp2021FacetList(); } @@ -678,16 +682,21 @@ export default class IssuesServiceMock { }; } if (name === 'languages') { + const counters = { + [IssueType.Bug]: { java: 4100, ts: 500 }, + [IssueType.CodeSmell]: { java: 21000, ts: 2000 }, + [IssueType.Vulnerability]: { java: 111, ts: 674 }, + }; return { property: name, values: [ { val: 'java', - count: 25211, + count: types.reduce((acc, type) => acc + counters[type].java, 0), }, { val: 'ts', - count: 3174, + count: types.reduce((acc, type) => acc + counters[type].ts, 0), }, ], }; @@ -700,7 +709,7 @@ export default class IssuesServiceMock { }; handleSearchIssues = (query: RequestData): Promise => { - const facets = this.mockFacetDetailResponse((query.facets ?? '') as string); + const facets = this.mockFacetDetailResponse(query); // Filter list (only supports assignee, type and severity) const filteredList = this.list 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 212d1d4a38e..e90b41b0a4e 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 @@ -499,6 +499,33 @@ describe('issues app', () => { }) ).not.toBeInTheDocument(); }); + + it('should update collapsed facets with filter change', async () => { + const user = userEvent.setup(); + + renderIssueApp(); + + await user.click(await ui.languageFacet.find()); + expect(await ui.languageFacetList.find()).toBeInTheDocument(); + expect( + within(ui.languageFacetList.get()).getByRole('checkbox', { name: 'java' }) + ).toHaveTextContent('java25short_number_suffix.k'); + expect( + within(ui.languageFacetList.get()).getByRole('checkbox', { name: 'ts' }) + ).toHaveTextContent('ts3.2short_number_suffix.k'); + + await user.click(ui.languageFacet.get()); + expect(ui.languageFacetList.query()).not.toBeInTheDocument(); + await user.click(ui.vulnerabilityIssueTypeFilter.get()); + await user.click(ui.languageFacet.get()); + expect(await ui.languageFacetList.find()).toBeInTheDocument(); + expect( + within(ui.languageFacetList.get()).getByRole('checkbox', { name: 'java' }) + ).toHaveTextContent('java111'); + expect( + within(ui.languageFacetList.get()).getByRole('checkbox', { name: 'ts' }) + ).toHaveTextContent('ts674'); + }); }); }); diff --git a/server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx b/server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx index 1cdb44ae166..ffad87ea9bb 100644 --- a/server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx +++ b/server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx @@ -33,11 +33,11 @@ import A11ySkipTarget from '../../../components/a11y/A11ySkipTarget'; import EmptySearch from '../../../components/common/EmptySearch'; import FiltersHeader from '../../../components/common/FiltersHeader'; import ScreenPositionHelper from '../../../components/common/ScreenPositionHelper'; -import { Button } from '../../../components/controls/buttons'; import ButtonToggle from '../../../components/controls/ButtonToggle'; import Checkbox from '../../../components/controls/Checkbox'; import HelpTooltip from '../../../components/controls/HelpTooltip'; import ListFooter from '../../../components/controls/ListFooter'; +import { Button } from '../../../components/controls/buttons'; import Suggestions from '../../../components/embed-docs-modal/Suggestions'; import withIndexationGuard from '../../../components/hoc/withIndexationGuard'; import { Location, Router, withRouter } from '../../../components/hoc/withRouter'; @@ -82,19 +82,19 @@ import ConciseIssuesListHeader from '../conciseIssuesList/ConciseIssuesListHeade import Sidebar from '../sidebar/Sidebar'; import '../styles.css'; import { + Query, + STANDARDS, areMyIssuesSelected, areQueriesEqual, getOpen, getOpenIssue, parseFacets, parseQuery, - Query, saveMyIssues, serializeQuery, shouldOpenSonarSourceSecurityFacet, shouldOpenStandardsChildFacet, shouldOpenStandardsFacet, - STANDARDS, } from '../utils'; import BulkChangeModal, { MAX_PAGE_SIZE } from './BulkChangeModal'; import IssueHeader from './IssueHeader'; @@ -503,10 +503,10 @@ export class App extends React.PureComponent { if (issues.length > 0) { selected = openIssue ? openIssue.key : issues[0].key; } - this.setState((state) => ({ + this.setState({ cannotShowOpenIssue: Boolean(openIssueKey && !openIssue), effortTotal, - facets: { ...state.facets, ...parseFacets(facets) }, + facets: parseFacets(facets), loading: false, locationsNavigator: true, issues, @@ -520,7 +520,7 @@ export class App extends React.PureComponent { selected, selectedFlowIndex: 0, selectedLocationIndex: undefined, - })); + }); } return issues; }, 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 5d92bcddc32..04f53c899df 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 @@ -68,6 +68,7 @@ export const ui = { clearStatusFacet: byRole('button', { name: 'clear_x_filter.issues.facet.statuses' }), openStatusFilter: byRole('checkbox', { name: 'issue.status.OPEN' }), confirmedStatusFilter: byRole('checkbox', { name: 'issue.status.CONFIRMED' }), + languageFacet: byRole('button', { name: 'issues.facet.languages' }), ruleFacet: byRole('button', { name: 'issues.facet.rules' }), clearRuleFacet: byRole('button', { name: 'clear_x_filter.issues.facet.rules' }), tagFacet: byRole('button', { name: 'issues.facet.tags' }), @@ -85,6 +86,7 @@ export const ui = { clearAllFilters: byRole('button', { name: 'clear_all_filters' }), ruleFacetList: byRole('list', { name: 'rules' }), + languageFacetList: byRole('list', { name: 'languages' }), ruleFacetSearch: byRole('searchbox', { name: 'search.search_for_rules' }), }; -- 2.39.5