diff options
author | Pascal Mugnier <pascal.mugnier@sonarsource.com> | 2018-04-20 07:38:14 +0200 |
---|---|---|
committer | SonarTech <sonartech@sonarsource.com> | 2018-04-24 20:20:46 +0200 |
commit | a7d7420a719ee56590e5c09d70bfd1a75a14abdf (patch) | |
tree | 8eb9897166acdaeeb4f3ce4555be3aceb8769593 /server/sonar-web/src | |
parent | c3d089474c621b449d10f5576bff671541cd626d (diff) | |
download | sonarqube-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')
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> </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> </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, |