@@ -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={ |
@@ -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' } }) |
@@ -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" |
@@ -926,6 +926,9 @@ issues.my_issues=My Issues | |||
issues.no_my_issues=There are no issues assigned to you. | |||
issues.no_issues=No Issues. Hooray! | |||
issues.x_more_locations=+ {0} more location(s) | |||
issues.not_all_issue_show=Not all issues are included | |||
issues.not_all_issue_show_why=You do not have access to all projects in this portfolio | |||
#------------------------------------------------------------------------------ | |||
# |