Selaa lähdekoodia

SONAR-12718 Revamp hotspot information layout

tags/8.2.0.32929
Philippe Perrin 4 vuotta sitten
vanhempi
commit
b381bc38fd
15 muutettua tiedostoa jossa 1408 lisäystä ja 1250 poistoa
  1. 4
    0
      server/sonar-web/src/main/js/app/styles/init/misc.css
  2. 1
    1
      server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotList.tsx
  3. 27
    0
      server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewer.css
  4. 37
    16
      server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerRenderer.tsx
  5. 4
    0
      server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotList-test.tsx.snap
  6. 1229
    1079
      server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewerRenderer-test.tsx.snap
  7. 26
    32
      server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/AssigneeRenderer.tsx
  8. 5
    0
      server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/AssigneeSelection.css
  9. 1
    4
      server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/AssigneeSelectionRenderer.tsx
  10. 68
    110
      server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/__snapshots__/AssigneeRenderer-test.tsx.snap
  11. 0
    2
      server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/__snapshots__/AssigneeSelectionRenderer-test.tsx.snap
  12. 1
    1
      server/sonar-web/src/main/js/apps/security-hotspots/components/status/Status.css
  13. 1
    1
      server/sonar-web/src/main/js/apps/security-hotspots/components/status/Status.tsx
  14. 3
    3
      server/sonar-web/src/main/js/apps/security-hotspots/components/status/__tests__/__snapshots__/Status-test.tsx.snap
  15. 1
    1
      sonar-core/src/main/resources/org/sonar/l10n/core.properties

+ 4
- 0
server/sonar-web/src/main/js/app/styles/init/misc.css Näytä tiedosto

@@ -440,6 +440,10 @@ th.huge-spacer-right {
flex: 1;
}

.flex-1-0-auto {
flex: 1 0 auto;
}

.flex-0 {
flex: 0 0 auto;
}

+ 1
- 1
server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotList.tsx Näytä tiedosto

