aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src/main
diff options
context:
space:
mode:
authorMathieu Suen <mathieu.suen@sonarsource.com>2022-12-13 14:25:48 +0100
committersonartech <sonartech@sonarsource.com>2022-12-14 20:03:52 +0000
commitef5732d44240ffb20d743672b1d3557451430c4e (patch)
tree774f567617504ac12418336a826542a1a2a7818f /server/sonar-web/src/main
parent22b8b6d4ad713c4abbca5c9b992e873499246b83 (diff)
downloadsonarqube-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.tsx27
-rw-r--r--server/sonar-web/src/main/js/apps/issues/components/__tests__/IssuesApp-test.tsx12
-rw-r--r--server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/IssuesApp-test.tsx.snap151
-rw-r--r--server/sonar-web/src/main/js/apps/issues/conciseIssuesList/ConciseIssue.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/issues/conciseIssuesList/ConciseIssueBox.tsx6
-rw-r--r--server/sonar-web/src/main/js/apps/issues/conciseIssuesList/ConciseIssuesList.tsx21
-rw-r--r--server/sonar-web/src/main/js/apps/issues/styles.css14
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);
}