diff options
author | Mathieu Suen <mathieu.suen@sonarsource.com> | 2022-12-13 14:25:48 +0100 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2022-12-14 20:03:52 +0000 |
commit | ef5732d44240ffb20d743672b1d3557451430c4e (patch) | |
tree | 774f567617504ac12418336a826542a1a2a7818f /server/sonar-web/src/main | |
parent | 22b8b6d4ad713c4abbca5c9b992e873499246b83 (diff) | |
download | sonarqube-ef5732d44240ffb20d743672b1d3557451430c4e.tar.gz sonarqube-ef5732d44240ffb20d743672b1d3557451430c4e.zip |
SONAR-17718 Fix warning position on protfolio when not all project is accessible
Diffstat (limited to 'server/sonar-web/src/main')
-rw-r--r-- | server/sonar-web/src/main/js/apps/issues/__tests__/IssuesApp-it.tsx (renamed from server/sonar-web/src/main/js/apps/issues/__tests__/IssueApp-it.tsx) | 27 | ||||
-rw-r--r-- | server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx | 27 | ||||
-rw-r--r-- | server/sonar-web/src/main/js/apps/issues/components/__tests__/IssuesApp-test.tsx | 12 | ||||
-rw-r--r-- | server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/IssuesApp-test.tsx.snap | 151 | ||||
-rw-r--r-- | server/sonar-web/src/main/js/apps/issues/conciseIssuesList/ConciseIssue.tsx | 2 | ||||
-rw-r--r-- | server/sonar-web/src/main/js/apps/issues/conciseIssuesList/ConciseIssueBox.tsx | 6 | ||||
-rw-r--r-- | server/sonar-web/src/main/js/apps/issues/conciseIssuesList/ConciseIssuesList.tsx | 21 | ||||
-rw-r--r-- | server/sonar-web/src/main/js/apps/issues/styles.css | 14 |
8 files changed, 65 insertions, 195 deletions
diff --git a/server/sonar-web/src/main/js/apps/issues/__tests__/IssueApp-it.tsx b/server/sonar-web/src/main/js/apps/issues/__tests__/IssuesApp-it.tsx index 30b48e55668..2c98af2587b 100644 --- a/server/sonar-web/src/main/js/apps/issues/__tests__/IssueApp-it.tsx +++ b/server/sonar-web/src/main/js/apps/issues/__tests__/IssuesApp-it.tsx @@ -23,10 +23,13 @@ import React from 'react'; import selectEvent from 'react-select-event'; import IssuesServiceMock from '../../../api/mocks/IssuesServiceMock'; import { TabKeys } from '../../../components/rules/RuleTabViewer'; +import { mockComponent } from '../../../helpers/mocks/component'; import { renderOwaspTop102021Category } from '../../../helpers/security-standard'; import { mockCurrentUser } from '../../../helpers/testMocks'; -import { renderApp, renderAppRoutes } from '../../../helpers/testReactTestingUtils'; +import { renderApp, renderAppWithComponentContext } from '../../../helpers/testReactTestingUtils'; +import { ComponentQualifier } from '../../../types/component'; import { IssueType } from '../../../types/issues'; +import { Component } from '../../../types/types'; import { CurrentUser } from '../../../types/users'; import IssuesApp from '../components/IssuesApp'; import { projectIssuesRoutes } from '../routes'; @@ -90,6 +93,19 @@ it('should be able to bulk change', async () => { ).toBeInTheDocument(); }); +it('should show warning when not all issues are accessible', async () => { + const user = userEvent.setup(); + renderProjectIssuesApp('project/issues?id=myproject', { + canBrowseAllChildProjects: false, + qualifier: ComponentQualifier.Portfolio, + }); + expect(await screen.findByRole('alert', { name: 'alert.tooltip.warning' })).toBeInTheDocument(); + + await user.keyboard('{ArrowRight}'); + + expect(await screen.findByRole('alert', { name: 'alert.tooltip.warning' })).toBeInTheDocument(); +}); + it('should interact with flows and locations', async () => { const user = userEvent.setup(); renderProjectIssuesApp('project/issues?issues=issue11&open=issue11&id=myproject'); @@ -606,6 +622,11 @@ function renderIssueApp(currentUser?: CurrentUser) { renderApp('project/issues', <IssuesApp />, { currentUser: mockCurrentUser(currentUser) }); } -function renderProjectIssuesApp(navigateTo?: string) { - renderAppRoutes('project/issues', projectIssuesRoutes, { navigateTo }); +function renderProjectIssuesApp(navigateTo?: string, overrides?: Partial<Component>) { + renderAppWithComponentContext( + 'project/issues', + projectIssuesRoutes, + { navigateTo }, + { component: mockComponent(overrides) } + ); } 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 b29c89f83f4..5c1c8da1a3d 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 @@ -976,19 +976,22 @@ export class App extends React.PureComponent<Props, State> { weight={10} /> {!canBrowseAllChildProjects && isPortfolioLike(qualifier) && ( - <Alert - className="big-spacer-top big-spacer-right big-spacer-left it__portfolio_warning" - variant="warning" + <div + className={classNames('not-all-issue-warning', { + 'open-issue-list': openIssue, + })} > - <AlertContent> - {translate('issues.not_all_issue_show')} - <HelpTooltip - className="spacer-left" - ariaLabel={translate('issues.not_all_issue_show_why')} - overlay={translate('issues.not_all_issue_show_why')} - /> - </AlertContent> - </Alert> + <Alert className={classNames('it__portfolio_warning')} variant="warning"> + <AlertContent> + {translate('issues.not_all_issue_show')} + <HelpTooltip + className="spacer-left" + ariaLabel={translate('issues.not_all_issue_show_why')} + overlay={translate('issues.not_all_issue_show_why')} + /> + </AlertContent> + </Alert> + </div> )} {openIssue ? this.renderConciseIssuesList() : this.renderFacets()} diff --git a/server/sonar-web/src/main/js/apps/issues/components/__tests__/IssuesApp-test.tsx b/server/sonar-web/src/main/js/apps/issues/components/__tests__/IssuesApp-test.tsx index 256797c4bf4..6da85978762 100644 --- a/server/sonar-web/src/main/js/apps/issues/components/__tests__/IssuesApp-test.tsx +++ b/server/sonar-web/src/main/js/apps/issues/components/__tests__/IssuesApp-test.tsx @@ -40,7 +40,6 @@ import { mockRouter, } from '../../../../helpers/testMocks'; import { keydown, mockEvent, waitAndUpdate } from '../../../../helpers/testUtils'; -import { ComponentQualifier } from '../../../../types/component'; import { ReferencedComponent } from '../../../../types/issues'; import { Issue, Paging } from '../../../../types/types'; import { @@ -116,17 +115,6 @@ afterEach(() => { (searchIssues as jest.Mock).mockReset(); }); -it('should show warnning when not all projects are accessible', () => { - const wrapper = shallowRender({ - component: mockComponent({ - canBrowseAllChildProjects: false, - qualifier: ComponentQualifier.Portfolio, - }), - }); - const rootNode = shallow(wrapper.instance().renderSide(undefined)); - expect(rootNode).toMatchSnapshot(); -}); - it('should render a list of issue', async () => { const wrapper = shallowRender(); await waitAndUpdate(wrapper); diff --git a/server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/IssuesApp-test.tsx.snap b/server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/IssuesApp-test.tsx.snap deleted file mode 100644 index 0be1d5defdf..00000000000 --- a/server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/IssuesApp-test.tsx.snap +++ /dev/null @@ -1,151 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should show warnning when not all projects are accessible 1`] = ` -<div - className="layout-page-side-outer" -> - <section - aria-label="filters" - className="layout-page-side" - style={ - Object { - "top": 0, - } - } - > - <div - className="layout-page-side-inner" - > - <A11ySkipTarget - anchor="issues_sidebar" - label="issues.skip_to_filters" - weight={10} - /> - <Alert - className="big-spacer-top big-spacer-right big-spacer-left it__portfolio_warning" - variant="warning" - > - <Styled(div)> - issues.not_all_issue_show - <HelpTooltip - ariaLabel="issues.not_all_issue_show_why" - className="spacer-left" - overlay="issues.not_all_issue_show_why" - /> - </Styled(div)> - </Alert> - <div - className="layout-page-filters" - > - <div - className="display-flex-justify-center big-spacer-bottom" - > - <ButtonToggle - onCheck={[Function]} - options={ - Array [ - Object { - "label": "issues.my_issues", - "value": true, - }, - Object { - "label": "all", - "value": false, - }, - ] - } - value={false} - /> - </div> - <FiltersHeader - displayReset={true} - onReset={[Function]} - /> - <withAppStateContext(Sidebar) - component={ - Object { - "breadcrumbs": Array [], - "canBrowseAllChildProjects": false, - "key": "my-project", - "name": "MyProject", - "qualifier": "VW", - "qualityGate": Object { - "isDefault": true, - "key": "30", - "name": "Sonar way", - }, - "qualityProfiles": Array [ - Object { - "deleted": false, - "key": "my-qp", - "language": "ts", - "name": "Sonar way", - }, - ], - "tags": Array [], - } - } - createdAfterIncludesTime={false} - facets={Object {}} - loadSearchResultCount={[Function]} - loadingFacets={Object {}} - myIssues={false} - onFacetToggle={[Function]} - onFilterChange={[Function]} - openFacets={ - Object { - "owaspTop10": false, - "owaspTop10-2021": false, - "sansTop25": false, - "severities": true, - "sonarsourceSecurity": false, - "standards": false, - "types": true, - } - } - query={ - Object { - "assigned": true, - "assignees": Array [], - "author": Array [], - "createdAfter": undefined, - "createdAt": "", - "createdBefore": undefined, - "createdInLast": "", - "cwe": Array [], - "directories": Array [], - "files": Array [], - "inNewCodePeriod": false, - "issues": Array [], - "languages": Array [], - "owaspAsvs-4.0": Array [], - "owaspAsvsLevel": "", - "owaspTop10": Array [], - "owaspTop10-2021": Array [], - "pciDss-3.2": Array [], - "pciDss-4.0": Array [], - "projects": Array [], - "resolutions": Array [], - "resolved": true, - "rules": Array [], - "sansTop25": Array [], - "scopes": Array [], - "severities": Array [], - "sonarsourceSecurity": Array [], - "sort": "", - "statuses": Array [], - "tags": Array [], - "types": Array [], - } - } - referencedComponentsById={Object {}} - referencedComponentsByKey={Object {}} - referencedLanguages={Object {}} - referencedRules={Object {}} - referencedUsers={Object {}} - /> - </div> - </div> - </section> -</div> -`; diff --git a/server/sonar-web/src/main/js/apps/issues/conciseIssuesList/ConciseIssue.tsx b/server/sonar-web/src/main/js/apps/issues/conciseIssuesList/ConciseIssue.tsx index 22c9233fa22..7acb9a6a0ea 100644 --- a/server/sonar-web/src/main/js/apps/issues/conciseIssuesList/ConciseIssue.tsx +++ b/server/sonar-web/src/main/js/apps/issues/conciseIssuesList/ConciseIssue.tsx @@ -28,7 +28,7 @@ export interface ConciseIssueProps { onLocationSelect: (index: number) => void; onSelect: (issueKey: string) => void; previousIssue: Issue | undefined; - scroll: (element: Element, bottomOffset?: number) => void; + scroll: (element: Element) => void; selected: boolean; selectedFlowIndex: number | undefined; selectedLocationIndex: number | undefined; diff --git a/server/sonar-web/src/main/js/apps/issues/conciseIssuesList/ConciseIssueBox.tsx b/server/sonar-web/src/main/js/apps/issues/conciseIssuesList/ConciseIssueBox.tsx index 5ff855693b6..14582d1fc11 100644 --- a/server/sonar-web/src/main/js/apps/issues/conciseIssuesList/ConciseIssueBox.tsx +++ b/server/sonar-web/src/main/js/apps/issues/conciseIssuesList/ConciseIssueBox.tsx @@ -34,14 +34,12 @@ interface Props { onClick: (issueKey: string) => void; onFlowSelect: (index?: number) => void; onLocationSelect: (index: number) => void; - scroll: (element: Element, bottomOffset?: number) => void; + scroll: (element: Element) => void; selected: boolean; selectedFlowIndex: number | undefined; selectedLocationIndex: number | undefined; } -const SCROLL_TOP_OFFSET = 250; - export default class ConciseIssueBox extends React.PureComponent<Props> { messageElement?: HTMLElement | null; @@ -63,7 +61,7 @@ export default class ConciseIssueBox extends React.PureComponent<Props> { handleScroll = () => { if (this.messageElement) { - this.props.scroll(this.messageElement, window.innerHeight - SCROLL_TOP_OFFSET); + this.props.scroll(this.messageElement); } }; diff --git a/server/sonar-web/src/main/js/apps/issues/conciseIssuesList/ConciseIssuesList.tsx b/server/sonar-web/src/main/js/apps/issues/conciseIssuesList/ConciseIssuesList.tsx index 9e372f2f59a..cf84f78d786 100644 --- a/server/sonar-web/src/main/js/apps/issues/conciseIssuesList/ConciseIssuesList.tsx +++ b/server/sonar-web/src/main/js/apps/issues/conciseIssuesList/ConciseIssuesList.tsx @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import { scrollToElement } from '../../../helpers/scrolling'; import { Issue } from '../../../types/types'; import ConciseIssue from './ConciseIssue'; @@ -32,20 +31,18 @@ export interface ConciseIssuesListProps { selectedLocationIndex: number | undefined; } -const DEFAULT_BOTTOM_OFFSET = 100; - export default function ConciseIssuesList(props: ConciseIssuesListProps) { const { issues, selected, selectedFlowIndex, selectedLocationIndex } = props; - const handleScroll = React.useCallback( - (element: Element, bottomOffset = DEFAULT_BOTTOM_OFFSET) => { - const scrollableElement = document.querySelector('.layout-page-side'); - if (element && scrollableElement) { - scrollToElement(element, { topOffset: 150, bottomOffset, parent: scrollableElement }); - } - }, - [] - ); + const handleScroll = React.useCallback((element: Element) => { + if (element) { + element.scrollIntoView({ + block: 'center', + behavior: 'smooth', + inline: 'center', + }); + } + }, []); return ( <ul> diff --git a/server/sonar-web/src/main/js/apps/issues/styles.css b/server/sonar-web/src/main/js/apps/issues/styles.css index d5d1019dec5..43c1eb215a8 100644 --- a/server/sonar-web/src/main/js/apps/issues/styles.css +++ b/server/sonar-web/src/main/js/apps/issues/styles.css @@ -68,6 +68,20 @@ transition: background-color 0.3s ease, border-color 0.3s ease; } +.not-all-issue-warning { + padding: 16px 16px 0; + width: 100%; + box-sizing: border-box; +} + +.not-all-issue-warning.open-issue-list { + position: sticky; + top: 0; + z-index: 1000; + background-color: var(--barBackgroundColor); + display: inline-block; +} + .concise-issue-box .issue-message-highlight-CODE { background-color: var(--blacka06); } |