@@ -119,7 +119,7 @@ export default class HotspotList extends React.Component<Props, State> {
{groupedHotspots.map(riskGroup => (
<li className="big-spacer-bottom" key={riskGroup.risk}>
<div className="hotspot-risk-header little-spacer-left">
<span>{translate('hotspots.risk_exposure')}</span>
<span>{translate('hotspots.risk_exposure')}:</span>
<div className={classNames('hotspot-risk-badge', 'spacer-left', riskGroup.risk)}>
{translate('risk_exposure', riskGroup.risk)}
</div>

+ 27
- 0
server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewer.css Näytä tiedosto

@@ -0,0 +1,27 @@
/*
* 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.
*/

.hotspot-information {
flex-basis: 320px;
}

.hotspot-information > div > span {
flex-basis: 100px;
}

+ 37
- 16
server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerRenderer.tsx Näytä tiedosto

@@ -17,6 +17,7 @@
* 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 classNames from 'classnames';
import * as React from 'react';
import { ClipboardButton } from 'sonar-ui-common/components/controls/clipboard';
import LinkIcon from 'sonar-ui-common/components/icons/LinkIcon';
@@ -29,6 +30,7 @@ import { BranchLike } from '../../../types/branch-like';
import { Hotspot } from '../../../types/security-hotspots';
import Assignee from './assignee/Assignee';
import HotspotSnippetContainer from './HotspotSnippetContainer';
import './HotspotViewer.css';
import HotspotViewerTabs from './HotspotViewerTabs';
import Status from './status/Status';

@@ -56,25 +58,44 @@ export default function HotspotViewerRenderer(props: HotspotViewerRendererProps)
<DeferredSpinner loading={loading}>
{hotspot && (
<div className="big-padded">
<div className="big-spacer-bottom">
<div className="display-flex-space-between">
<strong className="big">{hotspot.message}</strong>
<ClipboardButton copyValue={permalink}>
<LinkIcon className="spacer-right" />
<span>{translate('hotspots.get_permalink')}</span>
</ClipboardButton>
<div className="huge-spacer-bottom display-flex-space-between">
<strong className="big big-spacer-right">{hotspot.message}</strong>
<ClipboardButton copyValue={permalink}>
<LinkIcon className="spacer-right" />
<span>{translate('hotspots.get_permalink')}</span>
</ClipboardButton>
</div>

<div className="huge-spacer-bottom display-flex-row">
<div className="hotspot-information display-flex-column display-flex-space-between">
<div className="display-flex-center">
<span className="big-spacer-right">{translate('category')}</span>
<strong className="nowrap">
{securityCategories[hotspot.rule.securityCategory].title}
</strong>
</div>
<div className="display-flex-center">
<span className="big-spacer-right">{translate('hotspots.risk_exposure')}</span>
<div
className={classNames(
'hotspot-risk-badge',
hotspot.rule.vulnerabilityProbability
)}>
{translate('risk_exposure', hotspot.rule.vulnerabilityProbability)}
</div>
</div>
<div className="display-flex-center">
<span className="big-spacer-right">{translate('assignee')}</span>
<div>
<Assignee hotspot={hotspot} onAssigneeChange={props.onUpdateHotspot} />
</div>
</div>
</div>
<div className="text-muted">
<span>{translate('category')}:</span>
<span className="little-spacer-left">
{securityCategories[hotspot.rule.securityCategory].title}
</span>
<div className="huge-spacer-left">
<Status hotspot={hotspot} onStatusChange={props.onUpdateHotspot} />
</div>
</div>
<div className="display-flex-row huge-spacer-bottom">
<Assignee hotspot={hotspot} onAssigneeChange={props.onUpdateHotspot} />
<Status hotspot={hotspot} onStatusChange={props.onUpdateHotspot} />
</div>

<HotspotSnippetContainer branchLike={branchLike} hotspot={hotspot} />
<HotspotViewerTabs hotspot={hotspot} onUpdateHotspot={props.onUpdateHotspot} />
</div>

+ 4
- 0
server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotList-test.tsx.snap Näytä tiedosto

@@ -92,6 +92,7 @@ exports[`should render correctly with hotspots: no pagination 1`] = `
>
<span>
hotspots.risk_exposure
:
</span>
<div
className="hotspot-risk-badge spacer-left HIGH"
@@ -205,6 +206,7 @@ exports[`should render correctly with hotspots: no pagination 1`] = `
>
<span>
hotspots.risk_exposure
:
</span>
<div
className="hotspot-risk-badge spacer-left MEDIUM"
@@ -357,6 +359,7 @@ exports[`should render correctly with hotspots: pagination 1`] = `
>
<span>
hotspots.risk_exposure
:
</span>
<div
className="hotspot-risk-badge spacer-left HIGH"
@@ -470,6 +473,7 @@ exports[`should render correctly with hotspots: pagination 1`] = `
>
<span>
hotspots.risk_exposure
:
</span>
<div
className="hotspot-risk-badge spacer-left MEDIUM"

+ 1229
- 1079
server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewerRenderer-test.tsx.snap
File diff suppressed because it is too large
Näytä tiedosto


+ 26
- 32
server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/AssigneeRenderer.tsx Näytä tiedosto

@@ -43,39 +43,33 @@ export default function AssigneeRenderer(props: AssigneeRendererProps) {
const { assignee, canEdit, loggedInUser, editing, loading } = props;

return (
<div className="big-spacer-top display-flex-center">
<span>{translate('assignee')}:</span>

<span className="spacer-left">
<DeferredSpinner loading={loading}>
{!editing && (
<div className="display-flex-center">
<strong>
{assignee &&
(assignee.active
? assignee.name ?? assignee.login
: translateWithParameters('user.x_deleted', assignee.name ?? assignee.login))}
{!assignee && translate('unassigned')}
</strong>
{loggedInUser && canEdit && (
<EditButton className="spacer-left" onClick={props.onEnterEditionMode} />
)}
</div>
<DeferredSpinner loading={loading}>
{!editing && (
<div className="display-flex-center">
<strong className="nowrap">
{assignee &&
(assignee.active
? assignee.name ?? assignee.login
: translateWithParameters('user.x_deleted', assignee.name ?? assignee.login))}
{!assignee && translate('unassigned')}
</strong>
{loggedInUser && canEdit && (
<EditButton className="spacer-left" onClick={props.onEnterEditionMode} />
)}
</div>
)}

{loggedInUser && editing && (
<EscKeydownHandler onKeydown={props.onExitEditionMode}>
<OutsideClickHandler onClickOutside={props.onExitEditionMode}>
<AssigneeSelection
allowCurrentUserSelection={loggedInUser.login !== assignee?.login}
loggedInUser={loggedInUser}
onSelect={props.onAssign}
/>
</OutsideClickHandler>
</EscKeydownHandler>
)}
</DeferredSpinner>
</span>
</div>
{loggedInUser && editing && (
<EscKeydownHandler onKeydown={props.onExitEditionMode}>
<OutsideClickHandler onClickOutside={props.onExitEditionMode}>
<AssigneeSelection
allowCurrentUserSelection={loggedInUser.login !== assignee?.login}
loggedInUser={loggedInUser}
onSelect={props.onAssign}
/>
</OutsideClickHandler>
</EscKeydownHandler>
)}
</DeferredSpinner>
);
}

+ 5
- 0
server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/AssigneeSelection.css Näytä tiedosto

@@ -17,6 +17,11 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

.hotspot-assignee-search-results {
min-width: 300px;
}

.hotspot-assignee-search-results li {
cursor: pointer;
}

+ 1
- 4
server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/AssigneeSelectionRenderer.tsx Näytä tiedosto

@@ -56,10 +56,7 @@ export default function AssigneeSelectionRenderer(props: HotspotAssigneeSelectRe

{!loading && open && (
<div className="position-relative">
<DropdownOverlay
className="abs-width-400"
noPadding={true}
placement={PopupPlacement.BottomLeft}>
<DropdownOverlay noPadding={true} placement={PopupPlacement.BottomLeft}>
{suggestedUsers && suggestedUsers.length > 0 ? (
<ul className="hotspot-assignee-search-results">
{suggestedUsers.map(suggestion => (

+ 68
- 110
server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/__snapshots__/AssigneeRenderer-test.tsx.snap Näytä tiedosto

@@ -1,135 +1,93 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should render correctly: editing 1`] = `
<div
className="big-spacer-top display-flex-center"
<DeferredSpinner
loading={false}
timeout={100}
>
<span>
assignee
:
</span>
<span
className="spacer-left"
<EscKeydownHandler
onKeydown={[MockFunction]}
>
<DeferredSpinner
loading={false}
timeout={100}
<OutsideClickHandler
onClickOutside={[MockFunction]}
>
<EscKeydownHandler
onKeydown={[MockFunction]}
>
<OutsideClickHandler
onClickOutside={[MockFunction]}
>
<AssigneeSelection
allowCurrentUserSelection={false}
loggedInUser={
Object {
"groups": Array [],
"isLoggedIn": true,
"login": "luke",
"name": "Skywalker",
"scmAccounts": Array [],
}
}
onSelect={[MockFunction]}
/>
</OutsideClickHandler>
</EscKeydownHandler>
</DeferredSpinner>
</span>
</div>
<AssigneeSelection
allowCurrentUserSelection={false}
loggedInUser={
Object {
"groups": Array [],
"isLoggedIn": true,
"login": "luke",
"name": "Skywalker",
"scmAccounts": Array [],
}
}
onSelect={[MockFunction]}
/>
</OutsideClickHandler>
</EscKeydownHandler>
</DeferredSpinner>
`;

exports[`should render correctly: not editing 1`] = `
<div
className="big-spacer-top display-flex-center"
<DeferredSpinner
loading={false}
timeout={100}
>
<span>
assignee
:
</span>
<span
className="spacer-left"
<div
className="display-flex-center"
>
<DeferredSpinner
loading={false}
timeout={100}
<strong
className="nowrap"
>
<div
className="display-flex-center"
>
<strong>
user.x_deleted.Skywalker
</strong>
<EditButton
className="spacer-left"
onClick={[MockFunction]}
/>
</div>
</DeferredSpinner>
</span>
</div>
user.x_deleted.Skywalker
</strong>
<EditButton
className="spacer-left"
onClick={[MockFunction]}
/>
</div>
</DeferredSpinner>
`;

exports[`should render correctly: with active assignee 1`] = `
<div
className="big-spacer-top display-flex-center"
<DeferredSpinner
loading={false}
timeout={100}
>
<span>
assignee
:
</span>
<span
className="spacer-left"
<div
className="display-flex-center"
>
<DeferredSpinner
loading={false}
timeout={100}
<strong
className="nowrap"
>
<div
className="display-flex-center"
>
<strong>
John Doe
</strong>
<EditButton
className="spacer-left"
onClick={[MockFunction]}
/>
</div>
</DeferredSpinner>
</span>
</div>
John Doe
</strong>
<EditButton
className="spacer-left"
onClick={[MockFunction]}
/>
</div>
</DeferredSpinner>
`;

exports[`should render correctly: without current assignee 1`] = `
<div
className="big-spacer-top display-flex-center"
<DeferredSpinner
loading={false}
timeout={100}
>
<span>
assignee
:
</span>
<span
className="spacer-left"
<div
className="display-flex-center"
>
<DeferredSpinner
loading={false}
timeout={100}
<strong
className="nowrap"
>
<div
className="display-flex-center"
>
<strong>
unassigned
</strong>
<EditButton
className="spacer-left"
onClick={[MockFunction]}
/>
</div>
</DeferredSpinner>
</span>
</div>
unassigned
</strong>
<EditButton
className="spacer-left"
onClick={[MockFunction]}
/>
</div>
</DeferredSpinner>
`;

+ 0
- 2
server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/__snapshots__/AssigneeSelectionRenderer-test.tsx.snap Näytä tiedosto

@@ -50,7 +50,6 @@ exports[`should render correctly: open 1`] = `
className="position-relative"
>
<DropdownOverlay
className="abs-width-400"
noPadding={true}
placement="bottom-left"
>
@@ -80,7 +79,6 @@ exports[`should render correctly: open with results 1`] = `
className="position-relative"
>
<DropdownOverlay
className="abs-width-400"
noPadding={true}
placement="bottom-left"
>

+ 1
- 1
server/sonar-web/src/main/js/apps/security-hotspots/components/status/Status.css Näytä tiedosto

@@ -19,7 +19,7 @@
*/

#status-trigger,
.popup {
#status-trigger + .popup {
width: 400px;
box-sizing: border-box;
}

+ 1
- 1
server/sonar-web/src/main/js/apps/security-hotspots/components/status/Status.tsx Näytä tiedosto

@@ -92,7 +92,7 @@ export function Status(props: StatusProps) {
);

return (
<div className="dropdown huge-spacer-left">
<div className="dropdown">
{readonly ? (
<Tooltip overlay={translate('hotspots.status.cannot_change_status')} placement="bottom">
{actionableTrigger}

+ 3
- 3
server/sonar-web/src/main/js/apps/security-hotspots/components/status/__tests__/__snapshots__/Status-test.tsx.snap Näytä tiedosto

@@ -2,7 +2,7 @@

exports[`should render correctly: closed 1`] = `
<div
className="dropdown huge-spacer-left"
className="dropdown"
>
<Toggler
closeOnClickOutside={true}
@@ -146,7 +146,7 @@ exports[`should render correctly: closed 1`] = `

exports[`should render correctly: open 1`] = `
<div
className="dropdown huge-spacer-left"
className="dropdown"
>
<Toggler
closeOnClickOutside={true}
@@ -291,7 +291,7 @@ exports[`should render correctly: open 1`] = `

exports[`should render correctly: readonly 1`] = `
<div
className="dropdown huge-spacer-left"
className="dropdown"
>
<Tooltip
overlay="hotspots.status.cannot_change_status"

+ 1
- 1
sonar-core/src/main/resources/org/sonar/l10n/core.properties Näytä tiedosto

@@ -662,7 +662,7 @@ hotspots.list_title={0} Security Hotspots
hotspots.list_title.TO_REVIEW={0} Security Hotspots to review
hotspots.list_title.FIXED={0} Security Hotspots reviewed as fixed
hotspots.list_title.SAFE={0} Security Hotspots reviewed as safe
hotspots.risk_exposure=Review priority:
hotspots.risk_exposure=Review priority

hotspots.tabs.risk_description=What's the risk?
hotspots.tabs.vulnerability_description=Are you at risk?

Loading…
Peruuta
Tallenna