aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src/main/js
diff options
context:
space:
mode:
authorMathieu Suen <mathieu.suen@sonarsource.com>2022-01-05 10:37:27 +0100
committersonartech <sonartech@sonarsource.com>2022-01-20 20:02:43 +0000
commit8a31770cf438f06857632c07958c6021e33d01c2 (patch)
tree46809943728994fe77756a64acdd162c3c0ab6c4 /server/sonar-web/src/main/js
parent3b37a05131ca2a4cf23f6888824258c8e0a423be (diff)
downloadsonarqube-8a31770cf438f06857632c07958c6021e33d01c2.tar.gz
sonarqube-8a31770cf438f06857632c07958c6021e33d01c2.zip
SONAR-15879 Add warning when not all issues are accessible
Diffstat (limited to 'server/sonar-web/src/main/js')
-rw-r--r--server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx15
-rw-r--r--server/sonar-web/src/main/js/apps/issues/components/__tests__/IssuesApp-test.tsx (renamed from server/sonar-web/src/main/js/apps/issues/components/__tests__/App-test.tsx)48
-rw-r--r--server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/IssuesApp-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/App-test.tsx.snap)125
3 files changed, 186 insertions, 2 deletions
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 daf950c8c91..091dde02396 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
@@ -29,6 +29,7 @@ import FiltersHeader from '../../../components/common/FiltersHeader';
import ScreenPositionHelper from '../../../components/common/ScreenPositionHelper';
import { Button } from '../../../components/controls/buttons';
import Checkbox from '../../../components/controls/Checkbox';
+import HelpTooltip from '../../../components/controls/HelpTooltip';
import ListFooter from '../../../components/controls/ListFooter';
import { Location, Router } from '../../../components/hoc/withRouter';
import '../../../components/search-navigator.css';
@@ -50,6 +51,7 @@ import {
} from '../../../helpers/pages';
import { serializeDate } from '../../../helpers/query';
import { BranchLike } from '../../../types/branch-like';
+import { ComponentQualifier, isPortfolioLike } from '../../../types/component';
import {
Facet,
FetchIssuesPromise,
@@ -85,7 +87,7 @@ import MyIssuesFilter from './MyIssuesFilter';
import NoIssues from './NoIssues';
import NoMyIssues from './NoMyIssues';
import PageActions from './PageActions';
-]
+
interface Props {
branchLike?: BranchLike;
component?: T.Component;
@@ -946,6 +948,8 @@ export default class App extends React.PureComponent<Props, State> {
}
renderSide(openIssue: T.Issue | undefined) {
+ const { canBrowseAllChildProjects, qualifier = ComponentQualifier.Project } =
+ this.props.component || {};
return (
<ScreenPositionHelper className="layout-page-side-outer">
{({ top }) => (
@@ -954,6 +958,15 @@ export default class App extends React.PureComponent<Props, State> {
className="layout-page-side"
style={{ top }}>
<div className="layout-page-side-inner">
+ {!canBrowseAllChildProjects && isPortfolioLike(qualifier) && (
+ <Alert className="big-spacer-top big-spacer-right" variant="warning">
+ {translate('issues.not_all_issue_show')}
+ <HelpTooltip
+ className="spacer-left"
+ overlay={translate('issues.not_all_issue_show_why')}
+ />
+ </Alert>
+ )}
<A11ySkipTarget
anchor="issues_sidebar"
label={
diff --git a/server/sonar-web/src/main/js/apps/issues/components/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/issues/components/__tests__/IssuesApp-test.tsx
index c46853dced1..ec5f4e5e767 100644
--- a/server/sonar-web/src/main/js/apps/issues/components/__tests__/App-test.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/components/__tests__/IssuesApp-test.tsx
@@ -39,6 +39,7 @@ import {
mockRouter
} from '../../../../helpers/testMocks';
import { KEYCODE_MAP, keydown, waitAndUpdate } from '../../../../helpers/testUtils';
+import { ComponentQualifier } from '../../../../types/component';
import {
disableLocationsNavigator,
enableLocationsNavigator,
@@ -47,8 +48,8 @@ import {
selectPreviousFlow,
selectPreviousLocation
} from '../../actions';
-import App from '../IssuesApp';
import BulkChangeModal from '../BulkChangeModal';
+import App from '../IssuesApp';
jest.mock('../../../../helpers/pages', () => ({
addSideBarClass: jest.fn(),
@@ -111,6 +112,17 @@ afterEach(() => {
});
});
+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);
@@ -122,6 +134,26 @@ it('should render a list of issue', async () => {
expect(addWhitePageClass).toBeCalled();
});
+it('should handle my issue change properly', () => {
+ const push = jest.fn();
+ const wrapper = shallowRender({ router: mockRouter({ push }) });
+ wrapper.instance().handleMyIssuesChange(true);
+
+ expect(push).toBeCalledWith({
+ pathname: '/issues',
+ query: {
+ id: 'foo',
+ myIssues: 'true'
+ }
+ });
+});
+
+it('should load search result count correcly', async () => {
+ const wrapper = shallowRender();
+ const count = await wrapper.instance().loadSearchResultCount('severities', {});
+ expect(count).toStrictEqual({ MINOR: 4 });
+});
+
it('should not render for anonymous user', () => {
shallowRender({
currentUser: mockCurrentUser({ isLoggedIn: false }),
@@ -130,6 +162,20 @@ it('should not render for anonymous user', () => {
expect(handleRequiredAuthentication).toBeCalled();
});
+it('should handle reset properly', () => {
+ const push = jest.fn();
+ const wrapper = shallowRender({ router: mockRouter({ push }) });
+ wrapper.instance().handleReset();
+ expect(push).toBeCalledWith({
+ pathname: '/issues',
+ query: {
+ id: 'foo',
+ myIssues: undefined,
+ resolved: 'false'
+ }
+ });
+});
+
it('should open standard facets for vulnerabilities and hotspots', () => {
const wrapper = shallowRender({
location: mockLocation({ pathname: '/issues', query: { types: 'VULNERABILITY' } })
diff --git a/server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/App-test.tsx.snap b/server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/IssuesApp-test.tsx.snap
index aa9a378fa01..5d9e05830a4 100644
--- a/server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/App-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/IssuesApp-test.tsx.snap
@@ -20,6 +20,131 @@ exports[`should check max 500 issues 1`] = `
</Button>
`;
+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"
+ >
+ <Alert
+ className="big-spacer-top big-spacer-right"
+ variant="warning"
+ >
+ issues.not_all_issue_show
+ <HelpTooltip
+ className="spacer-left"
+ overlay="issues.not_all_issue_show_why"
+ />
+ </Alert>
+ <A11ySkipTarget
+ anchor="issues_sidebar"
+ label="issues.skip_to_filters"
+ weight={10}
+ />
+ <div
+ className="layout-page-filters"
+ >
+ <MyIssuesFilter
+ myIssues={false}
+ onMyIssuesChange={[Function]}
+ />
+ <FiltersHeader
+ displayReset={true}
+ onReset={[Function]}
+ />
+ <Connect(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,
+ "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 [],
+ "issues": Array [],
+ "languages": Array [],
+ "owaspTop10": Array [],
+ "projects": Array [],
+ "resolutions": Array [],
+ "resolved": true,
+ "rules": Array [],
+ "sansTop25": Array [],
+ "scopes": Array [],
+ "severities": Array [],
+ "sinceLeakPeriod": false,
+ "sonarsourceSecurity": Array [],
+ "sort": "",
+ "statuses": Array [],
+ "tags": Array [],
+ "types": Array [],
+ }
+ }
+ referencedComponentsById={Object {}}
+ referencedComponentsByKey={Object {}}
+ referencedLanguages={Object {}}
+ referencedRules={Object {}}
+ referencedUsers={Object {}}
+ />
+ </div>
+ </div>
+ </section>
+</div>
+`;
+
exports[`should switch to source view if an issue is selected 1`] = `
<div
className="layout-page issues"