Browse Source

SONAR-11885 Add Hotspots to Overview page

* Update Measures links on Overview page
* Add tooltips to the issues and metrics on the Overview page
* Move activity page links on the Overview page
* Add tests for untested components
* Add bugs and vulnerabilities graphs on overview page
tags/7.8
Grégoire Aubert 5 years ago
parent
commit
b92d5bf549
35 changed files with 2029 additions and 178 deletions
  1. 1
    0
      server/sonar-docs/src/tooltips/metrics/bugs.md
  2. 1
    0
      server/sonar-docs/src/tooltips/metrics/code-smells.md
  3. 1
    0
      server/sonar-docs/src/tooltips/metrics/coverage.md
  4. 1
    0
      server/sonar-docs/src/tooltips/metrics/debt.md
  5. 1
    0
      server/sonar-docs/src/tooltips/metrics/duplicated-blocks.md
  6. 1
    0
      server/sonar-docs/src/tooltips/metrics/duplications.md
  7. 1
    0
      server/sonar-docs/src/tooltips/metrics/security-hotspots.md
  8. 1
    0
      server/sonar-docs/src/tooltips/metrics/unit-tests.md
  9. 1
    0
      server/sonar-docs/src/tooltips/metrics/vulnerabilities.md
  10. 5
    0
      server/sonar-web/src/main/js/app/styles/init/misc.css
  11. 4
    2
      server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx
  12. 6
    16
      server/sonar-web/src/main/js/apps/overview/components/__tests__/OverviewApp-test.tsx
  13. 191
    8
      server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/OverviewApp-test.tsx.snap
  14. 34
    60
      server/sonar-web/src/main/js/apps/overview/main/Bugs.tsx
  15. 19
    33
      server/sonar-web/src/main/js/apps/overview/main/CodeSmells.tsx
  16. 20
    6
      server/sonar-web/src/main/js/apps/overview/main/Coverage.tsx
  17. 16
    5
      server/sonar-web/src/main/js/apps/overview/main/Duplications.tsx
  18. 127
    0
      server/sonar-web/src/main/js/apps/overview/main/VulnerabilitiesAndHotspots.tsx
  19. 87
    0
      server/sonar-web/src/main/js/apps/overview/main/__tests__/Bugs-test.tsx
  20. 113
    0
      server/sonar-web/src/main/js/apps/overview/main/__tests__/CodeSmells-test.tsx
  21. 73
    0
      server/sonar-web/src/main/js/apps/overview/main/__tests__/Coverage-test.tsx
  22. 92
    0
      server/sonar-web/src/main/js/apps/overview/main/__tests__/Duplications-test.tsx
  23. 119
    0
      server/sonar-web/src/main/js/apps/overview/main/__tests__/VulnerabilitiesAndHotspots-test.tsx
  24. 180
    0
      server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/Bugs-test.tsx.snap
  25. 223
    0
      server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/CodeSmells-test.tsx.snap
  26. 187
    0
      server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/Coverage-test.tsx.snap
  27. 166
    0
      server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/Duplications-test.tsx.snap
  28. 288
    0
      server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/VulnerabilitiesAndHotspots-test.tsx.snap
  29. 15
    12
      server/sonar-web/src/main/js/apps/overview/main/enhance.tsx
  30. 28
    32
      server/sonar-web/src/main/js/apps/overview/styles.css
  31. 4
    0
      server/sonar-web/src/main/js/apps/overview/utils.ts
  32. 1
    1
      server/sonar-web/src/main/js/apps/securityReports/components/VulnerabilityList.tsx
  33. 2
    2
      server/sonar-web/src/main/js/apps/securityReports/components/__tests__/__snapshots__/VulnerabilityList-test.tsx.snap
  34. 17
    0
      server/sonar-web/src/main/js/helpers/testMocks.ts
  35. 3
    1
      sonar-core/src/main/resources/org/sonar/l10n/core.properties

+ 1
- 0
server/sonar-docs/src/tooltips/metrics/bugs.md View File

@@ -0,0 +1 @@
A coding error that will break your code and needs to be fixed immediately.

+ 1
- 0
server/sonar-docs/src/tooltips/metrics/code-smells.md View File

@@ -0,0 +1 @@
Code that is confusing and difficult to maintain.

+ 1
- 0
server/sonar-docs/src/tooltips/metrics/coverage.md View File

@@ -0,0 +1 @@
The percentage of lines of code covered by tests.

+ 1
- 0
server/sonar-docs/src/tooltips/metrics/debt.md View File

@@ -0,0 +1 @@
The estimated time it will take to fix all Code Smells.

+ 1
- 0
server/sonar-docs/src/tooltips/metrics/duplicated-blocks.md View File

@@ -0,0 +1 @@
The number of duplicated blocks of lines of code.

+ 1
- 0
server/sonar-docs/src/tooltips/metrics/duplications.md View File

@@ -0,0 +1 @@
Identical lines of code.

+ 1
- 0
server/sonar-docs/src/tooltips/metrics/security-hotspots.md View File

@@ -0,0 +1 @@
Security-sensitive code that requires manual review to assess whether or not a vulnerability exists.

+ 1
- 0
server/sonar-docs/src/tooltips/metrics/unit-tests.md View File

@@ -0,0 +1 @@
Tests that ensure your code is working properly.

+ 1
- 0
server/sonar-docs/src/tooltips/metrics/vulnerabilities.md View File

@@ -0,0 +1 @@
Code that can be exploited by hackers.

+ 5
- 0
server/sonar-web/src/main/js/app/styles/init/misc.css View File

@@ -307,6 +307,11 @@ td.big-spacer-top {
align-items: center;
}

.display-flex-justify-center {
display: flex !important;
justify-content: center;
}

.display-flex-space-around {
display: flex !important;
justify-content: space-around;

+ 4
- 2
server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx View File

@@ -21,10 +21,11 @@ import * as React from 'react';
import { uniq } from 'lodash';
import { connect } from 'react-redux';
import ApplicationQualityGate from '../qualityGate/ApplicationQualityGate';
import BugsAndVulnerabilities from '../main/BugsAndVulnerabilities';
import Bugs from '../main/Bugs';
import CodeSmells from '../main/CodeSmells';
import Coverage from '../main/Coverage';
import Duplications from '../main/Duplications';
import VulnerabilitiesAndHotspots from '../main/VulnerabilitiesAndHotspots';
import MetaContainer from '../meta/MetaContainer';
import QualityGate from '../qualityGate/QualityGate';
import A11ySkipTarget from '../../../app/components/a11y/A11ySkipTarget';
@@ -213,7 +214,8 @@ export class OverviewApp extends React.PureComponent<Props, State> {
)}

<div className="overview-domains-list">
<BugsAndVulnerabilities {...domainProps} />
<Bugs {...domainProps} />
<VulnerabilitiesAndHotspots {...domainProps} />
<CodeSmells {...domainProps} />
<Coverage {...domainProps} />
<Duplications {...domainProps} />

+ 6
- 16
server/sonar-web/src/main/js/apps/overview/components/__tests__/OverviewApp-test.tsx View File

