]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-11719 Update measures page for Prs anad SLBs
authorWouter Admiraal <wouter.admiraal@sonarsource.com>
Tue, 12 Feb 2019 10:08:52 +0000 (11:08 +0100)
committerSonarTech <sonartech@sonarsource.com>
Mon, 11 Mar 2019 19:21:03 +0000 (20:21 +0100)
13 files changed:
server/sonar-web/src/main/js/apps/component-measures/components/App.tsx
server/sonar-web/src/main/js/apps/component-measures/components/MeasureHeader.tsx
server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverview.tsx
server/sonar-web/src/main/js/apps/component-measures/sidebar/DomainFacet.tsx
server/sonar-web/src/main/js/apps/component-measures/sidebar/FacetMeasureValue.tsx
server/sonar-web/src/main/js/apps/component-measures/sidebar/Sidebar.tsx
server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/DomainFacet-test.tsx
server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/FacetMeasureValue-test.tsx
server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/Sidebar-test.tsx
server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/DomainFacet-test.tsx.snap
server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/FacetMeasureValue-test.tsx.snap
server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/Sidebar-test.tsx.snap
server/sonar-web/src/main/js/apps/component-measures/utils.ts

index 551d4d9f80d6c4d7fbead001970e74e24d3c0a3c..0603e1a269bd65ec8ed97c7bcf7880bd6b510792 100644 (file)
@@ -285,8 +285,8 @@ export class App extends React.PureComponent<Props, State> {
     const { branchLike } = this.props;
     const { measures } = this.state;
     const query = parseQuery(this.props.location.query);
-    const hasOverview = hasFullMeasures(branchLike);
-    const displayOverview = hasOverview && hasBubbleChart(query.metric);
+    const showFullMeasures = hasFullMeasures(branchLike);
+    const displayOverview = hasBubbleChart(query.metric);
     const metric = this.getSelectedMetric(query, displayOverview);
 
     return (
@@ -302,9 +302,9 @@ export class App extends React.PureComponent<Props, State> {
                   <div className="layout-page-side-inner">
                     <div className="layout-page-filters">
                       <Sidebar
-                        hasOverview={hasOverview}
                         measures={measures}
                         selectedMetric={metric ? metric.key : query.metric}
+                        showFullMeasures={showFullMeasures}
                         updateQuery={this.updateQuery}
                       />
                     </div>
index 842c72ff5b89eb533e6656418cfc4b6b6bfb7c20..5b9929b9447e23bd883acbacee214a7e828ea668 100644 (file)
@@ -54,7 +54,7 @@ export default function MeasureHeader(props: Props) {
           <span className="measure-details-value spacer-left">
             <strong>
               <Measure
-                className={isDiff ? 'leak-box' : undefined}
+                className={isDiff && displayLeak ? 'leak-box' : undefined}
                 metricKey={metric.key}
                 metricType={metric.type}
                 value={measureValue}
index 2e9f409257d46e21d504433220c9281b4b5dcf13..e20de1491591223638b3b3502624fa67cf10537e 100644 (file)
@@ -23,11 +23,11 @@ import LeakPeriodLegend from './LeakPeriodLegend';
 import MeasureContentHeader from './MeasureContentHeader';
 import PageActions from '../../../components/ui/PageActions';
 import BubbleChart from '../drilldown/BubbleChart';
+import DeferredSpinner from '../../../components/common/DeferredSpinner';
 import SourceViewer from '../../../components/SourceViewer/SourceViewer';
 import { getComponentLeaves } from '../../../api/components';
-import { enhanceComponent, getBubbleMetrics, isFileType } from '../utils';
+import { enhanceComponent, getBubbleMetrics, isFileType, hasFullMeasures } from '../utils';
 import { getBranchLikeQuery, isSameBranchLike } from '../../../helpers/branches';
-import DeferredSpinner from '../../../components/common/DeferredSpinner';
 
 interface Props {
   branchLike?: T.BranchLike;
@@ -135,6 +135,7 @@ export default class MeasureOverview extends React.PureComponent<Props, State> {
   render() {
     const { branchLike, component, leakPeriod, rootComponent } = this.props;
     const { paging } = this.state;
+    const displayLeak = hasFullMeasures(branchLike);
     return (
       <div className={this.props.className}>
         <div className="layout-page-header-panel layout-page-main-header">
@@ -163,9 +164,14 @@ export default class MeasureOverview extends React.PureComponent<Props, State> {
         </div>
         <div className="layout-page-main-inner measure-details-content">
           <div className="clearfix big-spacer-bottom">
-            {leakPeriod && (
-              <LeakPeriodLegend className="pull-right" component={component} period={leakPeriod} />
-            )}
+            {leakPeriod &&
+              displayLeak && (
+                <LeakPeriodLegend
+                  className="pull-right"
+                  component={component}
+                  period={leakPeriod}
+                />
+              )}
           </div>
           <DeferredSpinner loading={this.props.loading} />
           {!this.props.loading && this.renderContent()}
index c81765cde2fc696b1aa4e69b8f22fb9a65c74438..3574939f9425328e6e4e3052da8bfdd01110cc3b 100644 (file)
@@ -41,11 +41,11 @@ import {
 
 interface Props {
   domain: { name: string; measures: T.MeasureEnhanced[] };
-  hasOverview: boolean;
   onChange: (metric: string) => void;
   onToggle: (property: string) => void;
   open: boolean;
   selected: string;
+  showFullMeasures: boolean;
 }
 
 export default class DomainFacet extends React.PureComponent<Props> {
@@ -74,11 +74,21 @@ export default class DomainFacet extends React.PureComponent<Props> {
   };
 
   hasOverview = (domain: string) => {
-    return this.props.hasOverview && hasBubbleChart(domain);
+    return this.props.showFullMeasures && hasBubbleChart(domain);
   };
 
   renderItemFacetStat = (item: T.MeasureEnhanced) => {
-    return hasFacetStat(item.metric.key) ? <FacetMeasureValue measure={item} /> : null;
+    return hasFacetStat(item.metric.key) ? (
+      <FacetMeasureValue displayLeak={this.props.showFullMeasures} measure={item} />
+    ) : null;
+  };
+
+  renderCategoryItem = (item: string) => {
+    return this.props.showFullMeasures || item === 'new_code_category' ? (
+      <span className="facet search-navigator-facet facet-category" key={item}>
+        <span className="facet-name">{translate('component_measures.facet_category', item)}</span>
+      </span>
+    ) : null;
   };
 
   renderItemsFacet = () => {
@@ -98,13 +108,7 @@ export default class DomainFacet extends React.PureComponent<Props> {
     return sortedItems.map(
       item =>
         typeof item === 'string' ? (
-          <span className="facet search-navigator-facet facet-category" key={item}>
-            <span className="facet-name">
-              {!this.props.hasOverview && item === 'overall_category'
-                ? translate('component_measures.facet_category', item, 'estimated')
-                : translate('component_measures.facet_category', item)}
-            </span>
-          </span>
+          this.renderCategoryItem(item)
         ) : (
           <FacetItem
             active={item.metric.key === selected}
index 2547e7f8f2497434c3b7bd83f77a124ff3528275..1d370f3dd723075793567846c58234f3522b9af3 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
+import * as classNames from 'classnames';
 import Measure from '../../../components/measure/Measure';
 import { isDiffMetric } from '../../../helpers/measures';
 
 interface Props {
+  displayLeak?: boolean;
   measure: T.MeasureEnhanced;
 }
 
-export default function FacetMeasureValue({ measure }: Props) {
+export default function FacetMeasureValue({ measure, displayLeak }: Props) {
   if (isDiffMetric(measure.metric.key)) {
     return (
-      <div className="domain-measures-value leak-box" id={`measure-${measure.metric.key}-leak`}>
+      <div
+        className={classNames('domain-measures-value', { 'leak-box': displayLeak })}
+        id={`measure-${measure.metric.key}-leak`}>
         <Measure
           metricKey={measure.metric.key}
           metricType={measure.metric.type}
index c6a3e599d7063bca755b64e11424312369efacc5..e227db24ec93486aafc67f8d28202fd1c1dd9775 100644 (file)
@@ -23,9 +23,9 @@ import DomainFacet from './DomainFacet';
 import { groupByDomains, KNOWN_DOMAINS, PROJECT_OVERVEW, Query } from '../utils';
 
 interface Props {
-  hasOverview: boolean;
   measures: T.MeasureEnhanced[];
   selectedMetric: string;
+  showFullMeasures: boolean;
   updateQuery: (query: Partial<Query>) => void;
 }
 
@@ -53,25 +53,23 @@ export default class Sidebar extends React.PureComponent<Props, State> {
   };
 
   render() {
-    const { hasOverview } = this.props;
+    const { showFullMeasures } = this.props;
     return (
       <div>
-        {hasOverview && (
-          <ProjectOverviewFacet
-            onChange={this.changeMetric}
-            selected={this.props.selectedMetric}
-            value={PROJECT_OVERVEW}
-          />
-        )}
+        <ProjectOverviewFacet
+          onChange={this.changeMetric}
+          selected={this.props.selectedMetric}
+          value={PROJECT_OVERVEW}
+        />
         {groupByDomains(this.props.measures).map(domain => (
           <DomainFacet
             domain={domain}
-            hasOverview={hasOverview}
             key={domain.name}
             onChange={this.changeMetric}
             onToggle={this.toggleFacet}
             open={this.state.openFacets[domain.name] === true}
             selected={this.props.selectedMetric}
+            showFullMeasures={showFullMeasures}
           />
         ))}
       </div>
index a570fda9252c24e730c60c3f959f54a8e694c9af..9aa6e8655dc37485bab2b5d1d0d324d859880fd9 100644 (file)
@@ -21,59 +21,21 @@ import * as React from 'react';
 import { shallow } from 'enzyme';
 import DomainFacet from '../DomainFacet';
 
-const DOMAIN = {
-  name: 'Reliability',
-  measures: [
-    {
-      metric: {
-        id: '1',
-        key: 'bugs',
-        type: 'INT',
-        name: 'Bugs',
-        domain: 'Reliability'
-      },
-      value: '5',
-      periods: [{ index: 1, value: '5' }],
-      leak: '5'
-    },
-    {
-      metric: {
-        id: '2',
-        key: 'new_bugs',
-        type: 'INT',
-        name: 'New Bugs',
-        domain: 'Reliability'
-      },
-      periods: [{ index: 1, value: '5' }],
-      leak: '5'
-    }
-  ]
-};
-
-const PROPS = {
-  domain: DOMAIN,
-  hasOverview: true,
-  onChange: () => {},
-  onToggle: () => {},
-  open: true,
-  selected: 'foo'
-};
-
 it('should display facet item list', () => {
-  expect(shallow(<DomainFacet {...PROPS} />)).toMatchSnapshot();
+  expect(shallowRender()).toMatchSnapshot();
 });
 
 it('should display facet item list with bugs selected', () => {
-  expect(shallow(<DomainFacet {...PROPS} selected="bugs" />)).toMatchSnapshot();
+  expect(shallowRender({ selected: 'bugs' })).toMatchSnapshot();
 });
 
 it('should render closed', () => {
-  const wrapper = shallow(<DomainFacet {...PROPS} open={false} />);
+  const wrapper = shallowRender({ open: false });
   expect(wrapper.find('FacetItemsList')).toHaveLength(0);
 });
 
 it('should render without overview', () => {
-  const wrapper = shallow(<DomainFacet {...PROPS} hasOverview={false} />);
+  const wrapper = shallowRender({ showFullMeasures: false });
   expect(
     wrapper
       .find('FacetItem')
@@ -82,11 +44,6 @@ it('should render without overview', () => {
   ).toBe(false);
 });
 
-it('should use "estimated" label for overall measures ', () => {
-  const wrapper = shallow(<DomainFacet {...PROPS} hasOverview={false} />);
-  expect(wrapper.find('.facet-name').map(w => w.text())).toMatchSnapshot();
-});
-
 it('should not display subtitles of new measures if there is none', () => {
   const domain = {
     name: 'Reliability',
@@ -98,7 +55,7 @@ it('should not display subtitles of new measures if there is none', () => {
     ]
   };
 
-  expect(shallow(<DomainFacet {...PROPS} domain={domain} />)).toMatchSnapshot();
+  expect(shallowRender({ domain })).toMatchSnapshot();
 });
 
 it('should not display subtitles of new measures if there is none, even on last line', () => {
@@ -112,5 +69,46 @@ it('should not display subtitles of new measures if there is none, even on last
     ]
   };
 
-  expect(shallow(<DomainFacet {...PROPS} domain={domain} />)).toMatchSnapshot();
+  expect(shallowRender({ domain })).toMatchSnapshot();
 });
+
+function shallowRender(props: Partial<DomainFacet['props']> = {}) {
+  return shallow(
+    <DomainFacet
+      domain={{
+        name: 'Reliability',
+        measures: [
+          {
+            metric: {
+              id: '1',
+              key: 'bugs',
+              type: 'INT',
+              name: 'Bugs',
+              domain: 'Reliability'
+            },
+            value: '5',
+            periods: [{ index: 1, value: '5' }],
+            leak: '5'
+          },
+          {
+            metric: {
+              id: '2',
+              key: 'new_bugs',
+              type: 'INT',
+              name: 'New Bugs',
+              domain: 'Reliability'
+            },
+            periods: [{ index: 1, value: '5' }],
+            leak: '5'
+          }
+        ]
+      }}
+      onChange={() => {}}
+      onToggle={() => {}}
+      open={true}
+      selected={'foo'}
+      showFullMeasures={true}
+      {...props}
+    />
+  );
+}
index dabd5a35884ff6d2f80b9cda1b35a85a22132c38..48fdd522edb6fed3969c8330f623128f243c44e9 100644 (file)
@@ -46,9 +46,14 @@ const LEAK_MEASURE = {
 };
 
 it('should display measure value', () => {
-  expect(shallow(<FacetMeasureValue measure={MEASURE} />)).toMatchSnapshot();
+  expect(shallow(<FacetMeasureValue displayLeak={true} measure={MEASURE} />)).toMatchSnapshot();
 });
 
 it('should display leak measure value', () => {
-  expect(shallow(<FacetMeasureValue measure={LEAK_MEASURE} />)).toMatchSnapshot();
+  expect(
+    shallow(<FacetMeasureValue displayLeak={true} measure={LEAK_MEASURE} />)
+  ).toMatchSnapshot();
+  expect(
+    shallow(<FacetMeasureValue displayLeak={false} measure={LEAK_MEASURE} />)
+  ).toMatchSnapshot();
 });
index a47cd75fe496a146a7c6f176a4e91c32b78533fb..aee555edc2ab30598a908294ce3740bbb2c942dc 100644 (file)
@@ -21,61 +21,64 @@ import * as React from 'react';
 import { shallow } from 'enzyme';
 import Sidebar from '../Sidebar';
 
-const MEASURES = [
-  {
-    metric: {
-      id: '1',
-      key: 'lines_to_cover',
-      type: 'INT',
-      name: 'Lines to Cover',
-      domain: 'Coverage'
-    },
-    value: '431',
-    periods: [{ index: 1, value: '70' }],
-    leak: '70'
-  },
-  {
-    metric: {
-      id: '2',
-      key: 'coverage',
-      type: 'PERCENT',
-      name: 'Coverage',
-      domain: 'Coverage'
-    },
-    value: '99.3',
-    periods: [{ index: 1, value: '0.0999999999999943' }],
-    leak: '0.0999999999999943'
-  },
-  {
-    metric: {
-      id: '3',
-      key: 'duplicated_lines_density',
-      type: 'PERCENT',
-      name: 'Duplicated Lines (%)',
-      domain: 'Duplications'
-    },
-    value: '3.2',
-    periods: [{ index: 1, value: '0.0' }],
-    leak: '0.0'
-  }
-];
-
-const PROPS = {
-  hasOverview: true,
-  measures: MEASURES,
-  selectedMetric: 'duplicated_lines_density',
-  updateQuery: () => {}
-};
-
 it('should display two facets', () => {
-  expect(shallow(<Sidebar {...PROPS} />)).toMatchSnapshot();
+  expect(shallowRender()).toMatchSnapshot();
 });
 
 it('should correctly toggle facets', () => {
-  const wrapper = shallow<Sidebar>(<Sidebar {...PROPS} />);
+  const wrapper = shallowRender();
   expect(wrapper.state('openFacets').bugs).toBeUndefined();
   (wrapper.instance() as Sidebar).toggleFacet('bugs');
   expect(wrapper.state('openFacets').bugs).toBeTruthy();
   (wrapper.instance() as Sidebar).toggleFacet('bugs');
   expect(wrapper.state('openFacets').bugs).toBeFalsy();
 });
+
+function shallowRender(props = {}) {
+  return shallow<Sidebar>(
+    <Sidebar
+      measures={[
+        {
+          metric: {
+            id: '1',
+            key: 'lines_to_cover',
+            type: 'INT',
+            name: 'Lines to Cover',
+            domain: 'Coverage'
+          },
+          value: '431',
+          periods: [{ index: 1, value: '70' }],
+          leak: '70'
+        },
+        {
+          metric: {
+            id: '2',
+            key: 'coverage',
+            type: 'PERCENT',
+            name: 'Coverage',
+            domain: 'Coverage'
+          },
+          value: '99.3',
+          periods: [{ index: 1, value: '0.0999999999999943' }],
+          leak: '0.0999999999999943'
+        },
+        {
+          metric: {
+            id: '3',
+            key: 'duplicated_lines_density',
+            type: 'PERCENT',
+            name: 'Duplicated Lines (%)',
+            domain: 'Duplications'
+          },
+          value: '3.2',
+          periods: [{ index: 1, value: '0.0' }],
+          leak: '0.0'
+        }
+      ]}
+      selectedMetric={'duplicated_lines_density'}
+      showFullMeasures={true}
+      updateQuery={() => {}}
+      {...props}
+    />
+  );
+}
index 25deb6dc14a5fa37d3a17693a659bf31ae9d1414..8fbc77212865ecb06e0b7eb1bdfe4aff5cd6b105 100644 (file)
@@ -60,6 +60,7 @@ exports[`should display facet item list 1`] = `
       onClick={[Function]}
       stat={
         <FacetMeasureValue
+          displayLeak={true}
           measure={
             Object {
               "leak": "5",
@@ -110,6 +111,7 @@ exports[`should display facet item list 1`] = `
       onClick={[Function]}
       stat={
         <FacetMeasureValue
+          displayLeak={true}
           measure={
             Object {
               "leak": "5",
@@ -202,6 +204,7 @@ exports[`should display facet item list with bugs selected 1`] = `
       onClick={[Function]}
       stat={
         <FacetMeasureValue
+          displayLeak={true}
           measure={
             Object {
               "leak": "5",
@@ -252,6 +255,7 @@ exports[`should display facet item list with bugs selected 1`] = `
       onClick={[Function]}
       stat={
         <FacetMeasureValue
+          displayLeak={true}
           measure={
             Object {
               "leak": "5",
@@ -340,6 +344,7 @@ exports[`should not display subtitles of new measures if there is none 1`] = `
       onClick={[Function]}
       stat={
         <FacetMeasureValue
+          displayLeak={true}
           measure={
             Object {
               "metric": Object {
@@ -421,6 +426,7 @@ exports[`should not display subtitles of new measures if there is none, even on
       onClick={[Function]}
       stat={
         <FacetMeasureValue
+          displayLeak={true}
           measure={
             Object {
               "metric": Object {
@@ -441,10 +447,3 @@ exports[`should not display subtitles of new measures if there is none, even on
   </FacetItemsList>
 </FacetBox>
 `;
-
-exports[`should use "estimated" label for overall measures  1`] = `
-Array [
-  "component_measures.facet_category.new_code_category",
-  "component_measures.facet_category.overall_category.estimated",
-]
-`;
index 94bc6ea97f58f2b4c99a60c4dd655dd83f8572ad..104dad272ffa4db22b62dd2d330f7709cec16cfd 100644 (file)
@@ -13,6 +13,19 @@ exports[`should display leak measure value 1`] = `
 </div>
 `;
 
+exports[`should display leak measure value 2`] = `
+<div
+  className="domain-measures-value"
+  id="measure-new_bugs-leak"
+>
+  <Measure
+    metricKey="new_bugs"
+    metricType="INT"
+    value="5"
+  />
+</div>
+`;
+
 exports[`should display measure value 1`] = `
 <div
   className="domain-measures-value"
index d626c8f7948273e1ff675c24ef82f9f6d039f4c3..89b68eacb9d0c2d1609661dec13ac6b04dab2e01 100644 (file)
@@ -49,12 +49,12 @@ exports[`should display two facets 1`] = `
         "name": "Coverage",
       }
     }
-    hasOverview={true}
     key="Coverage"
     onChange={[Function]}
     onToggle={[Function]}
     open={false}
     selected="duplicated_lines_density"
+    showFullMeasures={true}
   />
   <DomainFacet
     domain={
@@ -81,12 +81,12 @@ exports[`should display two facets 1`] = `
         "name": "Duplications",
       }
     }
-    hasOverview={true}
     key="Duplications"
     onChange={[Function]}
     onToggle={[Function]}
     open={true}
     selected="duplicated_lines_density"
+    showFullMeasures={true}
   />
 </div>
 `;
index 52e39e4e0599a9edb1efcb2316f9350d1ef5a2c0..b28a82613cc70e40ee37d15cfe8d539a1fd25cdc 100644 (file)
@@ -23,8 +23,13 @@ import { bubbles } from './config/bubbles';
 import { getLocalizedMetricName } from '../../helpers/l10n';
 import { enhanceMeasure } from '../../components/measure/utils';
 import { cleanQuery, parseAsString, RawQuery, serializeString } from '../../helpers/query';
-import { isLongLivingBranch, isMainBranch } from '../../helpers/branches';
-import { getDisplayMetrics } from '../../helpers/measures';
+import {
+  isLongLivingBranch,
+  isMainBranch,
+  isPullRequest,
+  isShortLivingBranch
+} from '../../helpers/branches';
+import { getDisplayMetrics, isDiffMetric } from '../../helpers/measures';
 
 export type View = 'list' | 'tree' | 'treemap';
 
@@ -152,25 +157,13 @@ export function getMeasuresPageMetricKeys(
   metrics: { [key: string]: T.Metric },
   branch?: T.BranchLike
 ) {
-  if (!hasFullMeasures(branch)) {
-    return [
-      'coverage',
-      'new_coverage',
-      'new_lines_to_cover',
-      'new_uncovered_lines',
-      'new_line_coverage',
-      'new_conditions_to_cover',
-      'new_uncovered_conditions',
-      'new_branch_coverage',
-
-      'duplicated_lines_density',
-      'new_duplicated_lines_density',
-      'new_duplicated_lines',
-      'new_duplicated_blocks'
-    ];
-  }
+  const metricKeys = getDisplayMetrics(Object.values(metrics)).map(metric => metric.key);
 
-  return getDisplayMetrics(Object.values(metrics)).map(metric => metric.key);
+  if (isPullRequest(branch) || isShortLivingBranch(branch)) {
+    return metricKeys.filter(key => isDiffMetric(key));
+  } else {
+    return metricKeys;
+  }
 }
 
 export function getBubbleMetrics(domain: string, metrics: { [key: string]: T.Metric }) {