aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>2017-08-07 14:29:30 +0200
committerGrégoire Aubert <gregoire.aubert@sonarsource.com>2017-08-14 11:44:44 +0200
commitee4605dde9a7d1859f554de7b220947821a6d5d4 (patch)
tree44825a598897ad3ea00bd73937fa1e54afb45ffb
parentbb393dd277ab06c8451513a6339171e800fc9944 (diff)
downloadsonarqube-ee4605dde9a7d1859f554de7b220947821a6d5d4.tar.gz
sonarqube-ee4605dde9a7d1859f554de7b220947821a6d5d4.zip
SONAR-9608 SONAR-9615 Add inline documentation on project measures page
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.css1
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/drilldown/BubbleChart.js14
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/sidebar/DomainFacet.js16
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/style.css38
-rw-r--r--server/sonar-web/src/main/js/components/facet/FacetHeader.js29
-rw-r--r--server/sonar-web/src/main/js/components/facet/__tests__/__snapshots__/FacetHeader-test.js.snap15
-rw-r--r--server/sonar-web/src/main/js/components/icons-components/HelpIcon.js2
-rw-r--r--sonar-core/src/main/resources/org/sonar/l10n/core.properties11
8 files changed, 98 insertions, 28 deletions
diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.css b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.css
index bdb8e019611..3bbf08445ed 100644
--- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.css
+++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.css
@@ -29,6 +29,7 @@
.navbar-help {
line-height: 16px !important;
padding: 7px !important;
+ color: #fff !important;
}
.global-navbar-menu {
diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/BubbleChart.js b/server/sonar-web/src/main/js/apps/component-measures/drilldown/BubbleChart.js
index 8ef9df9b759..897918ed170 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/drilldown/BubbleChart.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/drilldown/BubbleChart.js
@@ -175,6 +175,19 @@ export default class BubbleChart extends React.PureComponent {
);
}
+ renderChartFooter(domain: string) {
+ const description = `component_measures.overview.${domain}.description`;
+ const translatedDescription = translate(description);
+ if (description === translatedDescription) {
+ return null;
+ }
+ return (
+ <div className="measure-overview-bubble-chart-footer">
+ {translatedDescription}
+ </div>
+ );
+ }
+
render() {
if (this.props.components.length <= 0) {
return <EmptyResult />;
@@ -197,6 +210,7 @@ export default class BubbleChart extends React.PureComponent {
<div className="measure-overview-bubble-chart-axis y">
{getLocalizedMetricName(yMetric)}
</div>
+ {this.renderChartFooter(domain)}
</div>
);
}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/DomainFacet.js b/server/sonar-web/src/main/js/apps/component-measures/sidebar/DomainFacet.js
index ee4d5de394d..0efc611f94e 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/sidebar/DomainFacet.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/sidebar/DomainFacet.js
@@ -31,6 +31,7 @@ import { filterMeasures, hasBubbleChart, sortMeasures } from '../utils';
import {
getLocalizedMetricDomain,
getLocalizedMetricName,
+ translate,
translateWithParameters
} from '../../../helpers/l10n';
import type { MeasureEnhanced } from '../../../components/measure/types';
@@ -48,6 +49,16 @@ export default class DomainFacet extends React.PureComponent {
handleHeaderClick = () => this.props.onToggle(this.props.domain.name);
+ hasFacetSelected = (
+ domain: { name: string },
+ measures: Array<MeasureEnhanced>,
+ selected: string
+ ) => {
+ const measureSelected = measures.find(measure => measure.metric.key === selected);
+ const overviewSelected = domain.name === selected && hasBubbleChart(domain.name);
+ return measureSelected || overviewSelected;
+ };
+
renderOverviewFacet = () => {
const { domain, selected } = this.props;
if (!hasBubbleChart(domain.name)) {
@@ -79,13 +90,16 @@ export default class DomainFacet extends React.PureComponent {
render() {
const { domain, selected } = this.props;
const measures = sortMeasures(domain.name, filterMeasures(domain.measures));
+ const helper = `component_measures.domain_facets.${domain.name}.help`;
+ const translatedHelper = translate(helper);
return (
<FacetBox>
<FacetHeader
+ helper={helper !== translatedHelper ? translatedHelper : undefined}
name={getLocalizedMetricDomain(domain.name)}
onClick={this.handleHeaderClick}
open={this.props.open}
- values={measures.find(measure => measure.metric.key === selected) ? 1 : 0}
+ values={this.hasFacetSelected(domain, measures, selected) ? 1 : 0}
/>
{this.props.open &&
diff --git a/server/sonar-web/src/main/js/apps/component-measures/style.css b/server/sonar-web/src/main/js/apps/component-measures/style.css
index 5327c58edd2..9739bc6ef15 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/style.css
+++ b/server/sonar-web/src/main/js/apps/component-measures/style.css
@@ -90,47 +90,57 @@
vertical-align: middle;
}
-.measure-details-bubble-chart {
+.measure-overview-bubble-chart {
position: relative;
- padding: 0 0 30px 60px;
border: 1px solid #e6e6e6;
background-color: #fff;
}
-.measure-details-bubble-chart-header {
+.measure-overview-bubble-chart-content {
+ padding: 0;
+ padding-left: 60px;
+}
+
+.measure-overview-bubble-chart-header {
display: flex;
align-items: center;
padding: 16px;
- margin-left: -60px;
border-bottom: 1px solid #e6e6e6;
}
-.measure-details-bubble-chart-title {
+.measure-overview-bubble-chart-title {
position: absolute;
}
-.measure-details-bubble-chart-legend {
+.measure-overview-bubble-chart-legend {
display: flex;
flex-direction: column;
text-align: center;
flex-grow: 1;
}
-.measure-details-bubble-chart-axis {
- position: absolute;
+.measure-overview-bubble-chart-footer {
+ padding: 15px 60px;
+ border-top: 1px solid #e6e6e6;
+ text-align: center;
+ font-size: 12px;
+ line-height: 1.4;
+}
+
+.measure-overview-bubble-chart-axis {
color: #777;
font-size: 12px;
}
-.measure-details-bubble-chart-axis.x {
- left: 50%;
- bottom: 10px;
- width: 500px;
- margin-left: -250px;
+.measure-overview-bubble-chart-axis.x {
+ position: relative;
+ top: -8px;
+ padding-bottom: 8px;
text-align: center;
}
-.measure-details-bubble-chart-axis.y {
+.measure-overview-bubble-chart-axis.y {
+ position: absolute;
top: 50%;
left: -20px;
transform: rotate(-90deg);
diff --git a/server/sonar-web/src/main/js/components/facet/FacetHeader.js b/server/sonar-web/src/main/js/components/facet/FacetHeader.js
index 42c7b274f89..0dfd5440e4c 100644
--- a/server/sonar-web/src/main/js/components/facet/FacetHeader.js
+++ b/server/sonar-web/src/main/js/components/facet/FacetHeader.js
@@ -20,9 +20,12 @@
// @flow
/* eslint-disable max-len */
import React from 'react';
+import Tooltip from '../controls/Tooltip';
+import HelpIcon from '../icons-components/HelpIcon';
import { translate } from '../../helpers/l10n';
type Props = {|
+ helper?: string,
name: string,
onClear?: () => void,
onClick?: () => void,
@@ -55,7 +58,12 @@ export default class FacetHeader extends React.PureComponent {
renderCheckbox() {
return (
- <svg viewBox="0 0 1792 1792" width="10" height="10" style={{ paddingTop: 3 }}>
+ <svg
+ className="little-spacer-right"
+ viewBox="0 0 1792 1792"
+ width="10"
+ height="10"
+ style={{ paddingTop: 3 }}>
{this.props.open
? <path
style={{ fill: 'currentColor ' }}
@@ -69,6 +77,19 @@ export default class FacetHeader extends React.PureComponent {
);
}
+ renderHelper() {
+ if (!this.props.helper) {
+ return null;
+ }
+ return (
+ <Tooltip overlay={this.props.helper} placement="right">
+ <span>
+ <HelpIcon className="spacer-left text-info" />
+ </span>
+ </Tooltip>
+ );
+ }
+
renderValueIndicator() {
if (this.props.open || !this.props.values) {
return null;
@@ -94,10 +115,14 @@ export default class FacetHeader extends React.PureComponent {
{this.props.onClick
? <a className="search-navigator-facet-header" href="#" onClick={this.handleClick}>
- {this.renderCheckbox()} {this.props.name} {this.renderValueIndicator()}
+ {this.renderCheckbox()}
+ {this.props.name}
+ {this.renderHelper()}
+ {this.renderValueIndicator()}
</a>
: <span className="search-navigator-facet-header">
{this.props.name}
+ {this.renderHelper()}
</span>}
</div>
);
diff --git a/server/sonar-web/src/main/js/components/facet/__tests__/__snapshots__/FacetHeader-test.js.snap b/server/sonar-web/src/main/js/components/facet/__tests__/__snapshots__/FacetHeader-test.js.snap
index 8c92ac2d4ba..3251d6c9e5f 100644
--- a/server/sonar-web/src/main/js/components/facet/__tests__/__snapshots__/FacetHeader-test.js.snap
+++ b/server/sonar-web/src/main/js/components/facet/__tests__/__snapshots__/FacetHeader-test.js.snap
@@ -14,6 +14,7 @@ exports[`should clear 1`] = `
onClick={[Function]}
>
<svg
+ className="little-spacer-right"
height="10"
style={
Object {
@@ -32,9 +33,7 @@ exports[`should clear 1`] = `
}
/>
</svg>
-
foo
-
<span
className="spacer-left badge is-rounded"
>
@@ -52,6 +51,7 @@ exports[`should render closed facet with value 1`] = `
onClick={[Function]}
>
<svg
+ className="little-spacer-right"
height="10"
style={
Object {
@@ -70,9 +70,7 @@ exports[`should render closed facet with value 1`] = `
}
/>
</svg>
-
foo
-
<span
className="spacer-left badge is-rounded"
>
@@ -90,6 +88,7 @@ exports[`should render closed facet without value 1`] = `
onClick={[Function]}
>
<svg
+ className="little-spacer-right"
height="10"
style={
Object {
@@ -108,9 +107,7 @@ exports[`should render closed facet without value 1`] = `
}
/>
</svg>
-
foo
-
</a>
</div>
`;
@@ -123,6 +120,7 @@ exports[`should render open facet with value 1`] = `
onClick={[Function]}
>
<svg
+ className="little-spacer-right"
height="10"
style={
Object {
@@ -141,9 +139,7 @@ exports[`should render open facet with value 1`] = `
}
/>
</svg>
-
foo
-
</a>
</div>
`;
@@ -156,6 +152,7 @@ exports[`should render open facet without value 1`] = `
onClick={[Function]}
>
<svg
+ className="little-spacer-right"
height="10"
style={
Object {
@@ -174,9 +171,7 @@ exports[`should render open facet without value 1`] = `
}
/>
</svg>
-
foo
-
</a>
</div>
`;
diff --git a/server/sonar-web/src/main/js/components/icons-components/HelpIcon.js b/server/sonar-web/src/main/js/components/icons-components/HelpIcon.js
index 86e5241b438..af6304198d3 100644
--- a/server/sonar-web/src/main/js/components/icons-components/HelpIcon.js
+++ b/server/sonar-web/src/main/js/components/icons-components/HelpIcon.js
@@ -28,7 +28,7 @@ export default function HelpIcon({ className, size = 16 }: Props) {
<svg className={className} viewBox="0 0 16 16" width={size} height={size}>
<g transform="matrix(0.0364583,0,0,0.0364583,1,-0.166667)">
<path
- fill="#fff"
+ fill="currentColor"
d="M224,344L224,296C224,293.667 223.25,291.75 221.75,290.25C220.25,288.75 218.333,288 216,288L168,288C165.667,288 163.75,288.75 162.25,290.25C160.75,291.75 160,293.667 160,296L160,344C160,346.333 160.75,348.25 162.25,349.75C163.75,351.25 165.667,352 168,352L216,352C218.333,352 220.25,351.25 221.75,349.75C223.25,348.25 224,346.333 224,344ZM288,176C288,161.333 283.375,147.75 274.125,135.25C264.875,122.75 253.333,113.083 239.5,106.25C225.667,99.417 211.5,96 197,96C156.5,96 125.583,113.75 104.25,149.25C101.75,153.25 102.417,156.75 106.25,159.75L139.25,184.75C140.417,185.75 142,186.25 144,186.25C146.667,186.25 148.75,185.25 150.25,183.25C159.083,171.917 166.25,164.25 171.75,160.25C177.417,156.25 184.583,154.25 193.25,154.25C201.25,154.25 208.375,156.417 214.625,160.75C220.875,165.083 224,170 224,175.5C224,181.833 222.333,186.917 219,190.75C215.667,194.583 210,198.333 202,202C191.5,206.667 181.875,213.875 173.125,223.625C164.375,233.375 160,243.833 160,255L160,264C160,266.333 160.75,268.25 162.25,269.75C163.75,271.25 165.667,272 168,272L216,272C218.333,272 220.25,271.25 221.75,269.75C223.25,268.25 224,266.333 224,264C224,260.833 225.792,256.708 229.375,251.625C232.958,246.542 237.5,242.417 243,239.25C248.333,236.25 252.417,233.875 255.25,232.125C258.083,230.375 261.917,227.458 266.75,223.375C271.583,219.292 275.292,215.292 277.875,211.375C280.458,207.458 282.792,202.417 284.875,196.25C286.958,190.083 288,183.333 288,176ZM384,224C384,258.833 375.417,290.958 358.25,320.375C341.083,349.792 317.792,373.083 288.375,390.25C258.958,407.417 226.833,416 192,416C157.167,416 125.042,407.417 95.625,390.25C66.208,373.083 42.917,349.792 25.75,320.375C8.583,290.958 0,258.833 0,224C0,189.167 8.583,157.042 25.75,127.625C42.917,98.208 66.208,74.917 95.625,57.75C125.042,40.583 157.167,32 192,32C226.833,32 258.958,40.583 288.375,57.75C317.792,74.917 341.083,98.208 358.25,127.625C375.417,157.042 384,189.167 384,224Z"
/>
</g>
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 2cb9c8049de..160fc777250 100644
--- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties
+++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
@@ -2904,6 +2904,17 @@ component_measures.to_navigate_back=to navigate back
component_measures.overview.project_overview.facet=Project Overview
component_measures.overview.project_overview.title=Risk
+component_measures.overview.project_overview.description=Get quick insights into the operational risks. Any color but green indicates immediate risks: Bugs or Vulnerabilities that should be examined. A position at the top or right of the graph means that the longer-term health may be at risk. Green bubbles at the bottom-left are best.
+component_measures.overview.Reliability.description=See bugs' operational risks. The closer a bubble's color is to red, the more severe the worse bugs are. Bubble size indicates bug volume, and each bubble's vertical position reflects the estimated time to address the bugs. Small green bubbles on the bottom edge are best.
+component_measures.overview.Security.description=See vulnerabilities' operational risks. The closer a bubble's color is to red, the more severe the worst vulnerabilities are. Bubble size indicates vulnerability volume, and each bubble's vertical position reflects the estimated time to address the vulnerabilities. Small green bubbles on the bottom edge are best.
+component_measures.overview.Maintainability.description=See code smells' long-term risks. The closer a bubble's color is to red, the higher the ratio of technical debt is. Bubble size indicates code smell volume, and each bubble's vertical position reflects the estimated time to address the code smells. Small green bubbles on the bottom edge are best.
+component_measures.overview.Coverage.description=See missing test coverage's long-term risks. Bubble size indicates the volume of uncovered lines, and each bubble's vertical position reflects the volume of missing coverage. Small bubbles on the bottom edge are best.
+component_measures.overview.Duplications.description=See duplications' long-term risks. Bubble size indicates the volume of duplicated blocks, and each bubble's vertical position reflects the volume of lines in those blocks. Small bubbles on the bottom edge are best.
+
+component_measures.domain_facets.Reliability.help=Issues in this domain mark code where you will get behavior other than what was expected.
+component_measures.domain_facets.Maintainability.help=Issues in this domain mark code that will be more difficult to update competently than it should.
+component_measures.domain_facets.Security.help=Issues in this domain mark potential weaknesses to hackers.
+component_measures.domain_facets.Complexity.help=How simple or complicated the control flow of the application is. Cyclomatic Complexity measures the minimum number of test cases requiref for full test coverage. Cognitive Complexity is a measure of how difficult the application is to Understand
#------------------------------------------------------------------------------
#