aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src
diff options
context:
space:
mode:
authorPascal Mugnier <pascal.mugnier@sonarsource.com>2018-04-20 07:38:14 +0200
committerSonarTech <sonartech@sonarsource.com>2018-04-24 20:20:46 +0200
commita7d7420a719ee56590e5c09d70bfd1a75a14abdf (patch)
tree8eb9897166acdaeeb4f3ce4555be3aceb8769593 /server/sonar-web/src
parentc3d089474c621b449d10f5576bff671541cd626d (diff)
downloadsonarqube-a7d7420a719ee56590e5c09d70bfd1a75a14abdf.tar.gz
sonarqube-a7d7420a719ee56590e5c09d70bfd1a75a14abdf.zip
SONAR-9472 Change the rendering of best values on the Measures page
Diffstat (limited to 'server/sonar-web/src')
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/components/MeasureContent.js5
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentsList.js152
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/drilldown/FilesView.js2
-rw-r--r--server/sonar-web/src/main/js/helpers/measures.ts10
-rw-r--r--server/sonar-web/src/main/js/store/metrics/actions.js1
5 files changed, 122 insertions, 48 deletions
diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureContent.js b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureContent.js
index a4847ed1848..a7cd534be4c 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureContent.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureContent.js
@@ -62,6 +62,7 @@ import { isSameBranchLike, getBranchLikeQuery } from '../../../helpers/branches'
|}; */
/*:: type State = {
+ bestValue?: string,
components: Array<ComponentEnhanced>,
metric: ?Metric,
paging?: Paging,
@@ -117,6 +118,7 @@ export default class MeasureContent extends React.PureComponent {
const metricKeys = [metric.key];
const opts /*: Object */ = {
...getBranchLikeQuery(this.props.branchLike),
+ additionalFields: 'metrics',
metricSortFilter: 'withMeasuresOnly'
};
const isDiff = isDiffMetric(metric.key);
@@ -151,6 +153,7 @@ export default class MeasureContent extends React.PureComponent {
if (metric === this.props.metric) {
if (this.mounted) {
this.setState(({ selected } /*: State */) => ({
+ bestValue: r.metrics[0].bestValue,
components: r.components.map(component =>
enhanceComponent(component, metric, metrics)
),
@@ -185,6 +188,7 @@ export default class MeasureContent extends React.PureComponent {
if (metric === this.props.metric) {
if (this.mounted) {
this.setState(state => ({
+ bestValue: r.metrics[0].bestValue,
components: [
...state.components,
...r.components.map(component => enhanceComponent(component, metric, metrics))
@@ -245,6 +249,7 @@ export default class MeasureContent extends React.PureComponent {
const selectedIdx = this.getSelectedIndex();
return (
<FilesView
+ bestValue={this.state.bestValue}
branchLike={this.props.branchLike}
components={this.state.components}
fetchMore={this.fetchMoreComponents}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentsList.js b/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentsList.js
index cfc0aa28aa2..fbd26322b63 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentsList.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentsList.js
@@ -22,11 +22,13 @@ import React from 'react';
import ComponentsListRow from './ComponentsListRow';
import EmptyResult from './EmptyResult';
import { complementary } from '../config/complementary';
-import { getLocalizedMetricName } from '../../../helpers/l10n';
+import { getLocalizedMetricName, translate, translateWithParameters } from '../../../helpers/l10n';
+import { formatMeasure, isDiffMetric, isPeriodBestValue } from '../../../helpers/measures';
/*:: import type { Component, ComponentEnhanced } from '../types'; */
/*:: import type { Metric } from '../../../store/metrics/actions'; */
/*:: type Props = {|
+ bestValue?: string,
branchLike?: { id?: string; name: string },
components: Array<ComponentEnhanced>,
onClick: string => void,
@@ -36,54 +38,108 @@ import { getLocalizedMetricName } from '../../../helpers/l10n';
selectedComponent?: ?string
|}; */
-export default function ComponentsList(
- {
- branchLike,
- components,
- onClick,
- metrics,
- metric,
- rootComponent,
- selectedComponent
- } /*: Props */
-) {
- if (!components.length) {
- return <EmptyResult />;
+/*:: type State = {
+ hideBest: boolean
+}; */
+
+export default class ComponentsList extends React.PureComponent {
+ /*:: props: Props; */
+ state /*: State */ = {
+ hideBest: true
+ };
+
+ componentWillReceiveProps(nextProps /*: Props */) {
+ if (nextProps.metric !== this.props.metric) {
+ this.setState({ hideBest: true });
+ }
+ }
+
+ displayAll = (event /*: Event */) => {
+ event.preventDefault();
+ this.setState({ hideBest: false });
+ };
+
+ hasBestValue(component /*: Component*/, otherMetrics /*: Array<Metric> */) {
+ const { metric } = this.props;
+ const focusedMeasure = component.measures.find(measure => measure.metric.key === metric.key);
+ if (isDiffMetric(focusedMeasure.metric.key)) {
+ return isPeriodBestValue(focusedMeasure, 1);
+ }
+ return focusedMeasure.bestValue;
}
- const otherMetrics = (complementary[metric.key] || []).map(key => metrics[key]);
- return (
- <table className="data zebra zebra-hover">
- {otherMetrics.length > 0 && (
- <thead>
- <tr>
- <th>&nbsp;</th>
- <th className="text-right">
- <span className="small">{getLocalizedMetricName(metric)}</span>
- </th>
- {otherMetrics.map(metric => (
- <th className="text-right" key={metric.key}>
- <span className="small">{getLocalizedMetricName(metric)}</span>
- </th>
- ))}
- </tr>
- </thead>
- )}
+ renderComponent(component /*: Component*/, otherMetrics /*: Array<Metric> */) {
+ const { branchLike, metric, selectedComponent, onClick, rootComponent } = this.props;
+ return (
+ <ComponentsListRow
+ branchLike={branchLike}
+ component={component}
+ isSelected={component.key === selectedComponent}
+ key={component.id}
+ metric={metric}
+ onClick={onClick}
+ otherMetrics={otherMetrics}
+ rootComponent={rootComponent}
+ />
+ );
+ }
- <tbody>
- {components.map(component => (
- <ComponentsListRow
- branchLike={branchLike}
- component={component}
- isSelected={component.key === selectedComponent}
- key={component.id}
- metric={metric}
- onClick={onClick}
- otherMetrics={otherMetrics}
- rootComponent={rootComponent}
- />
- ))}
- </tbody>
- </table>
- );
+ renderHiddenLink(hiddenCount /*: number*/, colCount /*: number*/) {
+ return (
+ <div className="alert alert-info spacer-top">
+ {translateWithParameters(
+ 'component_measures.hidden_best_score_metrics',
+ hiddenCount,
+ formatMeasure(this.props.bestValue, this.props.metric.type)
+ )}
+ <a className="spacer-left" href="#" onClick={this.displayAll}>
+ {translate('show_all')}
+ </a>
+ </div>
+ );
+ }
+
+ render() {
+ const { components, metric, metrics } = this.props;
+ if (!components.length) {
+ return <EmptyResult />;
+ }
+
+ const otherMetrics = (complementary[metric.key] || []).map(key => metrics[key]);
+ const notBestComponents = components.filter(
+ component => !this.hasBestValue(component, otherMetrics)
+ );
+ const hiddenCount = components.length - notBestComponents.length;
+ const shouldHideBest = this.state.hideBest && hiddenCount !== components.length;
+ return (
+ <React.Fragment>
+ <table className="data zebra zebra-hover">
+ {otherMetrics.length > 0 && (
+ <thead>
+ <tr>
+ <th>&nbsp;</th>
+ <th className="text-right">
+ <span className="small">{getLocalizedMetricName(metric)}</span>
+ </th>
+ {otherMetrics.map(metric => (
+ <th className="text-right" key={metric.key}>
+ <span className="small">{getLocalizedMetricName(metric)}</span>
+ </th>
+ ))}
+ </tr>
+ </thead>
+ )}
+
+ <tbody>
+ {(shouldHideBest ? notBestComponents : components).map(component =>
+ this.renderComponent(component, otherMetrics)
+ )}
+ </tbody>
+ </table>
+ {shouldHideBest &&
+ hiddenCount > 0 &&
+ this.renderHiddenLink(hiddenCount, otherMetrics.length + 3)}
+ </React.Fragment>
+ );
+ }
}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/FilesView.js b/server/sonar-web/src/main/js/apps/component-measures/drilldown/FilesView.js
index 4c1fbb8ce08..93f464ef47b 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/drilldown/FilesView.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/drilldown/FilesView.js
@@ -28,6 +28,7 @@ import { scrollToElement } from '../../../helpers/scrolling';
/*:: import type { Metric } from '../../../store/metrics/actions'; */
/*:: type Props = {|
+ bestValue?: string,
branchLike?: { id?: string; name: string },
components: Array<ComponentEnhanced>,
fetchMore: () => void,
@@ -124,6 +125,7 @@ export default class ListView extends React.PureComponent {
return (
<div ref={elem => (this.listContainer = elem)}>
<ComponentsList
+ bestValue={this.props.bestValue}
branchLike={this.props.branchLike}
components={this.props.components}
metric={this.props.metric}
diff --git a/server/sonar-web/src/main/js/helpers/measures.ts b/server/sonar-web/src/main/js/helpers/measures.ts
index 928fc79a103..596ea2a3685 100644
--- a/server/sonar-web/src/main/js/helpers/measures.ts
+++ b/server/sonar-web/src/main/js/helpers/measures.ts
@@ -25,6 +25,7 @@ const HOURS_IN_DAY = 8;
export interface MeasurePeriod {
index: number;
value: string;
+ bestValue?: boolean;
}
export interface MeasureIntern {
@@ -90,6 +91,15 @@ export function getPeriodValue(
return period ? period.value : undefined;
}
+export function isPeriodBestValue(
+ measure: Measure | MeasureEnhanced,
+ periodIndex: number
+): boolean {
+ const { periods } = measure;
+ const period = periods && periods.find(period => period.index === periodIndex);
+ return (period && period.bestValue) || false;
+}
+
/** Check if metric is differential */
export function isDiffMetric(metricKey: string): boolean {
return metricKey.indexOf('new_') === 0;
diff --git a/server/sonar-web/src/main/js/store/metrics/actions.js b/server/sonar-web/src/main/js/store/metrics/actions.js
index 31f4cc198e7..a271928ce3b 100644
--- a/server/sonar-web/src/main/js/store/metrics/actions.js
+++ b/server/sonar-web/src/main/js/store/metrics/actions.js
@@ -19,6 +19,7 @@
*/
// @flow
/*:: export type Metric = {
+ bestValue?: string,
custom?: boolean,
decimalScale?: number,
description?: string,