Browse Source

SONAR-12797 Message when no hotspots found (list of keys)

tags/8.2.0.32929
Jeremy Davis 4 years ago
parent
commit
8d8f01a13a

+ 15
- 37
server/sonar-web/src/main/js/apps/securityHotspots/SecurityHotspotsAppRenderer.tsx View File

@@ -19,16 +19,20 @@
*/
import * as React from 'react';
import { Helmet } from 'react-helmet-async';
import { Link } from 'react-router';
import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { getBaseUrl } from 'sonar-ui-common/helpers/urls';
import A11ySkipTarget from '../../app/components/a11y/A11ySkipTarget';
import Suggestions from '../../app/components/embed-docs-modal/Suggestions';
import ScreenPositionHelper from '../../components/common/ScreenPositionHelper';
import { isBranch } from '../../helpers/branch-like';
import { BranchLike } from '../../types/branch-like';
import { HotspotFilters, HotspotUpdate, RawHotspot } from '../../types/security-hotspots';
import {
HotspotFilters,
HotspotStatusFilter,
HotspotUpdate,
RawHotspot
} from '../../types/security-hotspots';
import EmptyHotspotsPage from './components/EmptyHotspotsPage';
import FilterBar from './components/FilterBar';
import HotspotList from './components/HotspotList';
import HotspotViewer from './components/HotspotViewer';
@@ -51,37 +55,6 @@ export interface SecurityHotspotsAppRendererProps {
securityCategories: T.StandardSecurityCategories;
}

function renderNoHotspots(filtered: boolean) {
return (
<div className="display-flex-column display-flex-center huge-spacer-top">
<img
alt={translate('hotspots.page')}
className="huge-spacer-top"
height={100}
src={`${getBaseUrl()}/images/${filtered ? 'filter-large' : 'hotspot-large'}.svg`}
/>
<h1 className="huge-spacer-top">
{filtered
? translate('hotspots.no_hotspots_for_filters.title')
: translate('hotspots.no_hotspots.title')}
</h1>
<div className="abs-width-400 text-center big-spacer-top">
{filtered
? translate('hotspots.no_hotspots_for_filters.description')
: translate('hotspots.no_hotspots.description')}
</div>
{!filtered && (
<Link
className="big-spacer-top"
target="_blank"
to={{ pathname: '/documentation/user-guide/security-hotspots/' }}>
{translate('hotspots.learn_more')}
</Link>
)}
</div>
);
}

