aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorStas Vilchik <vilchiks@gmail.com>2016-03-08 14:47:18 +0100
committerStas Vilchik <vilchiks@gmail.com>2016-03-09 14:12:33 +0100
commit89de9611b4b455a58ca22170fc46c38350816e87 (patch)
treea30b5c10e018a2a52848cc689791cc70ebbaec5c /server
parent8549b6143656ddd868948584ffd99c021805d9a4 (diff)
downloadsonarqube-89de9611b4b455a58ca22170fc46c38350816e87.tar.gz
sonarqube-89de9611b4b455a58ca22170fc46c38350816e87.zip
SONAR-7410 Display related measures alongside with selected one on the "Measures" page
Diffstat (limited to 'server')
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/components/LanguageDistribution.js71
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/components/MeasureDetails.js27
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/components/MeasureDetailsHeader.js22
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/styles.css12
-rw-r--r--server/sonar-web/src/main/less/components/graphics.less24
-rw-r--r--server/sonar-web/src/main/less/pages/overview.less18
6 files changed, 148 insertions, 26 deletions
diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/LanguageDistribution.js b/server/sonar-web/src/main/js/apps/component-measures/components/LanguageDistribution.js
new file mode 100644
index 00000000000..ea0e9db68ba
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/component-measures/components/LanguageDistribution.js
@@ -0,0 +1,71 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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 _ from 'underscore';
+import React from 'react';
+
+import { Histogram } from '../../../components/charts/histogram';
+import { formatMeasure } from '../../../helpers/measures';
+import { getLanguages } from '../../../api/languages';
+import { translate } from '../../../helpers/l10n';
+
+
+export default class LanguageDistribution extends React.Component {
+ componentDidMount () {
+ this.requestLanguages();
+ }
+
+ requestLanguages () {
+ getLanguages().then(languages => this.setState({ languages }));
+ }
+
+ getLanguageName (langKey) {
+ if (this.state && this.state.languages) {
+ const lang = _.findWhere(this.state.languages, { key: langKey });
+ return lang ? lang.name : translate('unknown');
+ } else {
+ return langKey;
+ }
+ }
+
+ cutLanguageName (name) {
+ return name.length > 10 ? `${name.substr(0, 7)}...` : name;
+ }
+
+ render () {
+ let data = this.props.distribution.split(';').map((point, index) => {
+ const tokens = point.split('=');
+ return { x: parseInt(tokens[1], 10), y: index, value: tokens[0] };
+ });
+
+ data = _.sortBy(data, d => -d.x);
+
+ const yTicks = data.map(point => this.getLanguageName(point.value)).map(this.cutLanguageName);
+ const yValues = data.map(point => formatMeasure(point.x, 'SHORT_INT'));
+
+ return (
+ <Histogram data={data}
+ yTicks={yTicks}
+ yValues={yValues}
+ barsWidth={10}
+ height={data.length * 25}
+ padding={[0, 60, 0, 80]}/>
+ );
+ }
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureDetails.js b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureDetails.js
index fa15d267c52..2ffc441f163 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureDetails.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureDetails.js
@@ -65,19 +65,33 @@ export default class MeasureDetails extends React.Component {
fetchMeasure () {
const { metricKey } = this.props.params;
const { component } = this.context;
+ const metrics = [metricKey];
+
+ if (metricKey === 'ncloc') {
+ metrics.push('ncloc_language_distribution');
+ }
+
+ if (metricKey === 'function_complexity') {
+ metrics.push('function_complexity_distribution');
+ }
+
+ if (metricKey === 'file_complexity') {
+ metrics.push('file_complexity_distribution');
+ }
getMeasuresAndMeta(
component.key,
- [metricKey],
+ metrics,
{ additionalFields: 'periods' }
).then(r => {
- const measures = r.component.measures;
-
- if (this.mounted && measures.length === 1) {
- const measure = enhanceWithLeak(measures[0]);
+ if (this.mounted) {
+ const measures = enhanceWithLeak(r.component.measures);
+ const measure = measures.find(measure => measure.metric === metricKey);
+ const secondaryMeasure = measures.find(measure => measure.metric !== metricKey);
this.setState({
measure,
+ secondaryMeasure,
periods: r.periods
});
}
@@ -85,7 +99,7 @@ export default class MeasureDetails extends React.Component {
}
render () {
- const { measure, periods } = this.state;
+ const { measure, secondaryMeasure, periods } = this.state;
if (!measure) {
return <Spinner/>;
@@ -101,6 +115,7 @@ export default class MeasureDetails extends React.Component {
<MeasureDetailsHeader
measure={measure}
metric={this.metric}
+ secondaryMeasure={secondaryMeasure}
leakPeriodLabel={leakPeriodLabel}/>
{measure && (
diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureDetailsHeader.js b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureDetailsHeader.js
index 93d0e8b58f3..737074afe9a 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureDetailsHeader.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureDetailsHeader.js
@@ -19,12 +19,14 @@
*/
import React from 'react';
+import LanguageDistribution from './LanguageDistribution';
+import { ComplexityDistribution } from '../../overview/components/complexity-distribution';
import { formatLeak } from '../utils';
import { formatMeasure } from '../../../helpers/measures';
import { translateWithParameters } from '../../../helpers/l10n';
import { TooltipsContainer } from '../../../components/mixins/tooltips-mixin';
-export default function MeasureDetailsHeader ({ measure, metric, leakPeriodLabel }) {
+export default function MeasureDetailsHeader ({ measure, metric, secondaryMeasure, leakPeriodLabel }) {
const leakPeriodTooltip = translateWithParameters('overview.leak_period_x', leakPeriodLabel);
return (
@@ -49,6 +51,24 @@ export default function MeasureDetailsHeader ({ measure, metric, leakPeriodLabel
{formatLeak(measure.leak, metric)}
</div>
)}
+
+ {secondaryMeasure && secondaryMeasure.metric === 'ncloc_language_distribution' && (
+ <div className="measure-details-secondary">
+ <LanguageDistribution distribution={secondaryMeasure.value}/>
+ </div>
+ )}
+
+ {secondaryMeasure && secondaryMeasure.metric === 'function_complexity_distribution' && (
+ <div className="measure-details-secondary">
+ <ComplexityDistribution distribution={secondaryMeasure.value} of="function"/>
+ </div>
+ )}
+
+ {secondaryMeasure && secondaryMeasure.metric === 'file_complexity_distribution' && (
+ <div className="measure-details-secondary">
+ <ComplexityDistribution distribution={secondaryMeasure.value} of="file"/>
+ </div>
+ )}
</div>
</TooltipsContainer>
</header>
diff --git a/server/sonar-web/src/main/js/apps/component-measures/styles.css b/server/sonar-web/src/main/js/apps/component-measures/styles.css
index e09866b9c43..185c82761c7 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/styles.css
+++ b/server/sonar-web/src/main/js/apps/component-measures/styles.css
@@ -73,25 +73,35 @@
.measure-details-value {
font-size: 24px;
- font-weight: 300;
}
.measure-details-value-absolute {
display: inline-block;
+ vertical-align: middle;
padding: 5px 0;
+ font-weight: 300;
}
.measure-details-value-leak {
display: inline-block;
+ vertical-align: middle;
padding: 4px 10px;
border: 1px solid #eae3c7;
background-color: #fbf3d5;
+ font-weight: 300;
}
.measure-details-value-absolute + .measure-details-value-leak {
margin-left: 20px;
}
+.measure-details-secondary {
+ display: inline-block;
+ vertical-align: middle;
+ width: 260px;
+ margin-left: 20px;
+}
+
.measure-details-drilldown {
margin-top: 20px;
}
diff --git a/server/sonar-web/src/main/less/components/graphics.less b/server/sonar-web/src/main/less/components/graphics.less
index dbe699f6ff0..b78984ad29c 100644
--- a/server/sonar-web/src/main/less/components/graphics.less
+++ b/server/sonar-web/src/main/less/components/graphics.less
@@ -338,3 +338,27 @@ text.max-results-reached-message {
.bubble-chart-tick-y {
text-anchor: end;
}
+
+/*
+ * Bar Chart
+ */
+.bar-chart {
+}
+
+.bar-chart-bar {
+ fill: @blue;
+}
+
+.bar-chart-tick {
+ fill: @secondFontColor;
+ font-size: 12px;
+ text-anchor: middle;
+}
+
+.histogram-tick {
+ text-anchor: end;
+}
+
+.histogram-value {
+ text-anchor: start;
+}
diff --git a/server/sonar-web/src/main/less/pages/overview.less b/server/sonar-web/src/main/less/pages/overview.less
index e11b40a93c3..b7c14709f08 100644
--- a/server/sonar-web/src/main/less/pages/overview.less
+++ b/server/sonar-web/src/main/less/pages/overview.less
@@ -422,24 +422,6 @@
svg {
position: absolute;
}
-
- .bar-chart-bar {
- fill: @blue;
- }
-
- .bar-chart-tick {
- fill: @secondFontColor;
- font-size: 12px;
- text-anchor: middle;
- }
-
- .histogram-tick {
- text-anchor: end;
- }
-
- .histogram-value {
- text-anchor: start;
- }
}
.overview-timeline {