diff options
author | Grégoire Aubert <gregoire.aubert@sonarsource.com> | 2019-04-09 13:55:26 +0200 |
---|---|---|
committer | SonarTech <sonartech@sonarsource.com> | 2019-04-23 20:21:09 +0200 |
commit | b92d5bf5496c2ea1705cc07de0228e2a868f926e (patch) | |
tree | f1d9dd3814bece332a3bc912fcd39b7d5350bd88 | |
parent | 4f885e88db04134cea9d500e89f28e6a09b65db2 (diff) | |
download | sonarqube-b92d5bf5496c2ea1705cc07de0228e2a868f926e.tar.gz sonarqube-b92d5bf5496c2ea1705cc07de0228e2a868f926e.zip |
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
35 files changed, 2029 insertions, 178 deletions
diff --git a/server/sonar-docs/src/tooltips/metrics/bugs.md b/server/sonar-docs/src/tooltips/metrics/bugs.md new file mode 100644 index 00000000000..ff8e346d96b --- /dev/null +++ b/server/sonar-docs/src/tooltips/metrics/bugs.md @@ -0,0 +1 @@ +A coding error that will break your code and needs to be fixed immediately.
\ No newline at end of file diff --git a/server/sonar-docs/src/tooltips/metrics/code-smells.md b/server/sonar-docs/src/tooltips/metrics/code-smells.md new file mode 100644 index 00000000000..95a031e8373 --- /dev/null +++ b/server/sonar-docs/src/tooltips/metrics/code-smells.md @@ -0,0 +1 @@ +Code that is confusing and difficult to maintain.
\ No newline at end of file diff --git a/server/sonar-docs/src/tooltips/metrics/coverage.md b/server/sonar-docs/src/tooltips/metrics/coverage.md new file mode 100644 index 00000000000..28784cdc084 --- /dev/null +++ b/server/sonar-docs/src/tooltips/metrics/coverage.md @@ -0,0 +1 @@ +The percentage of lines of code covered by tests.
\ No newline at end of file diff --git a/server/sonar-docs/src/tooltips/metrics/debt.md b/server/sonar-docs/src/tooltips/metrics/debt.md new file mode 100644 index 00000000000..8b6141bf74b --- /dev/null +++ b/server/sonar-docs/src/tooltips/metrics/debt.md @@ -0,0 +1 @@ +The estimated time it will take to fix all Code Smells.
\ No newline at end of file diff --git a/server/sonar-docs/src/tooltips/metrics/duplicated-blocks.md b/server/sonar-docs/src/tooltips/metrics/duplicated-blocks.md new file mode 100644 index 00000000000..0458c5f7df1 --- /dev/null +++ b/server/sonar-docs/src/tooltips/metrics/duplicated-blocks.md @@ -0,0 +1 @@ +The number of duplicated blocks of lines of code.
\ No newline at end of file diff --git a/server/sonar-docs/src/tooltips/metrics/duplications.md b/server/sonar-docs/src/tooltips/metrics/duplications.md new file mode 100644 index 00000000000..31ae4afde25 --- /dev/null +++ b/server/sonar-docs/src/tooltips/metrics/duplications.md @@ -0,0 +1 @@ +Identical lines of code.
\ No newline at end of file diff --git a/server/sonar-docs/src/tooltips/metrics/security-hotspots.md b/server/sonar-docs/src/tooltips/metrics/security-hotspots.md new file mode 100644 index 00000000000..a9460e893e0 --- /dev/null +++ b/server/sonar-docs/src/tooltips/metrics/security-hotspots.md @@ -0,0 +1 @@ +Security-sensitive code that requires manual review to assess whether or not a vulnerability exists. diff --git a/server/sonar-docs/src/tooltips/metrics/unit-tests.md b/server/sonar-docs/src/tooltips/metrics/unit-tests.md new file mode 100644 index 00000000000..96fb4ef3663 --- /dev/null +++ b/server/sonar-docs/src/tooltips/metrics/unit-tests.md @@ -0,0 +1 @@ +Tests that ensure your code is working properly.
\ No newline at end of file diff --git a/server/sonar-docs/src/tooltips/metrics/vulnerabilities.md b/server/sonar-docs/src/tooltips/metrics/vulnerabilities.md new file mode 100644 index 00000000000..f7845ac883e --- /dev/null +++ b/server/sonar-docs/src/tooltips/metrics/vulnerabilities.md @@ -0,0 +1 @@ +Code that can be exploited by hackers.
\ No newline at end of file diff --git a/server/sonar-web/src/main/js/app/styles/init/misc.css b/server/sonar-web/src/main/js/app/styles/init/misc.css index 06637e62f6d..bbe084f4229 100644 --- a/server/sonar-web/src/main/js/app/styles/init/misc.css +++ b/server/sonar-web/src/main/js/app/styles/init/misc.css @@ -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; diff --git a/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx b/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx index 59c6ff4fefd..be4107412cc 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx @@ -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} /> diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/OverviewApp-test.tsx b/server/sonar-web/src/main/js/apps/overview/components/__tests__/OverviewApp-test.tsx index 84c7cc24557..c107902beb2 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/OverviewApp-test.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/OverviewApp-test.tsx @@ -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' }] } ] }) })); diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/OverviewApp-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/OverviewApp-test.tsx.snap index 2bc253d326b..b92c643ffa7 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/OverviewApp-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/OverviewApp-test.tsx.snap @@ -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={ diff --git a/server/sonar-web/src/main/js/apps/overview/main/BugsAndVulnerabilities.tsx b/server/sonar-web/src/main/js/apps/overview/main/Bugs.tsx index 5ef03220d46..e370f3ae8c1 100644 --- a/server/sonar-web/src/main/js/apps/overview/main/BugsAndVulnerabilities.tsx +++ b/server/sonar-web/src/main/js/apps/overview/main/Bugs.tsx @@ -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); diff --git a/server/sonar-web/src/main/js/apps/overview/main/CodeSmells.tsx b/server/sonar-web/src/main/js/apps/overview/main/CodeSmells.tsx index e67b35a42ee..fcf6d78cc6d 100644 --- a/server/sonar-web/src/main/js/apps/overview/main/CodeSmells.tsx +++ b/server/sonar-web/src/main/js/apps/overview/main/CodeSmells.tsx @@ -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> ); } diff --git a/server/sonar-web/src/main/js/apps/overview/main/Coverage.tsx b/server/sonar-web/src/main/js/apps/overview/main/Coverage.tsx index 3b1960b5b31..a335fa06f50 100644 --- a/server/sonar-web/src/main/js/apps/overview/main/Coverage.tsx +++ b/server/sonar-web/src/main/js/apps/overview/main/Coverage.tsx @@ -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> diff --git a/server/sonar-web/src/main/js/apps/overview/main/Duplications.tsx b/server/sonar-web/src/main/js/apps/overview/main/Duplications.tsx index 04dea37a24e..30b4c08d570 100644 --- a/server/sonar-web/src/main/js/apps/overview/main/Duplications.tsx +++ b/server/sonar-web/src/main/js/apps/overview/main/Duplications.tsx @@ -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> diff --git a/server/sonar-web/src/main/js/apps/overview/main/VulnerabilitiesAndHotspots.tsx b/server/sonar-web/src/main/js/apps/overview/main/VulnerabilitiesAndHotspots.tsx new file mode 100644 index 00000000000..3fd1e96db20 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/main/VulnerabilitiesAndHotspots.tsx @@ -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); diff --git a/server/sonar-web/src/main/js/apps/overview/main/__tests__/Bugs-test.tsx b/server/sonar-web/src/main/js/apps/overview/main/__tests__/Bugs-test.tsx new file mode 100644 index 00000000000..1c52153ed50 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/main/__tests__/Bugs-test.tsx @@ -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> + ); +} diff --git a/server/sonar-web/src/main/js/apps/overview/main/__tests__/CodeSmells-test.tsx b/server/sonar-web/src/main/js/apps/overview/main/__tests__/CodeSmells-test.tsx new file mode 100644 index 00000000000..eb4889945ed --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/main/__tests__/CodeSmells-test.tsx @@ -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} + /> + ); +} diff --git a/server/sonar-web/src/main/js/apps/overview/main/__tests__/Coverage-test.tsx b/server/sonar-web/src/main/js/apps/overview/main/__tests__/Coverage-test.tsx new file mode 100644 index 00000000000..6186947ffda --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/main/__tests__/Coverage-test.tsx @@ -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} + /> + ); +} diff --git a/server/sonar-web/src/main/js/apps/overview/main/__tests__/Duplications-test.tsx b/server/sonar-web/src/main/js/apps/overview/main/__tests__/Duplications-test.tsx new file mode 100644 index 00000000000..e98f2c2cfd3 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/main/__tests__/Duplications-test.tsx @@ -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} + /> + ); +} diff --git a/server/sonar-web/src/main/js/apps/overview/main/__tests__/VulnerabilitiesAndHotspots-test.tsx b/server/sonar-web/src/main/js/apps/overview/main/__tests__/VulnerabilitiesAndHotspots-test.tsx new file mode 100644 index 00000000000..b9b05f5ad58 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/main/__tests__/VulnerabilitiesAndHotspots-test.tsx @@ -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} + /> + ); +} diff --git a/server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/Bugs-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/Bugs-test.tsx.snap new file mode 100644 index 00000000000..95c23ca9f85 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/Bugs-test.tsx.snap @@ -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> +`; diff --git a/server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/CodeSmells-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/CodeSmells-test.tsx.snap new file mode 100644 index 00000000000..1842d0aa2b8 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/CodeSmells-test.tsx.snap @@ -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> +`; diff --git a/server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/Coverage-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/Coverage-test.tsx.snap new file mode 100644 index 00000000000..65cc3f86dcb --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/Coverage-test.tsx.snap @@ -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> +`; diff --git a/server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/Duplications-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/Duplications-test.tsx.snap new file mode 100644 index 00000000000..7c06ddb9058 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/Duplications-test.tsx.snap @@ -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> +`; diff --git a/server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/VulnerabilitiesAndHotspots-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/VulnerabilitiesAndHotspots-test.tsx.snap new file mode 100644 index 00000000000..826e2a6bb8c --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/VulnerabilitiesAndHotspots-test.tsx.snap @@ -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> +`; diff --git a/server/sonar-web/src/main/js/apps/overview/main/enhance.tsx b/server/sonar-web/src/main/js/apps/overview/main/enhance.tsx index 6ce6f657113..72cda201606 100644 --- a/server/sonar-web/src/main/js/apps/overview/main/enhance.tsx +++ b/server/sonar-web/src/main/js/apps/overview/main/enhance.tsx @@ -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> ); }; diff --git a/server/sonar-web/src/main/js/apps/overview/styles.css b/server/sonar-web/src/main/js/apps/overview/styles.css index 3e552f55f3c..ef63faa08ef 100644 --- a/server/sonar-web/src/main/js/apps/overview/styles.css +++ b/server/sonar-web/src/main/js/apps/overview/styles.css @@ -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; } diff --git a/server/sonar-web/src/main/js/apps/overview/utils.ts b/server/sonar-web/src/main/js/apps/overview/utils.ts index 9a490f6098a..4aab1ebe562 100644 --- a/server/sonar-web/src/main/js/apps/overview/utils.ts +++ b/server/sonar-web/src/main/js/apps/overview/utils.ts @@ -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', diff --git a/server/sonar-web/src/main/js/apps/securityReports/components/VulnerabilityList.tsx b/server/sonar-web/src/main/js/apps/securityReports/components/VulnerabilityList.tsx index 95dc4630e29..22bf4655635 100755 --- a/server/sonar-web/src/main/js/apps/securityReports/components/VulnerabilityList.tsx +++ b/server/sonar-web/src/main/js/apps/securityReports/components/VulnerabilityList.tsx @@ -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> diff --git a/server/sonar-web/src/main/js/apps/securityReports/components/__tests__/__snapshots__/VulnerabilityList-test.tsx.snap b/server/sonar-web/src/main/js/apps/securityReports/components/__tests__/__snapshots__/VulnerabilityList-test.tsx.snap index 238d720bad0..98c06bbb330 100644 --- a/server/sonar-web/src/main/js/apps/securityReports/components/__tests__/__snapshots__/VulnerabilityList-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/securityReports/components/__tests__/__snapshots__/VulnerabilityList-test.tsx.snap @@ -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> diff --git a/server/sonar-web/src/main/js/helpers/testMocks.ts b/server/sonar-web/src/main/js/helpers/testMocks.ts index 3d52b4e8098..dd3b736a845 100644 --- a/server/sonar-web/src/main/js/helpers/testMocks.ts +++ b/server/sonar-web/src/main/js/helpers/testMocks.ts @@ -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 }; } diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index a2196a1509c..61016a97cee 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -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 |