export default function SecurityHotspotsAppRenderer(props: SecurityHotspotsAppRendererProps) {
const {
branchLike,
@@ -117,9 +90,14 @@ export default function SecurityHotspotsAppRenderer(props: SecurityHotspotsAppRe
) : (
<>
{hotspots.length === 0 ? (
renderNoHotspots(
filters.assignedToMe || (filters.sinceLeakPeriod && isBranch(branchLike))
)
<EmptyHotspotsPage
filtered={
filters.assignedToMe ||
(isBranch(branchLike) && filters.sinceLeakPeriod) ||
filters.status !== HotspotStatusFilter.TO_REVIEW
}
isStaticListOfHotspots={isStaticListOfHotspots}
/>
) : (
<div className="layout-page">
<div className="sidebar">

+ 8
- 53
server/sonar-web/src/main/js/apps/securityHotspots/__tests__/__snapshots__/SecurityHotspotsAppRenderer-test.tsx.snap View File

@@ -209,39 +209,10 @@ exports[`should render correctly: no hotspots 1`] = `
<A11ySkipTarget
anchor="security_hotspots_main"
/>
<div
className="display-flex-column display-flex-center huge-spacer-top"
>
<img
alt="hotspots.page"
className="huge-spacer-top"
height={100}
src="/images/hotspot-large.svg"
/>
<h1
className="huge-spacer-top"
>
hotspots.no_hotspots.title
</h1>
<div
className="abs-width-400 text-center big-spacer-top"
>
hotspots.no_hotspots.description
</div>
<Link
className="big-spacer-top"
onlyActiveOnIndex={false}
style={Object {}}
target="_blank"
to={
Object {
"pathname": "/documentation/user-guide/security-hotspots/",
}
}
>
hotspots.learn_more
</Link>
</div>
<EmptyHotspotsPage
filtered={false}
isStaticListOfHotspots={true}
/>
</div>
</div>
`;
@@ -267,26 +238,10 @@ exports[`should render correctly: no hotspots with filters 1`] = `
<A11ySkipTarget
anchor="security_hotspots_main"
/>
<div
className="display-flex-column display-flex-center huge-spacer-top"
>
<img
alt="hotspots.page"
className="huge-spacer-top"
height={100}
src="/images/filter-large.svg"
/>
<h1
className="huge-spacer-top"
>
hotspots.no_hotspots_for_filters.title
</h1>
<div
className="abs-width-400 text-center big-spacer-top"
>
hotspots.no_hotspots_for_filters.description
</div>
</div>
<EmptyHotspotsPage
filtered={true}
isStaticListOfHotspots={true}
/>
</div>
</div>
`;

+ 64
- 0
server/sonar-web/src/main/js/apps/securityHotspots/components/EmptyHotspotsPage.tsx View File

@@ -0,0 +1,64 @@
/*
* SonarQube
* Copyright (C) 2009-2020 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
import { Link } from 'react-router';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { getBaseUrl } from 'sonar-ui-common/helpers/urls';

export interface EmptyHotspotsPageProps {
filtered: boolean;
isStaticListOfHotspots: boolean;
}

export default function EmptyHotspotsPage(props: EmptyHotspotsPageProps) {
const { filtered, isStaticListOfHotspots } = props;

let translationRoot;
if (isStaticListOfHotspots) {
translationRoot = 'no_hotspots_for_keys';
} else if (filtered) {
translationRoot = 'no_hotspots_for_filters';
} else {
translationRoot = 'no_hotspots';
}

return (
<div className="display-flex-column display-flex-center huge-spacer-top">
<img
alt={translate('hotspots.page')}
className="huge-spacer-top"
height={100}
src={`${getBaseUrl()}/images/${filtered ? 'filter-large' : 'hotspot-large'}.svg`}
/>
<h1 className="huge-spacer-top">{translate(`hotspots.${translationRoot}.title`)}</h1>
<div className="abs-width-400 text-center big-spacer-top">
{translate(`hotspots.${translationRoot}.description`)}
</div>
{!(filtered || isStaticListOfHotspots) && (
<Link
className="big-spacer-top"
target="_blank"
to={{ pathname: '/documentation/user-guide/security-hotspots/' }}>
{translate('hotspots.learn_more')}
</Link>
)}
</div>
);
}

+ 32
- 0
server/sonar-web/src/main/js/apps/securityHotspots/components/__tests__/EmptyHotspotsPage-test.tsx View File

@@ -0,0 +1,32 @@
/*
* SonarQube
* Copyright (C) 2009-2020 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { shallow } from 'enzyme';
import * as React from 'react';
import EmptyHotspotsPage, { EmptyHotspotsPageProps } from '../EmptyHotspotsPage';

it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot();
expect(shallowRender({ filtered: true })).toMatchSnapshot('filtered');
expect(shallowRender({ isStaticListOfHotspots: true })).toMatchSnapshot('keys');
});

function shallowRender(props: Partial<EmptyHotspotsPageProps> = {}) {
return shallow(<EmptyHotspotsPage filtered={false} isStaticListOfHotspots={false} {...props} />);
}

+ 83
- 0
server/sonar-web/src/main/js/apps/securityHotspots/components/__tests__/__snapshots__/EmptyHotspotsPage-test.tsx.snap View File

@@ -0,0 +1,83 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should render correctly 1`] = `
<div
className="display-flex-column display-flex-center huge-spacer-top"
>
<img
alt="hotspots.page"
className="huge-spacer-top"
height={100}
src="/images/hotspot-large.svg"
/>
<h1
className="huge-spacer-top"
>
hotspots.no_hotspots.title
</h1>
<div
className="abs-width-400 text-center big-spacer-top"
>
hotspots.no_hotspots.description
</div>
<Link
className="big-spacer-top"
onlyActiveOnIndex={false}
style={Object {}}
target="_blank"
to={
Object {
"pathname": "/documentation/user-guide/security-hotspots/",
}
}
>
hotspots.learn_more
</Link>
</div>
`;

exports[`should render correctly: filtered 1`] = `
<div
className="display-flex-column display-flex-center huge-spacer-top"
>
<img
alt="hotspots.page"
className="huge-spacer-top"
height={100}
src="/images/filter-large.svg"
/>
<h1
className="huge-spacer-top"
>
hotspots.no_hotspots_for_filters.title
</h1>
<div
className="abs-width-400 text-center big-spacer-top"
>
hotspots.no_hotspots_for_filters.description
</div>
</div>
`;

exports[`should render correctly: keys 1`] = `
<div
className="display-flex-column display-flex-center huge-spacer-top"
>
<img
alt="hotspots.page"
className="huge-spacer-top"
height={100}
src="/images/hotspot-large.svg"
/>
<h1
className="huge-spacer-top"
>
hotspots.no_hotspots_for_keys.title
</h1>
<div
className="abs-width-400 text-center big-spacer-top"
>
hotspots.no_hotspots_for_keys.description
</div>
</div>
`;

+ 2
- 0
sonar-core/src/main/resources/org/sonar/l10n/core.properties View File

@@ -649,6 +649,8 @@ hotspots.no_hotspots.title=There are no Security Hotspots to review.
hotspots.no_hotspots.description=Next time you analyse a piece of code that contains a potential security risk, it will show up here.
hotspots.no_hotspots_for_filters.title=We couldn't find any results matching the selected criteria.
hotspots.no_hotspots_for_filters.description=Try changing the filters to get some results.
hotspots.no_hotspots_for_keys.title=The requested hotspots no longer exist.
hotspots.no_hotspots_for_keys.description=They have been closed because the code involved has been changed or removed.
hotspots.learn_more=Learn more about Security Hotspots
hotspots.list_title={0} Security Hotspots
hotspots.list_title.TO_REVIEW={0} Security Hotspots to review

Loading…
Cancel
Save