@@ -50,22 +50,12 @@ jest.mock('../../../../helpers/dates', () => ({
jest.mock('../../../../api/time-machine', () => ({
getAllTimeMachineData: jest.fn().mockResolvedValue({
measures: [
{
metric: 'sqale_index',
history: [{ date: '2019-01-01', value: '1.0' }]
},
{
metric: 'duplicated_lines_density',
history: [{ date: '2019-01-02', value: '1.0' }]
},
{
metric: 'ncloc',
history: [{ date: '2019-01-03', value: '10000' }]
},
{
metric: 'coverage',
history: [{ date: '2019-01-04', value: '95.5' }]
}
{ metric: 'bugs', history: [{ date: '2019-01-05', value: '2.0' }] },
{ metric: 'vulnerabilities', history: [{ date: '2019-01-05', value: '0' }] },
{ metric: 'sqale_index', history: [{ date: '2019-01-01', value: '1.0' }] },
{ metric: 'duplicated_lines_density', history: [{ date: '2019-01-02', value: '1.0' }] },
{ metric: 'ncloc', history: [{ date: '2019-01-03', value: '10000' }] },
{ metric: 'coverage', history: [{ date: '2019-01-04', value: '95.5' }] }
]
})
}));

+ 191
- 8
server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/OverviewApp-test.tsx.snap View File

@@ -96,7 +96,7 @@ exports[`should render correctly 2`] = `
<div
className="overview-domains-list"
>
<enhance(undefined)}
<enhance(Bugs)
branchLike={
Object {
"analysisDate": "2018-01-01",
@@ -129,6 +129,12 @@ exports[`should render correctly 2`] = `
}
history={
Object {
"bugs": Array [
Object {
"date": "2019-01-05",
"value": "2.0",
},
],
"coverage": Array [
Object {
"date": "2019-01-04",
@@ -153,9 +159,15 @@ exports[`should render correctly 2`] = `
"value": "1.0",
},
],
"vulnerabilities": Array [
Object {
"date": "2019-01-05",
"value": "0",
},
],
}
}
historyStartDate="2019-01-01"
historyStartDate="2019-01-05"
measures={
Array [
Object {
@@ -195,7 +207,7 @@ exports[`should render correctly 2`] = `
]
}
/>
<enhance(undefined)}
<enhance(VulnerabiltiesAndHotspots)
branchLike={
Object {
"analysisDate": "2018-01-01",
@@ -228,6 +240,12 @@ exports[`should render correctly 2`] = `
}
history={
Object {
"bugs": Array [
Object {
"date": "2019-01-05",
"value": "2.0",
},
],
"coverage": Array [
Object {
"date": "2019-01-04",
@@ -252,9 +270,15 @@ exports[`should render correctly 2`] = `
"value": "1.0",
},
],
"vulnerabilities": Array [
Object {
"date": "2019-01-05",
"value": "0",
},
],
}
}
historyStartDate="2019-01-01"
historyStartDate="2019-01-05"
measures={
Array [
Object {
@@ -294,7 +318,7 @@ exports[`should render correctly 2`] = `
]
}
/>
<enhance(undefined)}
<enhance(CodeSmells)
branchLike={
Object {
"analysisDate": "2018-01-01",
@@ -327,6 +351,12 @@ exports[`should render correctly 2`] = `
}
history={
Object {
"bugs": Array [
Object {
"date": "2019-01-05",
"value": "2.0",
},
],
"coverage": Array [
Object {
"date": "2019-01-04",
@@ -351,9 +381,15 @@ exports[`should render correctly 2`] = `
"value": "1.0",
},
],
"vulnerabilities": Array [
Object {
"date": "2019-01-05",
"value": "0",
},
],
}
}
historyStartDate="2019-01-01"
historyStartDate="2019-01-05"
measures={
Array [
Object {
@@ -393,7 +429,7 @@ exports[`should render correctly 2`] = `
]
}
/>
<enhance(undefined)}
<enhance(Coverage)
branchLike={
Object {
"analysisDate": "2018-01-01",
@@ -426,6 +462,12 @@ exports[`should render correctly 2`] = `
}
history={
Object {
"bugs": Array [
Object {
"date": "2019-01-05",
"value": "2.0",
},
],
"coverage": Array [
Object {
"date": "2019-01-04",
@@ -450,9 +492,126 @@ exports[`should render correctly 2`] = `
"value": "1.0",
},
],
"vulnerabilities": Array [
Object {
"date": "2019-01-05",
"value": "0",
},
],
}
}
historyStartDate="2019-01-01"
historyStartDate="2019-01-05"
measures={
Array [
Object {
"bestValue": true,
"metric": Object {
"id": "coverage",
"key": "ncloc",
"name": "Coverage",
"type": "PERCENT",
},
"periods": Array [
Object {
"bestValue": true,
"index": 1,
"value": "1.0",
},
],
"value": "1.0",
},
Object {
"bestValue": true,
"metric": Object {
"id": "coverage",
"key": "coverage",
"name": "Coverage",
"type": "PERCENT",
},
"periods": Array [
Object {
"bestValue": true,
"index": 1,
"value": "1.0",
},
],
"value": "1.0",
},
]
}
/>
<enhance(Duplications)
branchLike={
Object {
"analysisDate": "2018-01-01",
"isMain": true,
"name": "master",
}
}
component={
Object {
"breadcrumbs": Array [],
"key": "my-project",
"name": "foo",
"organization": "foo",
"qualifier": "TRK",
"qualityGate": Object {
"isDefault": true,
"key": "30",
"name": "Sonar way",
},
"qualityProfiles": Array [
Object {
"deleted": false,
"key": "my-qp",
"language": "ts",
"name": "Sonar way",
},
],
"tags": Array [],
}
}
history={
Object {
"bugs": Array [
Object {
"date": "2019-01-05",
"value": "2.0",
},
],
"coverage": Array [
Object {
"date": "2019-01-04",
"value": "95.5",
},
],
"duplicated_lines_density": Array [
Object {
"date": "2019-01-02",
"value": "1.0",
},
],
"ncloc": Array [
Object {
"date": "2019-01-03",
"value": "10000",
},
],
"sqale_index": Array [
Object {
"date": "2019-01-01",
"value": "1.0",
},
],
"vulnerabilities": Array [
Object {
"date": "2019-01-05",
"value": "0",
},
],
}
}
historyStartDate="2019-01-05"
measures={
Array [
Object {
@@ -530,6 +689,12 @@ exports[`should render correctly 2`] = `
}
history={
Object {
"bugs": Array [
Object {
"date": "2019-01-05",
"value": "2.0",
},
],
"coverage": Array [
Object {
"date": "2019-01-04",
@@ -554,6 +719,12 @@ exports[`should render correctly 2`] = `
"value": "1.0",
},
],
"vulnerabilities": Array [
Object {
"date": "2019-01-05",
"value": "0",
},
],
}
}
measures={
@@ -664,6 +835,12 @@ exports[`should render correctly if no measures are found 1`] = `
}
history={
Object {
"bugs": Array [
Object {
"date": "2019-01-05",
"value": "2.0",
},
],
"coverage": Array [
Object {
"date": "2019-01-04",
@@ -688,6 +865,12 @@ exports[`should render correctly if no measures are found 1`] = `
"value": "1.0",
},
],
"vulnerabilities": Array [
Object {
"date": "2019-01-05",
"value": "0",
},
],
}
}
measures={

server/sonar-web/src/main/js/apps/overview/main/BugsAndVulnerabilities.tsx → server/sonar-web/src/main/js/apps/overview/main/Bugs.tsx View File

@@ -18,49 +18,40 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
import { Link } from 'react-router';
import enhance, { ComposedProps } from './enhance';
import ApplicationLeakPeriodLegend from '../components/ApplicationLeakPeriodLegend';
import BubblesIcon from '../../../components/icons-components/BubblesIcon';
import BugIcon from '../../../components/icons-components/BugIcon';
import DocTooltip from '../../../components/docs/DocTooltip';
import DateFromNow from '../../../components/intl/DateFromNow';
import LeakPeriodLegend from '../components/LeakPeriodLegend';
import VulnerabilityIcon from '../../../components/icons-components/VulnerabilityIcon';
import { getMetricName } from '../utils';
import { getComponentDrilldownUrl } from '../../../helpers/urls';
import { translate } from '../../../helpers/l10n';
import { isLongLivingBranch } from '../../../helpers/branches';
import { translateWithParameters } from '../../../helpers/l10n';

export class BugsAndVulnerabilities extends React.PureComponent<ComposedProps> {
export class Bugs extends React.PureComponent<ComposedProps> {
renderHeader() {
const { branchLike, component } = this.props;
return this.props.renderHeader('Reliability');
}

renderTimelineStartDate(historyStartDate?: Date) {
if (!historyStartDate) {
return undefined;
}
return (
<div className="overview-card-header">
<div className="overview-title">
<span>{translate('metric.bugs.name')}</span>
<Link
className="button button-small spacer-left text-text-bottom"
to={getComponentDrilldownUrl({
componentKey: component.key,
metric: 'Reliability',
branchLike
})}>
<BubblesIcon size={14} />
</Link>
<span className="big-spacer-left">{translate('metric.vulnerabilities.name')}</span>
<Link
className="button button-small spacer-left text-text-bottom"
to={getComponentDrilldownUrl({
componentKey: component.key,
metric: 'Security',
branchLike
})}>
<BubblesIcon size={14} />
</Link>
</div>
</div>
<DateFromNow date={historyStartDate}>
{fromNow => (
<span className="overview-domain-timeline-date">
{translateWithParameters('overview.started_x', fromNow)}
</span>
)}
</DateFromNow>
);
}

renderTimeline(range: string, historyStartDate?: Date) {
return this.props.renderTimeline('bugs', range, this.renderTimelineStartDate(historyStartDate));
}

renderLeak() {
const { branchLike, component, leakPeriod } = this.props;
if (!leakPeriod) {
@@ -81,7 +72,7 @@ export class BugsAndVulnerabilities extends React.PureComponent<ComposedProps> {
<div className="overview-domain-measures">
<div className="overview-domain-measure">
<div className="overview-domain-measure-value">
<span style={{ marginLeft: 30 }}>{this.props.renderIssues('new_bugs', 'BUG')}</span>
<span className="offset-left">{this.props.renderIssues('new_bugs', 'BUG')}</span>
{this.props.renderRating('new_reliability_rating')}
</div>
<div className="overview-domain-measure-label">
@@ -89,19 +80,8 @@ export class BugsAndVulnerabilities extends React.PureComponent<ComposedProps> {
{getMetricName('new_bugs')}
</div>
</div>
<div className="overview-domain-measure">
<div className="overview-domain-measure-value">
<span style={{ marginLeft: 30 }}>
{this.props.renderIssues('new_vulnerabilities', 'VULNERABILITY')}
</span>
{this.props.renderRating('new_security_rating')}
</div>
<div className="overview-domain-measure-label">
<VulnerabilityIcon className="little-spacer-right" />
{getMetricName('new_vulnerabilities')}
</div>
</div>
</div>
{this.renderTimeline('after')}
</div>
);
}
@@ -112,27 +92,21 @@ export class BugsAndVulnerabilities extends React.PureComponent<ComposedProps> {
<div className="overview-domain-measures">
<div className="overview-domain-measure">
<div className="overview-domain-measure-value">
{this.props.renderIssues('bugs', 'BUG')}
<span className="offset-left">{this.props.renderIssues('bugs', 'BUG')}</span>
{this.props.renderRating('reliability_rating')}
</div>
<div className="overview-domain-measure-label">
<div className="overview-domain-measure-label display-flex-center display-flex-justify-center">
<BugIcon className="little-spacer-right " />
{getMetricName('bugs')}
{this.props.renderHistoryLink('bugs')}
</div>
</div>
<div className="overview-domain-measure">
<div className="overview-domain-measure-value">
{this.props.renderIssues('vulnerabilities', 'VULNERABILITY')}
{this.props.renderRating('security_rating')}
</div>
<div className="overview-domain-measure-label">
<VulnerabilityIcon className="little-spacer-right " />
{getMetricName('vulnerabilities')}
{this.props.renderHistoryLink('vulnerabilities')}
<DocTooltip
className="little-spacer-left"
doc={import(/* webpackMode: "eager" */ 'Docs/tooltips/metrics/bugs.md')}
/>
</div>
{this.props.renderHistoryLink('bugs')}
</div>
</div>
{this.renderTimeline('before', this.props.historyStartDate)}
</div>
);
}
@@ -144,7 +118,7 @@ export class BugsAndVulnerabilities extends React.PureComponent<ComposedProps> {
return null;
}
return (
<div className="overview-card overview-card-special">
<div className="overview-card">
{this.renderHeader()}

<div className="overview-domain-panel">
@@ -156,4 +130,4 @@ export class BugsAndVulnerabilities extends React.PureComponent<ComposedProps> {
}
}

export default enhance(BugsAndVulnerabilities);
export default enhance(Bugs);

+ 19
- 33
server/sonar-web/src/main/js/apps/overview/main/CodeSmells.tsx View File

@@ -19,16 +19,15 @@
*/
import * as React from 'react';
import enhance, { ComposedProps } from './enhance';
import DateFromNow from '../../../components/intl/DateFromNow';
import DocTooltip from '../../../components/docs/DocTooltip';
import { getMetricName } from '../utils';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { formatMeasure } from '../../../helpers/measures';
import CodeSmellIcon from '../../../components/icons-components/CodeSmellIcon';
import DrilldownLink from '../../../components/shared/DrilldownLink';

export class CodeSmells extends React.PureComponent<ComposedProps> {
renderHeader() {
return this.props.renderHeader('Maintainability', translate('metric.code_smells.name'));
return this.props.renderHeader('Maintainability');
}

renderDebt(metric: string) {
@@ -43,27 +42,8 @@ export class CodeSmells extends React.PureComponent<ComposedProps> {
);
}

renderTimelineStartDate() {
if (!this.props.historyStartDate) {
return null;
}
return (
<DateFromNow date={this.props.historyStartDate}>
{fromNow => (
<span className="overview-domain-timeline-date">
{translateWithParameters('overview.started_x', fromNow)}
</span>
)}
</DateFromNow>
);
}

renderTimeline(range: string, displayDate?: boolean) {
return this.props.renderTimeline(
'sqale_index',
range,
displayDate ? this.renderTimelineStartDate() : null
);
renderTimeline(range: string) {
return this.props.renderTimeline('sqale_index', range);
}

renderLeak() {
@@ -77,7 +57,7 @@ export class CodeSmells extends React.PureComponent<ComposedProps> {
<div className="overview-domain-measures">
<div className="overview-domain-measure">
<div className="overview-domain-measure-value">
<span style={{ marginLeft: 30 }}>{this.renderDebt('new_technical_debt')}</span>
<span className="offset-left">{this.renderDebt('new_technical_debt')}</span>
{this.props.renderRating('new_maintainability_rating')}
</div>
<div className="overview-domain-measure-label">{getMetricName('new_effort')}</div>
@@ -92,7 +72,6 @@ export class CodeSmells extends React.PureComponent<ComposedProps> {
</div>
</div>
</div>

{this.renderTimeline('after')}
</div>
);
@@ -104,27 +83,34 @@ export class CodeSmells extends React.PureComponent<ComposedProps> {
<div className="overview-domain-measures">
<div className="overview-domain-measure">
<div className="overview-domain-measure-value">
{this.renderDebt('sqale_index')}
<span className="offset-left">{this.renderDebt('sqale_index')}</span>
{this.props.renderRating('sqale_rating')}
</div>
<div className="overview-domain-measure-label">
<div className="overview-domain-measure-label display-flex-center display-flex-justify-center">
{getMetricName('effort')}
{this.props.renderHistoryLink('sqale_index')}
<DocTooltip
className="little-spacer-left"
doc={import(/* webpackMode: "eager" */ 'Docs/tooltips/metrics/debt.md')}
/>
</div>
{this.props.renderHistoryLink('sqale_index')}
</div>
<div className="overview-domain-measure">
<div className="overview-domain-measure-value">
{this.props.renderIssues('code_smells', 'CODE_SMELL')}
</div>
<div className="overview-domain-measure-label offset-left">
<div className="overview-domain-measure-label display-flex-center display-flex-justify-center">
<CodeSmellIcon className="little-spacer-right " />
{getMetricName('code_smells')}
{this.props.renderHistoryLink('code_smells')}
<DocTooltip
className="little-spacer-left"
doc={import(/* webpackMode: "eager" */ 'Docs/tooltips/metrics/code-smells.md')}
/>
</div>
{this.props.renderHistoryLink('code_smells')}
</div>
</div>

{this.renderTimeline('before', true)}
{this.renderTimeline('before')}
</div>
);
}

+ 20
- 6
server/sonar-web/src/main/js/apps/overview/main/Coverage.tsx View File

@@ -19,6 +19,7 @@
*/
import * as React from 'react';
import enhance, { ComposedProps } from './enhance';
import DocTooltip from '../../../components/docs/DocTooltip';
import DrilldownLink from '../../../components/shared/DrilldownLink';
import { getMetricName } from '../utils';
import { formatMeasure, getPeriodValue } from '../../../helpers/measures';
@@ -40,7 +41,13 @@ export class Coverage extends React.PureComponent<ComposedProps> {
}

renderTests() {
return this.props.renderMeasure('tests');
return this.props.renderMeasure(
'tests',
<DocTooltip
className="little-spacer-left"
doc={import(/* webpackMode: "eager" */ 'Docs/tooltips/metrics/unit-tests.md')}
/>
);
}

renderCoverage() {
@@ -50,7 +57,7 @@ export class Coverage extends React.PureComponent<ComposedProps> {

return (
<div className="overview-domain-measure">
<div className="display-inline-block text-middle big-spacer-right">
<div className="display-inline-block text-middle big-spacer-right neg-offset-left">
<CoverageRating size="big" value={coverage} />
</div>

@@ -63,11 +70,16 @@ export class Coverage extends React.PureComponent<ComposedProps> {
</DrilldownLink>
</div>

<div className="overview-domain-measure-label">
<div className="overview-domain-measure-label display-flex-center display-flex-justify-center">
{getMetricName('coverage')}
{this.props.renderHistoryLink('coverage')}
<DocTooltip
className="little-spacer-left"
doc={import(/* webpackMode: "eager" */ 'Docs/tooltips/metrics/coverage.md')}
/>
</div>
{this.props.renderHistoryLink('coverage')}
</div>
{this.props.renderHistoryLink('coverage')}
</div>
);
}
@@ -117,7 +129,9 @@ export class Coverage extends React.PureComponent<ComposedProps> {
{getMetricName('new_lines_to_cover')}
</div>
) : (
<div className="overview-domain-measure-label">{getMetricName('new_coverage')}</div>
<div className="overview-domain-measure-label display-flex-center display-flex-justify-center">
{getMetricName('new_coverage')}
</div>
);

return (
@@ -131,7 +145,7 @@ export class Coverage extends React.PureComponent<ComposedProps> {
renderNutshell() {
return (
<div className="overview-domain-nutshell">
<div className="overview-domain-measures">
<div className="overview-domain-measures overview-domain-measures-big">
{this.renderCoverage()}
{this.renderTests()}
</div>

+ 16
- 5
server/sonar-web/src/main/js/apps/overview/main/Duplications.tsx View File

@@ -19,6 +19,7 @@
*/
import * as React from 'react';
import enhance, { ComposedProps } from './enhance';
import DocTooltip from '../../../components/docs/DocTooltip';
import DrilldownLink from '../../../components/shared/DrilldownLink';
import { getMetricName } from '../utils';
import { formatMeasure, getPeriodValue } from '../../../helpers/measures';
@@ -35,7 +36,13 @@ export class Duplications extends React.PureComponent<ComposedProps> {
}

renderDuplicatedBlocks() {
return this.props.renderMeasure('duplicated_blocks');
return this.props.renderMeasure(
'duplicated_blocks',
<DocTooltip
className="little-spacer-left"
doc={import(/* webpackMode: "eager" */ 'Docs/tooltips/metrics/duplicated-blocks.md')}
/>
);
}

renderDuplications() {
@@ -49,7 +56,7 @@ export class Duplications extends React.PureComponent<ComposedProps> {

return (
<div className="overview-domain-measure">
<div className="display-inline-block text-middle big-spacer-right">
<div className="display-inline-block text-middle big-spacer-right neg-offset-left">
<DuplicationsRating size="big" value={duplications} />
</div>

@@ -63,10 +70,14 @@ export class Duplications extends React.PureComponent<ComposedProps> {
</DrilldownLink>
</div>

<div className="overview-domain-measure-label offset-left">
<div className="overview-domain-measure-label display-flex-center display-flex-justify-center">
{getMetricName('duplications')}
{this.props.renderHistoryLink('duplicated_lines_density')}
<DocTooltip
className="little-spacer-left"
doc={import(/* webpackMode: "eager" */ 'Docs/tooltips/metrics/duplications.md')}
/>
</div>
{this.props.renderHistoryLink('duplicated_lines_density')}
</div>
</div>
);
@@ -131,7 +142,7 @@ export class Duplications extends React.PureComponent<ComposedProps> {
renderNutshell() {
return (
<div className="overview-domain-nutshell">
<div className="overview-domain-measures">
<div className="overview-domain-measures overview-domain-measures-big">
{this.renderDuplications()}
{this.renderDuplicatedBlocks()}
</div>

+ 127
- 0
server/sonar-web/src/main/js/apps/overview/main/VulnerabilitiesAndHotspots.tsx View File

@@ -0,0 +1,127 @@
/*
* SonarQube
* Copyright (C) 2009-2019 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 enhance, { ComposedProps } from './enhance';
import DocTooltip from '../../../components/docs/DocTooltip';
import VulnerabilityIcon from '../../../components/icons-components/VulnerabilityIcon';
import { getMetricName } from '../utils';
import SecurityHotspotIcon from '../../../components/icons-components/SecurityHotspotIcon';

export class VulnerabiltiesAndHotspots extends React.PureComponent<ComposedProps> {
renderHeader() {
return this.props.renderHeader('Security');
}

renderTimeline(range: string) {
return this.props.renderTimeline('vulnerabilities', range);
}

renderLeak() {
const { leakPeriod } = this.props;
if (!leakPeriod) {
return null;
}

return (
<div className="overview-domain-leak">
<div className="overview-domain-measures">
<div className="overview-domain-measure">
<div className="overview-domain-measure-value">
<span className="offset-left">
{this.props.renderIssues('new_vulnerabilities', 'VULNERABILITY')}
</span>
{this.props.renderRating('new_security_rating')}
</div>
<div className="overview-domain-measure-label">
<VulnerabilityIcon className="little-spacer-right" />
{getMetricName('new_vulnerabilities')}
</div>
</div>
<div className="overview-domain-measure">
<div className="overview-domain-measure-value overview-domain-measure-value-small">
<span>{this.props.renderIssues('new_security_hotspots', 'SECURITY_HOTSPOT')}</span>
</div>
<div className="overview-domain-measure-label">
<SecurityHotspotIcon className="little-spacer-right" />
{getMetricName('new_security_hotspots')}
</div>
</div>
</div>
{this.renderTimeline('after')}
</div>
);
}

renderNutshell() {
return (
<div className="overview-domain-nutshell">
<div className="overview-domain-measures">
<div className="overview-domain-measure">
<div className="overview-domain-measure-value">
<span className="offset-left">
{this.props.renderIssues('vulnerabilities', 'VULNERABILITY')}
</span>
{this.props.renderRating('security_rating')}
</div>
<div className="overview-domain-measure-label display-flex-center display-flex-justify-center">
<VulnerabilityIcon className="little-spacer-right" />
{getMetricName('vulnerabilities')}
<DocTooltip
className="little-spacer-left"
doc={import(/* webpackMode: "eager" */ 'Docs/tooltips/metrics/vulnerabilities.md')}
/>
</div>
{this.props.renderHistoryLink('vulnerabilities')}
</div>
<div className="overview-domain-measure">
<div className="overview-domain-measure-value overview-domain-measure-value-small">
{this.props.renderIssues('security_hotspots', 'SECURITY_HOTSPOT')}
</div>
<div className="overview-domain-measure-label display-flex-center display-flex-justify-center">
<SecurityHotspotIcon className="little-spacer-right" />
{getMetricName('security_hotspots')}
<DocTooltip
className="little-spacer-left"
doc={import(/* webpackMode: "eager" */ 'Docs/tooltips/metrics/security-hotspots.md')}
/>
</div>
{this.props.renderHistoryLink('security_hotspots')}
</div>
</div>
{this.renderTimeline('before')}
</div>
);
}

render() {
return (
<div className="overview-card">
{this.renderHeader()}

<div className="overview-domain-panel">
{this.renderNutshell()}
{this.renderLeak()}
</div>
</div>
);
}
}

export default enhance(VulnerabiltiesAndHotspots);

+ 87
- 0
server/sonar-web/src/main/js/apps/overview/main/__tests__/Bugs-test.tsx View File

@@ -0,0 +1,87 @@
/*
* SonarQube
* Copyright (C) 2009-2019 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 { IntlProvider } from 'react-intl';
import { render } from 'enzyme';
import Bugs from '../Bugs';
import { ComposedProps } from '../enhance';
import {
mockComponent,
mockMainBranch,
mockMeasureEnhanced,
mockMetric
} from '../../../../helpers/testMocks';

it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot();
});

function shallowRender(props: Partial<ComposedProps> = {}) {
return render(
<IntlProvider locale="en" messages={{}}>
<Bugs
branchLike={mockMainBranch()}
component={mockComponent()}
history={{ bugs: [] }}
historyStartDate={new Date('2019-01-14T15:44:51.000Z')}
leakPeriod={{ index: 1, mode: 'days' } as T.Period}
measures={[
mockMeasureEnhanced({
metric: mockMetric({
id: 'bugs',
key: 'bugs',
name: 'Bugs',
type: 'INT'
}),
value: '5'
}),
mockMeasureEnhanced({
metric: mockMetric({
id: 'new_bugs',
key: 'new_bugs',
name: 'New Bugs',
type: 'INT'
}),
value: '2'
}),
mockMeasureEnhanced({
metric: mockMetric({
id: 'reliability_rating',
key: 'reliability_rating',
name: 'Reliability',
type: 'RATING'
}),
value: '1.0'
}),
mockMeasureEnhanced({
metric: mockMetric({
id: 'new_reliability_rating',
key: 'new_reliability_rating',
name: 'New Reliability',
type: 'RATING'
}),
value: '2.0'
})
]}
{...props}
/>
</IntlProvider>
);
}

+ 113
- 0
server/sonar-web/src/main/js/apps/overview/main/__tests__/CodeSmells-test.tsx View File

@@ -0,0 +1,113 @@
/*
* SonarQube
* Copyright (C) 2009-2019 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 { render } from 'enzyme';
import CodeSmells from '../CodeSmells';
import { ComposedProps } from '../enhance';
import {
mockComponent,
mockMainBranch,
mockMeasureEnhanced,
mockMetric
} from '../../../../helpers/testMocks';

it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot();
});

function shallowRender(props: Partial<ComposedProps> = {}) {
return render(
<CodeSmells
branchLike={mockMainBranch()}
component={mockComponent()}
history={{ sqale_index: [] }}
leakPeriod={{ index: 1 } as T.Period}
measures={[
mockMeasureEnhanced({
metric: mockMetric({
id: 'code_smells',
key: 'code_smells',
name: 'Code Smells',
type: 'INT'
}),
value: '15'
}),
mockMeasureEnhanced({
metric: mockMetric({
id: 'sqale_index',
key: 'sqale_index',
name: 'Debt',
type: 'INT'
}),
value: '1052'
}),
mockMeasureEnhanced({
metric: mockMetric({
id: 'sqale_rating',
key: 'sqale_rating',
name: 'Maintainability',
type: 'RATING'
}),
value: '2.0'
}),
mockMeasureEnhanced({
metric: mockMetric({
id: 'new_code_smells',
key: 'new_code_smells',
name: 'New Code Smells',
type: 'INT'
}),
periods: [
{
bestValue: true,
index: 1,
value: '52'
}
]
}),
mockMeasureEnhanced({
metric: mockMetric({
id: 'new_technical_debt',
key: 'new_technical_debt',
name: 'New Debt',
type: 'INT'
}),
periods: [
{
bestValue: true,
index: 1,
value: '85'
}
]
}),
mockMeasureEnhanced({
metric: mockMetric({
id: 'new_maintainability_rating',
key: 'new_maintainability_rating',
name: 'New Maintainability',
type: 'RATING'
}),
value: '3.0'
})
]}
{...props}
/>
);
}

+ 73
- 0
server/sonar-web/src/main/js/apps/overview/main/__tests__/Coverage-test.tsx View File

@@ -0,0 +1,73 @@
/*
* SonarQube
* Copyright (C) 2009-2019 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 { render } from 'enzyme';
import Coverage from '../Coverage';
import { ComposedProps } from '../enhance';
import {
mockComponent,
mockMainBranch,
mockMeasureEnhanced,
mockMetric
} from '../../../../helpers/testMocks';

it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot();
});

function shallowRender(props: Partial<ComposedProps> = {}) {
return render(
<Coverage
branchLike={mockMainBranch()}
component={mockComponent()}
leakPeriod={{ index: 1 } as T.Period}
measures={[
mockMeasureEnhanced(),
mockMeasureEnhanced({
metric: mockMetric({
id: 'new_lines_to_cover',
key: 'new_lines_to_cover',
name: 'New Lines to Cover',
type: 'INT'
}),
value: '52'
}),
mockMeasureEnhanced({
metric: mockMetric({
id: 'new_coverage',
key: 'new_coverage',
name: 'New Coverage'
}),
value: '85.0'
}),
mockMeasureEnhanced({
metric: mockMetric({
id: 'tests',
key: 'tests',
name: 'Unit Tests',
type: 'INT'
}),
value: '15'
})
]}
{...props}
/>
);
}

+ 92
- 0
server/sonar-web/src/main/js/apps/overview/main/__tests__/Duplications-test.tsx View File

@@ -0,0 +1,92 @@
/*
* SonarQube
* Copyright (C) 2009-2019 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 { render } from 'enzyme';
import Duplications from '../Duplications';
import { ComposedProps } from '../enhance';
import {
mockComponent,
mockMainBranch,
mockMeasureEnhanced,
mockMetric
} from '../../../../helpers/testMocks';

it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot();
});

function shallowRender(props: Partial<ComposedProps> = {}) {
return render(
<Duplications
branchLike={mockMainBranch()}
component={mockComponent()}
leakPeriod={{ index: 1 } as T.Period}
measures={[
mockMeasureEnhanced({
metric: mockMetric({
id: 'duplicated_lines_density',
key: 'duplicated_lines_density',
name: 'Duplicated Lines'
}),
value: '0.5'
}),
mockMeasureEnhanced({
metric: mockMetric({
id: 'new_lines',
key: 'new_lines',
name: 'New Lines',
type: 'INT'
}),
value: '52'
}),
mockMeasureEnhanced({
metric: mockMetric({
id: 'new_duplicated_lines_density',
key: 'new_duplicated_lines_density',
name: 'New Duplicated Lines'
}),
periods: [
{
bestValue: true,
index: 1,
value: '1.5'
}
]
}),
mockMeasureEnhanced({
metric: mockMetric({
id: 'duplicated_blocks',
key: 'duplicated_blocks',
name: 'Duplicated Blocks',
type: 'INT'
}),
periods: [
{
bestValue: true,
index: 1,
value: '2'
}
]
})
]}
{...props}
/>
);
}

+ 119
- 0
server/sonar-web/src/main/js/apps/overview/main/__tests__/VulnerabilitiesAndHotspots-test.tsx View File

@@ -0,0 +1,119 @@
/*
* SonarQube
* Copyright (C) 2009-2019 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 { render } from 'enzyme';
import VulnerabilitiesAndHotspots from '../VulnerabilitiesAndHotspots';
import { ComposedProps } from '../enhance';
import {
mockComponent,
mockMainBranch,
mockMeasureEnhanced,
mockMetric
} from '../../../../helpers/testMocks';

it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot();
});

function shallowRender(props: Partial<ComposedProps> = {}) {
return render(
<VulnerabilitiesAndHotspots
branchLike={mockMainBranch()}
component={mockComponent()}
history={{ vulnerabilities: [] }}
leakPeriod={{ index: 1 } as T.Period}
measures={[
mockMeasureEnhanced({
metric: mockMetric({
id: 'vulnerabilities',
key: 'vulnerabilities',
name: 'Vulnerabilities',
type: 'INT'
}),
value: '0'
}),
mockMeasureEnhanced({
metric: mockMetric({
id: 'security_hotspots',
key: 'security_hotspots',
name: 'Security Hotspots',
type: 'INT'
}),
value: '0'
}),
mockMeasureEnhanced({
metric: mockMetric({
id: 'security_rating',
key: 'security_rating',
name: 'Security',
type: 'RATING'
}),
value: '1.0'
}),
mockMeasureEnhanced({
metric: mockMetric({
id: 'new_vulnerabilities',
key: 'new_vulnerabilities',
name: 'New Vulnerabilities',
type: 'INT'
}),
periods: [
{
bestValue: true,
index: 1,
value: '1'
}
]
}),
mockMeasureEnhanced({
metric: mockMetric({
id: 'new_security_hotspots',
key: 'new_security_hotspots',
name: 'New Security Hotspots',
type: 'INT'
}),
periods: [
{
bestValue: true,
index: 1,
value: '10'
}
]
}),
mockMeasureEnhanced({
metric: mockMetric({
id: 'new_security_rating',
key: 'new_security_rating',
name: 'New Security Rating',
type: 'RATING'
}),
periods: [
{
bestValue: true,
index: 1,
value: '5.0'
}
]
})
]}
{...props}
/>
);
}

+ 180
- 0
server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/Bugs-test.tsx.snap View File

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

exports[`should render correctly 1`] = `
<div
class="overview-card"
>
<div
class="overview-card-header"
>
<div
class="overview-title"
>
<span>
metric_domain.Reliability
</span>
<a
class="spacer-left small"
>
layout.measures
</a>
</div>
</div>
<div
class="overview-domain-panel"
>
<div
class="overview-domain-nutshell"
>
<div
class="overview-domain-measures"
>
<div
class="overview-domain-measure"
>
<div
class="overview-domain-measure-value"
>
<span
class="offset-left"
>
<a>
5
</a>
</span>
<div
class="overview-domain-measure-sup"
>
<a
class="link-no-underline"
>
<span
aria-label="metric.has_rating_X.A"
class="rating rating-A"
>
A
</span>
</a>
</div>
</div>
<div
class="overview-domain-measure-label display-flex-center display-flex-justify-center"
>
<svg
class="little-spacer-right "
height="16"
space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421"
version="1.1"
viewBox="0 0 16 16"
width="16"
xlink="http://www.w3.org/1999/xlink"
>
<path
d="M11 9h1.3l.5.8.8-.5-.8-1.3H11v-.3l2-2.3V3h-1v2l-1 1.2V5c-.1-.8-.7-1.5-1.4-1.9L11 1.8l-.7-.7-1.8 1.6-1.8-1.6-.7.7 1.5 1.3C6.7 3.5 6.1 4.2 6 5v1.1L5 5V3H4v2.3l2 2.3V8H4.2l-.7 1.2.8.5.4-.7H6v.3l-2 1.9V14h1v-2.4l1-1C6 12 7.1 13 8.4 13h.8c.7 0 1.4-.3 1.8-.9.3-.4.3-.9.2-1.4l.9.9V14h1v-2.8l-2-1.9V9zm-2 2H8V6h1v5z"
style="fill:currentColor"
/>
</svg>
overview.metric.bugs
</div>
<a
class="overview-domain-measure-history-link"
>
<svg
height="16"
space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421"
version="1.1"
viewBox="0 0 16 16"
width="16"
xlink="http://www.w3.org/1999/xlink"
>
<path
d="M14.7 3.4v3.3c0 .1 0 .2-.1.2s-.2 0-.3-.1l-.9-.9-4.8 4.8c-.1.1-.1.1-.2.1s-.1 0-.2-.1L6.4 9l-3.2 3.2-1.5-1.5 4.5-4.5c.1-.1.1-.1.2-.1s.1 0 .2.1L8.4 8l3.5-3.5-.9-1c-.1-.1-.1-.2-.1-.3s.1-.1.2-.1h3.3c.1 0 .1 0 .2.1.1 0 .1.1.1.2z"
style="fill:currentColor"
/>
</svg>
<span>
project_activity.page
</span>
</a>
</div>
</div>
<div
class="overview-domain-timeline"
>
<span
class="overview-domain-timeline-date"
>
overview.started_x.3 months ago
</span>
</div>
</div>
<div
class="overview-domain-leak"
>
<div
class="overview-legend overview-legend-spaced-line"
>
overview.new_code_period_x.overview.period.days.
</div>
<div
class="overview-domain-measures"
>
<div
class="overview-domain-measure"
>
<div
class="overview-domain-measure-value"
>
<span
class="offset-left"
>
<a>
1
</a>
</span>
<div
class="overview-domain-measure-sup"
>
<a
class="link-no-underline"
>
<span
aria-label="metric.has_rating_X.A"
class="rating rating-A"
>
A
</span>
</a>
</div>
</div>
<div
class="overview-domain-measure-label"
>
<svg
class="little-spacer-right"
height="16"
space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421"
version="1.1"
viewBox="0 0 16 16"
width="16"
xlink="http://www.w3.org/1999/xlink"
>
<path
d="M11 9h1.3l.5.8.8-.5-.8-1.3H11v-.3l2-2.3V3h-1v2l-1 1.2V5c-.1-.8-.7-1.5-1.4-1.9L11 1.8l-.7-.7-1.8 1.6-1.8-1.6-.7.7 1.5 1.3C6.7 3.5 6.1 4.2 6 5v1.1L5 5V3H4v2.3l2 2.3V8H4.2l-.7 1.2.8.5.4-.7H6v.3l-2 1.9V14h1v-2.4l1-1C6 12 7.1 13 8.4 13h.8c.7 0 1.4-.3 1.8-.9.3-.4.3-.9.2-1.4l.9.9V14h1v-2.8l-2-1.9V9zm-2 2H8V6h1v5z"
style="fill:currentColor"
/>
</svg>
overview.metric.new_bugs
</div>
</div>
</div>
<div
class="overview-domain-timeline"
/>
</div>
</div>
</div>
`;

+ 223
- 0
server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/CodeSmells-test.tsx.snap View File

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

exports[`should render correctly 1`] = `
<div
class="overview-card"
id="overview-code-smells"
>
<div
class="overview-card-header"
>
<div
class="overview-title"
>
<span>
metric_domain.Maintainability
</span>
<a
class="spacer-left small"
>
layout.measures
</a>
</div>
</div>
<div
class="overview-domain-panel"
>
<div
class="overview-domain-nutshell"
>
<div
class="overview-domain-measures"
>
<div
class="overview-domain-measure"
>
<div
class="overview-domain-measure-value"
>
<span
class="offset-left"
>
<a>
work_duration.x_days.2
</a>
</span>
<div
class="overview-domain-measure-sup"
>
<a
class="link-no-underline"
>
<span
aria-label="metric.has_rating_X.B"
class="rating rating-B"
>
B
</span>
</a>
</div>
</div>
<div
class="overview-domain-measure-label display-flex-center display-flex-justify-center"
>
overview.metric.effort
</div>
<a
class="overview-domain-measure-history-link"
>
<svg
height="16"
space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421"
version="1.1"
viewBox="0 0 16 16"
width="16"
xlink="http://www.w3.org/1999/xlink"
>
<path
d="M14.7 3.4v3.3c0 .1 0 .2-.1.2s-.2 0-.3-.1l-.9-.9-4.8 4.8c-.1.1-.1.1-.2.1s-.1 0-.2-.1L6.4 9l-3.2 3.2-1.5-1.5 4.5-4.5c.1-.1.1-.1.2-.1s.1 0 .2.1L8.4 8l3.5-3.5-.9-1c-.1-.1-.1-.2-.1-.3s.1-.1.2-.1h3.3c.1 0 .1 0 .2.1.1 0 .1.1.1.2z"
style="fill:currentColor"
/>
</svg>
<span>
project_activity.page
</span>
</a>
</div>
<div
class="overview-domain-measure"
>
<div
class="overview-domain-measure-value"
>
<a>
15
</a>
</div>
<div
class="overview-domain-measure-label display-flex-center display-flex-justify-center"
>
<svg
class="little-spacer-right "
height="16"
space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421"
version="1.1"
viewBox="0 0 16 16"
width="16"
xlink="http://www.w3.org/1999/xlink"
>
<path
d="M8 2C4.7 2 2 4.7 2 8s2.7 6 6 6 6-2.7 6-6-2.7-6-6-6zm-.5 5.5h.9v.9h-.9v-.9zm-3.8.2c-.1 0-.2-.1-.2-.2 0-.4.1-1.2.6-2S5.3 4.2 5.6 4c.2 0 .3 0 .3.1l1.3 2.3c0 .1 0 .2-.1.2-.1.2-.2.3-.3.5-.1.2-.2.4-.2.5 0 .1-.1.2-.2.2l-2.7-.1zM9.9 12c-.3.2-1.1.5-2 .5-.9 0-1.7-.3-2-.5-.1 0-.1-.2-.1-.3l1.3-2.3c0-.1.1-.1.2-.1.2.1.3.1.5.1s.4 0 .5-.1c.1 0 .2 0 .2.1l1.3 2.3c.2.2.2.3.1.3zm2.5-4.1L9.7 8c-.1 0-.2-.1-.2-.2 0-.2-.1-.4-.2-.5 0-.1-.2-.3-.3-.4-.1 0-.1-.1-.1-.2l1.3-2.3c.1-.1.2-.1.3-.1.3.2 1 .7 1.5 1.5s.6 1.6.6 2c0 0-.1.1-.2.1z"
style="fill:currentColor"
/>
</svg>
overview.metric.code_smells
</div>
<a
class="overview-domain-measure-history-link"
>
<svg
height="16"
space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421"
version="1.1"
viewBox="0 0 16 16"
width="16"
xlink="http://www.w3.org/1999/xlink"
>
<path
d="M14.7 3.4v3.3c0 .1 0 .2-.1.2s-.2 0-.3-.1l-.9-.9-4.8 4.8c-.1.1-.1.1-.2.1s-.1 0-.2-.1L6.4 9l-3.2 3.2-1.5-1.5 4.5-4.5c.1-.1.1-.1.2-.1s.1 0 .2.1L8.4 8l3.5-3.5-.9-1c-.1-.1-.1-.2-.1-.3s.1-.1.2-.1h3.3c.1 0 .1 0 .2.1.1 0 .1.1.1.2z"
style="fill:currentColor"
/>
</svg>
<span>
project_activity.page
</span>
</a>
</div>
</div>
<div
class="overview-domain-timeline"
/>
</div>
<div
class="overview-domain-leak"
>
<div
class="overview-domain-measures"
>
<div
class="overview-domain-measure"
>
<div
class="overview-domain-measure-value"
>
<span
class="offset-left"
>
<a>
work_duration.x_hours.1
</a>
</span>
<div
class="overview-domain-measure-sup"
>
<a
class="link-no-underline"
>
<span
aria-label="metric.has_rating_X.A"
class="rating rating-A"
>
A
</span>
</a>
</div>
</div>
<div
class="overview-domain-measure-label"
>
overview.metric.new_effort
</div>
</div>
<div
class="overview-domain-measure"
>
<div
class="overview-domain-measure-value"
>
<a>
52
</a>
</div>
<div
class="overview-domain-measure-label"
>
<svg
class="little-spacer-right"
height="16"
space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421"
version="1.1"
viewBox="0 0 16 16"
width="16"
xlink="http://www.w3.org/1999/xlink"
>
<path
d="M8 2C4.7 2 2 4.7 2 8s2.7 6 6 6 6-2.7 6-6-2.7-6-6-6zm-.5 5.5h.9v.9h-.9v-.9zm-3.8.2c-.1 0-.2-.1-.2-.2 0-.4.1-1.2.6-2S5.3 4.2 5.6 4c.2 0 .3 0 .3.1l1.3 2.3c0 .1 0 .2-.1.2-.1.2-.2.3-.3.5-.1.2-.2.4-.2.5 0 .1-.1.2-.2.2l-2.7-.1zM9.9 12c-.3.2-1.1.5-2 .5-.9 0-1.7-.3-2-.5-.1 0-.1-.2-.1-.3l1.3-2.3c0-.1.1-.1.2-.1.2.1.3.1.5.1s.4 0 .5-.1c.1 0 .2 0 .2.1l1.3 2.3c.2.2.2.3.1.3zm2.5-4.1L9.7 8c-.1 0-.2-.1-.2-.2 0-.2-.1-.4-.2-.5 0-.1-.2-.3-.3-.4-.1 0-.1-.1-.1-.2l1.3-2.3c.1-.1.2-.1.3-.1.3.2 1 .7 1.5 1.5s.6 1.6.6 2c0 0-.1.1-.2.1z"
style="fill:currentColor"
/>
</svg>
overview.metric.new_code_smells
</div>
</div>
</div>
<div
class="overview-domain-timeline"
/>
</div>
</div>
</div>
`;

+ 187
- 0
server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/Coverage-test.tsx.snap View File

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

exports[`should render correctly 1`] = `
<div
class="overview-card"
>
<div
class="overview-card-header"
>
<div
class="overview-title"
>
<span>
metric.coverage.name
</span>
<a
class="spacer-left small"
>
layout.measures
</a>
</div>
</div>
<div
class="overview-domain-panel"
>
<div
class="overview-domain-nutshell"
>
<div
class="overview-domain-measures overview-domain-measures-big"
>
<div
class="overview-domain-measure"
>
<div
class="display-inline-block text-middle big-spacer-right neg-offset-left"
/>
<div
class="display-inline-block text-middle"
>
<div
class="overview-domain-measure-value"
>
<a>
<span
class="js-overview-main-coverage"
>
1.0%
</span>
</a>
</div>
<div
class="overview-domain-measure-label display-flex-center display-flex-justify-center"
>
overview.metric.coverage
</div>
<a
class="overview-domain-measure-history-link"
>
<svg
height="16"
space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421"
version="1.1"
viewBox="0 0 16 16"
width="16"
xlink="http://www.w3.org/1999/xlink"
>
<path
d="M14.7 3.4v3.3c0 .1 0 .2-.1.2s-.2 0-.3-.1l-.9-.9-4.8 4.8c-.1.1-.1.1-.2.1s-.1 0-.2-.1L6.4 9l-3.2 3.2-1.5-1.5 4.5-4.5c.1-.1.1-.1.2-.1s.1 0 .2.1L8.4 8l3.5-3.5-.9-1c-.1-.1-.1-.2-.1-.3s.1-.1.2-.1h3.3c.1 0 .1 0 .2.1.1 0 .1.1.1.2z"
style="fill:currentColor"
/>
</svg>
<span>
project_activity.page
</span>
</a>
</div>
<a
class="overview-domain-measure-history-link"
>
<svg
height="16"
space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421"
version="1.1"
viewBox="0 0 16 16"
width="16"
xlink="http://www.w3.org/1999/xlink"
>
<path
d="M14.7 3.4v3.3c0 .1 0 .2-.1.2s-.2 0-.3-.1l-.9-.9-4.8 4.8c-.1.1-.1.1-.2.1s-.1 0-.2-.1L6.4 9l-3.2 3.2-1.5-1.5 4.5-4.5c.1-.1.1-.1.2-.1s.1 0 .2.1L8.4 8l3.5-3.5-.9-1c-.1-.1-.1-.2-.1-.3s.1-.1.2-.1h3.3c.1 0 .1 0 .2.1.1 0 .1.1.1.2z"
style="fill:currentColor"
/>
</svg>
<span>
project_activity.page
</span>
</a>
</div>
<div
class="overview-domain-measure"
>
<div
class="overview-domain-measure-value"
>
<a>
<span
class="js-overview-main-tests"
>
15
</span>
</a>
</div>
<div
class="overview-domain-measure-label display-flex-center display-flex-justify-center"
>
Unit Tests
<a
class="overview-domain-measure-history-link"
>
<svg
height="16"
space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421"
version="1.1"
viewBox="0 0 16 16"
width="16"
xlink="http://www.w3.org/1999/xlink"
>
<path
d="M14.7 3.4v3.3c0 .1 0 .2-.1.2s-.2 0-.3-.1l-.9-.9-4.8 4.8c-.1.1-.1.1-.2.1s-.1 0-.2-.1L6.4 9l-3.2 3.2-1.5-1.5 4.5-4.5c.1-.1.1-.1.2-.1s.1 0 .2.1L8.4 8l3.5-3.5-.9-1c-.1-.1-.1-.2-.1-.3s.1-.1.2-.1h3.3c.1 0 .1 0 .2.1.1 0 .1.1.1.2z"
style="fill:currentColor"
/>
</svg>
<span>
project_activity.page
</span>
</a>
</div>
</div>
</div>
</div>
<div
class="overview-domain-leak"
>
<div
class="overview-domain-measures"
>
<div
class="overview-domain-measure"
>
<div
class="overview-domain-measure-value"
>
<div>
<a>
<span
class="js-overview-main-new-coverage"
>
1.0%
</span>
</a>
</div>
</div>
<div
class="overview-domain-measure-label"
>
overview.coverage_on
<br />
<a
class="spacer-right overview-domain-secondary-measure-value"
>
<span
class="js-overview-main-new-coverage"
>
1
</span>
</a>
overview.metric.new_lines_to_cover
</div>
</div>
</div>
</div>
</div>
</div>
`;

+ 166
- 0
server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/Duplications-test.tsx.snap View File

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

exports[`should render correctly 1`] = `
<div
class="overview-card"
>
<div
class="overview-card-header"
>
<div
class="overview-title"
>
<span>
overview.domain.duplications
</span>
<a
class="spacer-left small"
>
layout.measures
</a>
</div>
</div>
<div
class="overview-domain-panel"
>
<div
class="overview-domain-nutshell"
>
<div
class="overview-domain-measures overview-domain-measures-big"
>
<div
class="overview-domain-measure"
>
<div
class="display-inline-block text-middle big-spacer-right neg-offset-left"
>
<div
class="duplications-rating duplications-rating-big duplications-rating-A"
/>
</div>
<div
class="display-inline-block text-middle"
>
<div
class="overview-domain-measure-value"
>
<a>
0.5%
</a>
</div>
<div
class="overview-domain-measure-label display-flex-center display-flex-justify-center"
>
overview.metric.duplications
</div>
<a
class="overview-domain-measure-history-link"
>
<svg
height="16"
space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421"
version="1.1"
viewBox="0 0 16 16"
width="16"
xlink="http://www.w3.org/1999/xlink"
>
<path
d="M14.7 3.4v3.3c0 .1 0 .2-.1.2s-.2 0-.3-.1l-.9-.9-4.8 4.8c-.1.1-.1.1-.2.1s-.1 0-.2-.1L6.4 9l-3.2 3.2-1.5-1.5 4.5-4.5c.1-.1.1-.1.2-.1s.1 0 .2.1L8.4 8l3.5-3.5-.9-1c-.1-.1-.1-.2-.1-.3s.1-.1.2-.1h3.3c.1 0 .1 0 .2.1.1 0 .1.1.1.2z"
style="fill:currentColor"
/>
</svg>
<span>
project_activity.page
</span>
</a>
</div>
</div>
<div
class="overview-domain-measure"
>
<div
class="overview-domain-measure-value"
>
<a>
<span
class="js-overview-main-tests"
>
1
</span>
</a>
</div>
<div
class="overview-domain-measure-label display-flex-center display-flex-justify-center"
>
Duplicated Blocks
<a
class="overview-domain-measure-history-link"
>
<svg
height="16"
space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421"
version="1.1"
viewBox="0 0 16 16"
width="16"
xlink="http://www.w3.org/1999/xlink"
>
<path
d="M14.7 3.4v3.3c0 .1 0 .2-.1.2s-.2 0-.3-.1l-.9-.9-4.8 4.8c-.1.1-.1.1-.2.1s-.1 0-.2-.1L6.4 9l-3.2 3.2-1.5-1.5 4.5-4.5c.1-.1.1-.1.2-.1s.1 0 .2.1L8.4 8l3.5-3.5-.9-1c-.1-.1-.1-.2-.1-.3s.1-.1.2-.1h3.3c.1 0 .1 0 .2.1.1 0 .1.1.1.2z"
style="fill:currentColor"
/>
</svg>
<span>
project_activity.page
</span>
</a>
</div>
</div>
</div>
</div>
<div
class="overview-domain-leak"
>
<div
class="overview-domain-measures"
>
<div
class="overview-domain-measure"
>
<div
class="overview-domain-measure-value"
>
<div>
<a>
<span
class="js-overview-main-new-duplications"
>
1.5%
</span>
</a>
</div>
</div>
<div
class="overview-domain-measure-label"
>
overview.duplications_on
<br />
<a
class="spacer-right overview-domain-secondary-measure-value"
>
<span
class="js-overview-main-new-lines"
>
1
</span>
</a>
overview.metric.new_lines
</div>
</div>
</div>
</div>
</div>
</div>
`;

+ 288
- 0
server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/VulnerabilitiesAndHotspots-test.tsx.snap View File

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

exports[`should render correctly 1`] = `
<div
class="overview-card"
>
<div
class="overview-card-header"
>
<div
class="overview-title"
>
<span>
metric_domain.Security
</span>
<a
class="spacer-left small"
>
layout.measures
</a>
</div>
</div>
<div
class="overview-domain-panel"
>
<div
class="overview-domain-nutshell"
>
<div
class="overview-domain-measures"
>
<div
class="overview-domain-measure"
>
<div
class="overview-domain-measure-value"
>
<span
class="offset-left"
>
<a>
0
</a>
</span>
<div
class="overview-domain-measure-sup"
>
<a
class="link-no-underline"
>
<span
aria-label="metric.has_rating_X.A"
class="rating rating-A"
>
A
</span>
</a>
</div>
</div>
<div
class="overview-domain-measure-label display-flex-center display-flex-justify-center"
>
<svg
class="little-spacer-right"
height="16"
space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421"
version="1.1"
viewBox="0 0 16 16"
width="16"
xlink="http://www.w3.org/1999/xlink"
>
<path
d="M10.8 5H6V3.9a2.28 2.28 0 0 1 2-2.5 2.22 2.22 0 0 1 1.8 1.2.48.48 0 0 0 .7.2.48.48 0 0 0 .2-.7A3 3 0 0 0 8 .4a3.34 3.34 0 0 0-3 3.5v1.2a2.16 2.16 0 0 0-2 2.1v4.4a2.22 2.22 0 0 0 2.2 2.2h5.6a2.22 2.22 0 0 0 2.2-2.2V7.2A2.22 2.22 0 0 0 10.8 5zm-2.2 5.5v1.2H7.4v-1.2a1.66 1.66 0 0 1-1.1-1.6A1.75 1.75 0 0 1 8 7.2a1.71 1.71 0 0 1 .6 3.3z"
style="fill:currentColor"
/>
</svg>
overview.metric.vulnerabilities
</div>
<a
class="overview-domain-measure-history-link"
>
<svg
height="16"
space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421"
version="1.1"
viewBox="0 0 16 16"
width="16"
xlink="http://www.w3.org/1999/xlink"
>
<path
d="M14.7 3.4v3.3c0 .1 0 .2-.1.2s-.2 0-.3-.1l-.9-.9-4.8 4.8c-.1.1-.1.1-.2.1s-.1 0-.2-.1L6.4 9l-3.2 3.2-1.5-1.5 4.5-4.5c.1-.1.1-.1.2-.1s.1 0 .2.1L8.4 8l3.5-3.5-.9-1c-.1-.1-.1-.2-.1-.3s.1-.1.2-.1h3.3c.1 0 .1 0 .2.1.1 0 .1.1.1.2z"
style="fill:currentColor"
/>
</svg>
<span>
project_activity.page
</span>
</a>
</div>
<div
class="overview-domain-measure"
>
<div
class="overview-domain-measure-value overview-domain-measure-value-small"
>
<a>
0
</a>
</div>
<div
class="overview-domain-measure-label display-flex-center display-flex-justify-center"
>
<svg
class="little-spacer-right"
height="16"
space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421"
version="1.1"
viewBox="0 0 16 16"
width="16"
xlink="http://www.w3.org/1999/xlink"
>
<g
style="fill:currentColor"
>
<path
d="M10.238 2.416c-0.432-0.895-1.259-1.504-2.202-1.504-1.386 0-2.521 1.318-2.521 2.927v5.481"
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-width="1.1429"
/>
<path
d="M8.537 10.372v1.199h-1.099v-1.199c-0.638-0.228-1.099-0.832-1.099-1.546 0-0.909 0.739-1.649 1.648-1.649s1.649 0.74 1.649 1.649c0 0.715-0.461 1.32-1.099 1.546zM10.734 4.979h-5.494c-1.21 0-2.199 0.989-2.199 2.197v4.395c0 1.21 0.989 2.199 2.199 2.199h5.494c1.209 0 2.197-0.989 2.197-2.199v-4.395c0-1.209-0.989-2.197-2.197-2.197z"
/>
<path
d="M4.030 6.352h6.923v6.923h-6.923z"
/>
<path
d="M7.504 10.283c0-0.423 0.048-0.757 0.144-1.002s0.251-0.457 0.465-0.637c0.215-0.18 0.377-0.344 0.489-0.493s0.167-0.313 0.167-0.493c0-0.438-0.189-0.656-0.565-0.656-0.174 0-0.314 0.064-0.421 0.191s-0.164 0.3-0.17 0.518h-1.469c0.006-0.58 0.189-1.031 0.548-1.354s0.864-0.485 1.513-0.485c0.646 0 1.147 0.149 1.501 0.447s0.532 0.723 0.532 1.274c0 0.241-0.048 0.459-0.144 0.656s-0.249 0.398-0.46 0.604l-0.5 0.465c-0.142 0.136-0.241 0.276-0.296 0.42s-0.086 0.325-0.091 0.545h-1.243zM7.326 11.604c0-0.215 0.078-0.39 0.233-0.528s0.349-0.207 0.58-0.207c0.232 0 0.425 0.068 0.58 0.207s0.233 0.313 0.233 0.528-0.078 0.39-0.233 0.528c-0.155 0.138-0.349 0.207-0.58 0.207s-0.425-0.068-0.58-0.207c-0.155-0.138-0.233-0.313-0.233-0.528z"
fill="#fff"
/>
</g>
</svg>
overview.metric.security_hotspots
</div>
<a
class="overview-domain-measure-history-link"
>
<svg
height="16"
space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421"
version="1.1"
viewBox="0 0 16 16"
width="16"
xlink="http://www.w3.org/1999/xlink"
>
<path
d="M14.7 3.4v3.3c0 .1 0 .2-.1.2s-.2 0-.3-.1l-.9-.9-4.8 4.8c-.1.1-.1.1-.2.1s-.1 0-.2-.1L6.4 9l-3.2 3.2-1.5-1.5 4.5-4.5c.1-.1.1-.1.2-.1s.1 0 .2.1L8.4 8l3.5-3.5-.9-1c-.1-.1-.1-.2-.1-.3s.1-.1.2-.1h3.3c.1 0 .1 0 .2.1.1 0 .1.1.1.2z"
style="fill:currentColor"
/>
</svg>
<span>
project_activity.page
</span>
</a>
</div>
</div>
<div
class="overview-domain-timeline"
/>
</div>
<div
class="overview-domain-leak"
>
<div
class="overview-domain-measures"
>
<div
class="overview-domain-measure"
>
<div
class="overview-domain-measure-value"
>
<span
class="offset-left"
>
<a>
1
</a>
</span>
<div
class="overview-domain-measure-sup"
>
<a
class="link-no-underline"
>
<span
aria-label="metric.has_rating_X.E"
class="rating rating-E"
>
E
</span>
</a>
</div>
</div>
<div
class="overview-domain-measure-label"
>
<svg
class="little-spacer-right"
height="16"
space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421"
version="1.1"
viewBox="0 0 16 16"
width="16"
xlink="http://www.w3.org/1999/xlink"
>
<path
d="M10.8 5H6V3.9a2.28 2.28 0 0 1 2-2.5 2.22 2.22 0 0 1 1.8 1.2.48.48 0 0 0 .7.2.48.48 0 0 0 .2-.7A3 3 0 0 0 8 .4a3.34 3.34 0 0 0-3 3.5v1.2a2.16 2.16 0 0 0-2 2.1v4.4a2.22 2.22 0 0 0 2.2 2.2h5.6a2.22 2.22 0 0 0 2.2-2.2V7.2A2.22 2.22 0 0 0 10.8 5zm-2.2 5.5v1.2H7.4v-1.2a1.66 1.66 0 0 1-1.1-1.6A1.75 1.75 0 0 1 8 7.2a1.71 1.71 0 0 1 .6 3.3z"
style="fill:currentColor"
/>
</svg>
overview.metric.new_vulnerabilities
</div>
</div>
<div
class="overview-domain-measure"
>
<div
class="overview-domain-measure-value overview-domain-measure-value-small"
>
<span>
<a>
10
</a>
</span>
</div>
<div
class="overview-domain-measure-label"
>
<svg
class="little-spacer-right"
height="16"
space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421"
version="1.1"
viewBox="0 0 16 16"
width="16"
xlink="http://www.w3.org/1999/xlink"
>
<g
style="fill:currentColor"
>
<path
d="M10.238 2.416c-0.432-0.895-1.259-1.504-2.202-1.504-1.386 0-2.521 1.318-2.521 2.927v5.481"
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-width="1.1429"
/>
<path
d="M8.537 10.372v1.199h-1.099v-1.199c-0.638-0.228-1.099-0.832-1.099-1.546 0-0.909 0.739-1.649 1.648-1.649s1.649 0.74 1.649 1.649c0 0.715-0.461 1.32-1.099 1.546zM10.734 4.979h-5.494c-1.21 0-2.199 0.989-2.199 2.197v4.395c0 1.21 0.989 2.199 2.199 2.199h5.494c1.209 0 2.197-0.989 2.197-2.199v-4.395c0-1.209-0.989-2.197-2.197-2.197z"
/>
<path
d="M4.030 6.352h6.923v6.923h-6.923z"
/>
<path
d="M7.504 10.283c0-0.423 0.048-0.757 0.144-1.002s0.251-0.457 0.465-0.637c0.215-0.18 0.377-0.344 0.489-0.493s0.167-0.313 0.167-0.493c0-0.438-0.189-0.656-0.565-0.656-0.174 0-0.314 0.064-0.421 0.191s-0.164 0.3-0.17 0.518h-1.469c0.006-0.58 0.189-1.031 0.548-1.354s0.864-0.485 1.513-0.485c0.646 0 1.147 0.149 1.501 0.447s0.532 0.723 0.532 1.274c0 0.241-0.048 0.459-0.144 0.656s-0.249 0.398-0.46 0.604l-0.5 0.465c-0.142 0.136-0.241 0.276-0.296 0.42s-0.086 0.325-0.091 0.545h-1.243zM7.326 11.604c0-0.215 0.078-0.39 0.233-0.528s0.349-0.207 0.58-0.207c0.232 0 0.425 0.068 0.58 0.207s0.233 0.313 0.233 0.528-0.078 0.39-0.233 0.528c-0.155 0.138-0.349 0.207-0.58 0.207s-0.425-0.068-0.58-0.207c-0.155-0.138-0.233-0.313-0.233-0.528z"
fill="#fff"
/>
</g>
</svg>
overview.metric.new_security_hotspots
</div>
</div>
</div>
<div
class="overview-domain-timeline"
/>
</div>
</div>
</div>
`;

+ 15
- 12
server/sonar-web/src/main/js/apps/overview/main/enhance.tsx View File

@@ -20,11 +20,11 @@
import * as React from 'react';
import { Link } from 'react-router';
import DrilldownLink from '../../../components/shared/DrilldownLink';
import BubblesIcon from '../../../components/icons-components/BubblesIcon';
import HistoryIcon from '../../../components/icons-components/HistoryIcon';
import Rating from '../../../components/ui/Rating';
import Timeline from '../components/Timeline';
import Tooltip from '../../../components/controls/Tooltip';
import { getWrappedDisplayName } from '../../../components/hoc/utils';
import {
formatMeasure,
isDiffMetric,
@@ -32,7 +32,7 @@ import {
getShortType,
getRatingTooltip
} from '../../../helpers/measures';
import { getLocalizedMetricName } from '../../../helpers/l10n';
import { getLocalizedMetricName, translate } from '../../../helpers/l10n';
import { getPeriodDate } from '../../../helpers/periods';
import {
getComponentDrilldownUrl,
@@ -54,8 +54,8 @@ export interface EnhanceProps {

export interface ComposedProps extends EnhanceProps {
getValue: (measure: T.MeasureEnhanced) => string | undefined;
renderHeader: (domain: string, label: string) => React.ReactNode;
renderMeasure: (metricKey: string) => React.ReactNode;
renderHeader: (domain: string, label?: string) => React.ReactNode;
renderMeasure: (metricKey: string, tooltip?: React.ReactNode) => React.ReactNode;
renderRating: (metricKey: string) => React.ReactNode;
renderIssues: (metric: string, type: T.IssueType) => React.ReactNode;
renderHistoryLink: (metricKey: string) => React.ReactNode;
@@ -64,7 +64,7 @@ export interface ComposedProps extends EnhanceProps {

export default function enhance(ComposedComponent: React.ComponentType<ComposedProps>) {
return class extends React.PureComponent<EnhanceProps> {
static displayName = `enhance(${ComposedComponent.displayName})}`;
static displayName = getWrappedDisplayName(ComposedComponent, 'enhance');

getValue = (measure: T.MeasureEnhanced) => {
const { leakPeriod } = this.props;
@@ -76,27 +76,28 @@ export default function enhance(ComposedComponent: React.ComponentType<ComposedP
: measure.value;
};

renderHeader = (domain: string, label: string) => {
renderHeader = (domain: string, label?: string) => {
const { branchLike, component } = this.props;
label = label !== undefined ? label : translate('metric_domain', domain);
return (
<div className="overview-card-header">
<div className="overview-title">
<span>{label}</span>
<Link
className="button button-small spacer-left text-text-bottom"
className="spacer-left small"
to={getComponentDrilldownUrl({
componentKey: component.key,
metric: domain,
branchLike
})}>
<BubblesIcon size={14} />
{translate('layout.measures')}
</Link>
</div>
</div>
);
};

renderMeasure = (metricKey: string) => {
renderMeasure = (metricKey: string, tooltip?: React.ReactNode) => {
const { branchLike, measures, component } = this.props;
const measure = measures.find(measure => measure.metric.key === metricKey);
if (!measure) {
@@ -113,8 +114,9 @@ export default function enhance(ComposedComponent: React.ComponentType<ComposedP
</DrilldownLink>
</div>

<div className="overview-domain-measure-label offset-left">
<div className="overview-domain-measure-label display-flex-center display-flex-justify-center">
{getLocalizedMetricName(measure.metric)}
{tooltip}
{this.renderHistoryLink(measure.metric.key)}
</div>
</div>
@@ -149,7 +151,7 @@ export default function enhance(ComposedComponent: React.ComponentType<ComposedP
const { branchLike, measures, component } = this.props;
const measure = measures.find(measure => measure.metric.key === metric);
if (!measure) {
return null;
return <span>—</span>;
}

const value = this.getValue(measure);
@@ -166,12 +168,13 @@ export default function enhance(ComposedComponent: React.ComponentType<ComposedP
};

renderHistoryLink = (metricKey: string) => {
const linkClass = 'button button-small spacer-left overview-domain-measure-history-link';
const linkClass = 'overview-domain-measure-history-link';
return (
<Link
className={linkClass}
to={getMeasureHistoryUrl(this.props.component.key, metricKey, this.props.branchLike)}>
<HistoryIcon />
<span>{translate('project_activity.page')}</span>
</Link>
);
};

+ 28
- 32
server/sonar-web/src/main/js/apps/overview/styles.css View File

@@ -44,6 +44,7 @@
.overview-title {
font-size: var(--bigFontSize);
font-weight: 400;
line-height: 1.3;
}

/*
@@ -162,12 +163,16 @@
}

.overview-card {
margin: 15px 0;
margin: calc(2 * var(--gridSize)) 0;
padding-top: 3px;
}

.overview-card-special {
padding-bottom: 26px;
border-bottom: 1px solid var(--barBorderColor);
.overview-card .offset-left {
margin-left: 30px;
}

.overview-card .neg-offset-left {
margin-left: -30px;
}

.overview-card-header {
@@ -189,7 +194,6 @@
.overview-domain-leak {
position: relative;
display: flex;
padding: 15px 10px;
}

.overview-domain-nutshell {
@@ -218,26 +222,18 @@
z-index: var(--normalZIndex);
display: flex;
flex: 1;
align-items: center;
padding: 0;
}

.overview-domain-measures + .overview-domain-measures {
margin-top: 30px;
}

.overview-domain-measures + .overview-domain-measures .overview-domain-measure-value {
font-size: var(--mediumFontSize);
font-weight: 400;
}

.overview-domain-measures + .overview-domain-measures .overview-domain-measure-label {
margin-top: 4px;
}

.overview-domain-measure {
flex: 1;
text-align: center;
padding: 15px 10px;
position: relative;
}

.overview-domain-measures-big .overview-domain-measure {
padding-top: 24px;
}

.overview-domain-measure-value {
@@ -247,6 +243,11 @@
white-space: nowrap;
}

.overview-domain-measure-value-small {
font-size: var(--hugeFontSize);
margin-top: 12px;
}

.overview-domain-secondary-measure-value {
line-height: 1;
font-size: 20px;
@@ -257,23 +258,18 @@
margin-top: 10px;
}

.overview-domain-measure-label.offset-left {
margin-right: -30px;
}

.overview-domain-measure-label > svg {
margin-top: 3px;
}

.overview-domain-leak .overview-domain-measure-label > svg {
margin-top: 0;
}

.overview-domain-measure-history-link {
vertical-align: bottom;
position: absolute;
top: var(--gridSize);
right: var(--gridSize);
border-bottom: 0;
visibility: hidden;
}

.overview-domain-measure-history-link span {
border-bottom: 1px solid var(--lightBlue);
}

.overview-domain-measure:hover .overview-domain-measure-history-link {
visibility: visible;
}

+ 4
- 0
server/sonar-web/src/main/js/apps/overview/utils.ts View File

@@ -40,6 +40,8 @@ export const METRICS = [
'new_vulnerabilities',
'security_rating',
'new_security_rating',
'security_hotspots',
'new_security_hotspots',

// code smells
'code_smells',
@@ -84,6 +86,8 @@ export const PR_METRICS = [
];

export const HISTORY_METRICS_LIST = [
'bugs',
'vulnerabilities',
'sqale_index',
'duplicated_lines_density',
'ncloc',

+ 1
- 1
server/sonar-web/src/main/js/apps/securityReports/components/VulnerabilityList.tsx View File

@@ -301,7 +301,7 @@ export default class VulnerabilityList extends React.PureComponent<Props, State>
<th className="text-right security-column-separator" colSpan={3}>
<div className="display-inline-flex-center">
<SecurityHotspotIcon className="spacer-right" />
{translate('security_reports.list.hotspots')}
{translate('security_reports.list.security_hotspots')}
</div>
</th>
</tr>

+ 2
- 2
server/sonar-web/src/main/js/apps/securityReports/components/__tests__/__snapshots__/VulnerabilityList-test.tsx.snap View File

@@ -36,7 +36,7 @@ exports[`renders 1`] = `
<SecurityHotspotIcon
className="spacer-right"
/>
security_reports.list.hotspots
security_reports.list.security_hotspots
</div>
</th>
</tr>
@@ -504,7 +504,7 @@ exports[`renders with cwe 1`] = `
<SecurityHotspotIcon
className="spacer-right"
/>
security_reports.list.hotspots
security_reports.list.security_hotspots
</div>
</th>
</tr>

+ 17
- 0
server/sonar-web/src/main/js/helpers/testMocks.ts View File

@@ -268,6 +268,23 @@ export function mockMeasure(overrides: Partial<T.Measure> = {}): T.Measure {
};
}

export function mockMeasureEnhanced(overrides: Partial<T.MeasureEnhanced> = {}): T.MeasureEnhanced {
return {
bestValue: true,
leak: '1',
metric: mockMetric({ ...(overrides.metric || {}) }),
periods: [
{
bestValue: true,
index: 1,
value: '1.0'
}
],
value: '1.0',
...overrides
};
}

export function mockOrganization(overrides: Partial<T.Organization> = {}): T.Organization {
return { key: 'foo', name: 'Foo', ...overrides };
}

+ 3
- 1
sonar-core/src/main/resources/org/sonar/l10n/core.properties View File

@@ -2089,7 +2089,7 @@ security_reports.owaspTop10.description=Track Vulnerabilities and Security Hotsp
security_reports.sansTop25.description=Track Vulnerabilities and Security Hotspots conforming to SANS Top 25 standard (25 CWE items in three categories).
security_reports.list.categories=Categories
security_reports.list.vulnerabilities=Vulnerabilities
security_reports.list.hotspots=Security Hotspots
security_reports.list.security_hotspots=Security Hotspots
security_reports.line.open=Open
security_reports.line.wont_fix=Won't Fix
security_reports.line.in_review=In Review
@@ -2454,6 +2454,8 @@ overview.metric.bugs=Bugs
overview.metric.new_bugs=New Bugs
overview.metric.vulnerabilities=Vulnerabilities
overview.metric.new_vulnerabilities=New Vulnerabilities
overview.metric.security_hotspots=Security Hotspots
overview.metric.new_security_hotspots=New Security Hotspots
overview.metric.issues=Issues
overview.metric.effort=Debt
overview.metric.new_issues=New Issues

Loading…
Cancel
Save