]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-8767 Now use sinceLeakPeriod instead of a periodDate
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>
Thu, 4 May 2017 16:00:30 +0000 (18:00 +0200)
committerGrégoire Aubert <gregoire.aubert@sonarsource.com>
Tue, 9 May 2017 09:14:36 +0000 (11:14 +0200)
server/sonar-web/src/main/js/apps/overview/components/OverviewApp.js
server/sonar-web/src/main/js/apps/overview/main/Coverage.js
server/sonar-web/src/main/js/apps/overview/main/Duplications.js
server/sonar-web/src/main/js/apps/overview/qualityGate/QualityGate.js
server/sonar-web/src/main/js/apps/overview/qualityGate/QualityGateCondition.js
server/sonar-web/src/main/js/apps/overview/qualityGate/QualityGateConditions.js
server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/QualityGateCondition-test.js
server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/__snapshots__/QualityGateCondition-test.js.snap
server/sonar-web/src/main/js/apps/overview/types.js [new file with mode: 0644]
server/sonar-web/src/main/js/components/shared/drilldown-link.js

index 517678a906fccbe5647541a9362c7492c9aecf18..04d85e28e95e3c313262f220292ab56c93a89279 100644 (file)
@@ -161,7 +161,7 @@ export default class OverviewApp extends React.PureComponent {
       <div className="page page-limited">
         <div className="overview page-with-sidebar">
           <div className="overview-main page-main">
-            <QualityGate component={component} measures={measures} periods={periods} />
+            <QualityGate component={component} measures={measures} />
 
             <TooltipsContainer>
               <div className="overview-domains-list">
index c9aa1f9a576173c678cbe970c2bb8c3dce458aaa..b2eeb752d25cfa84d7d1a5943d51935af67536f7 100644 (file)
@@ -96,10 +96,7 @@ class Coverage extends React.PureComponent {
 
     const formattedValue = newCoverageValue != null
       ? <div>
-          <DrilldownLink
-            component={component.key}
-            metric={newCoverageMeasure.metric.key}
-            period={leakPeriod.index}>
+          <DrilldownLink component={component.key} metric={newCoverageMeasure.metric.key}>
             <span className="js-overview-main-new-coverage">
               {formatMeasure(newCoverageValue, 'PERCENT')}
             </span>
@@ -113,8 +110,7 @@ class Coverage extends React.PureComponent {
           <DrilldownLink
             className="spacer-right overview-domain-secondary-measure-value"
             component={component.key}
-            metric={newLinesToCover.metric.key}
-            period={leakPeriod.index}>
+            metric={newLinesToCover.metric.key}>
             <span className="js-overview-main-new-coverage">
               {formatMeasure(newLinesToCoverValue, 'SHORT_INT')}
             </span>
index 1a090d6fdb9ff0a98da9069a77fedb9d7636766f..d0989dcddf1623d41dc7c46cfef889404fdb13b7 100644 (file)
@@ -80,10 +80,7 @@ class Duplications extends React.PureComponent {
 
     const formattedValue = newDuplicationsValue != null
       ? <div>
-          <DrilldownLink
-            component={component.key}
-            metric={newDuplicationsMeasure.metric.key}
-            period={leakPeriod.index}>
+          <DrilldownLink component={component.key} metric={newDuplicationsMeasure.metric.key}>
             <span className="js-overview-main-new-duplications">
               {formatMeasure(newDuplicationsValue, 'PERCENT')}
             </span>
@@ -97,8 +94,7 @@ class Duplications extends React.PureComponent {
           <DrilldownLink
             className="spacer-right overview-domain-secondary-measure-value"
             component={component.key}
-            metric={newLinesMeasure.metric.key}
-            period={leakPeriod.index}>
+            metric={newLinesMeasure.metric.key}>
             <span className="js-overview-main-new-lines">
               {formatMeasure(newLinesValue, 'SHORT_INT')}
             </span>
index 0968fec0d3bed0858d4fde368bcb311c3d1469a2..18413693f9af0674d2b7b387d0b1cfa02ac95674 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+//@flow
 import React from 'react';
 import QualityGateConditions from './QualityGateConditions';
 import EmptyQualityGate from './EmptyQualityGate';
-import { ComponentType, MeasuresListType, PeriodsListType } from '../propTypes';
 import { translate } from '../../../helpers/l10n';
 import Level from '../../../components/ui/Level';
+import type { Component, MeasuresList } from '../types';
 
-function parseQualityGateDetails(rawDetails) {
+function parseQualityGateDetails(rawDetails: string) {
   return JSON.parse(rawDetails);
 }
 
-function isProject(component) {
+function isProject(component: Component) {
   return component.qualifier === 'TRK';
 }
 
-const QualityGate = ({ component, measures, periods }) => {
+type Props = {
+  component: Component,
+  measures: MeasuresList
+};
+
+export default function QualityGate({ component, measures }: Props) {
   const statusMeasure = measures.find(measure => measure.metric.key === 'alert_status');
   const detailsMeasure = measures.find(measure => measure.metric.key === 'quality_gate_details');
 
@@ -43,7 +49,7 @@ const QualityGate = ({ component, measures, periods }) => {
   const level = statusMeasure.value;
 
   let conditions = [];
-  if (detailsMeasure) {
+  if (detailsMeasure && detailsMeasure.value) {
     conditions = parseQualityGateDetails(detailsMeasure.value).conditions;
   }
 
@@ -55,15 +61,7 @@ const QualityGate = ({ component, measures, periods }) => {
       </h2>
 
       {conditions.length > 0 &&
-        <QualityGateConditions component={component} periods={periods} conditions={conditions} />}
+        <QualityGateConditions component={component} conditions={conditions} />}
     </div>
   );
-};
-
-QualityGate.propTypes = {
-  component: ComponentType.isRequired,
-  measures: MeasuresListType.isRequired,
-  periods: PeriodsListType.isRequired
-};
-
-export default QualityGate;
+}
index 8fec8fdfba6f2eab213794c2154d8f4b60f28957..132c49a88e907870512cd9afc6cfd4f061de2a6f 100644 (file)
@@ -25,19 +25,13 @@ import { DrilldownLink } from '../../../components/shared/drilldown-link';
 import Measure from '../../component-measures/components/Measure';
 import { getPeriodValue, isDiffMetric, formatMeasure } from '../../../helpers/measures';
 import { translate } from '../../../helpers/l10n';
-import { getPeriod, getPeriodDate } from '../../../helpers/periods';
 import { getComponentIssuesUrl } from '../../../helpers/urls';
 import IssueTypeIcon from '../../../components/ui/IssueTypeIcon';
+import type { Component } from '../types';
 
 export default class QualityGateCondition extends React.PureComponent {
   props: {
-    component: { key: string },
-    periods: Array<{
-      index: number,
-      date: string,
-      mode: string,
-      parameter?: string
-    }>,
+    component: Component,
     condition: {
       level: string,
       measure: {
@@ -94,15 +88,12 @@ export default class QualityGateCondition extends React.PureComponent {
   }
 
   wrapWithLink(children: React.Element<*>) {
-    const { component, periods, condition } = this.props;
-
-    const period = getPeriod(periods, condition.period);
-    const periodDate = getPeriodDate(period);
+    const { component, condition } = this.props;
 
     const className = classNames(
       'overview-quality-gate-condition',
       'overview-quality-gate-condition-' + condition.level.toLowerCase(),
-      { 'overview-quality-gate-condition-leak': period != null }
+      { 'overview-quality-gate-condition-leak': condition.period != null }
     );
 
     const metricKey = condition.measure.metric.key;
@@ -124,14 +115,13 @@ export default class QualityGateCondition extends React.PureComponent {
           className={className}
           component={component.key}
           metric={condition.measure.metric.key}
-          period={condition.period}
-          periodDate={periodDate}>
+          sinceLeakPeriod={condition.period != null}>
           {children}
         </DrilldownLink>;
   }
 
   render() {
-    const { periods, condition } = this.props;
+    const { condition } = this.props;
 
     const { measure } = condition;
     const { metric } = measure;
@@ -142,7 +132,6 @@ export default class QualityGateCondition extends React.PureComponent {
     const threshold = condition.level === 'ERROR' ? condition.error : condition.warning;
 
     const actual = condition.period ? getPeriodValue(measure, condition.period) : measure.value;
-    const period = getPeriod(periods, condition.period);
 
     const operator = isRating
       ? translate('quality_gates.operator', condition.op, 'rating')
@@ -160,7 +149,7 @@ export default class QualityGateCondition extends React.PureComponent {
             {metric.name}
           </div>
           {!isDiff &&
-            period != null &&
+            condition.period != null &&
             <div className="overview-quality-gate-condition-period">
               {translate('quality_gates.conditions.leak')}
             </div>}
index 60be2bd664a19b9760c20e0641e1ae093ddb8047..cd98f13bae9859180e87de2801fbb4066c257c89 100644 (file)
@@ -81,7 +81,7 @@ export default class QualityGateConditions extends React.PureComponent {
   }
 
   render() {
-    const { component, periods } = this.props;
+    const { component } = this.props;
     const { loading, conditions } = this.state;
 
     if (loading) {
@@ -102,7 +102,6 @@ export default class QualityGateConditions extends React.PureComponent {
           <QualityGateCondition
             key={condition.measure.metric.key}
             component={component}
-            periods={periods}
             condition={condition}
           />
         ))}
index e798bcd33269c7a4e55737bb89a16c645dbeb44f..e07cc20c666f097d823becc16de135e531d8a2e4 100644 (file)
@@ -37,6 +37,8 @@ const mockRatingCondition = metric => ({
   metric
 });
 
+const periods = [{ value: '3', index: 1 }];
+
 it('open_issues', () => {
   const condition = {
     actual: '10',
@@ -54,9 +56,7 @@ it('open_issues', () => {
     op: 'GT'
   };
   expect(
-    shallow(
-      <QualityGateCondition component={{ key: 'abcd-key' }} periods={[]} condition={condition} />
-    )
+    shallow(<QualityGateCondition component={{ key: 'abcd-key' }} condition={condition} />)
   ).toMatchSnapshot();
 });
 
@@ -71,68 +71,62 @@ it('new_open_issues', () => {
         type: 'INT',
         name: 'new_open_issues'
       },
+      periods: [{ value: '10', index: 1 }],
       value: '10'
     },
     metric: 'new_open_issues',
-    op: 'GT'
+    op: 'GT',
+    period: 1
   };
   expect(
-    shallow(
-      <QualityGateCondition component={{ key: 'abcd-key' }} periods={[]} condition={condition} />
-    )
+    shallow(<QualityGateCondition component={{ key: 'abcd-key' }} condition={condition} />)
   ).toMatchSnapshot();
 });
 
 it('reliability_rating', () => {
   const condition = mockRatingCondition('reliability_rating');
   expect(
-    shallow(
-      <QualityGateCondition component={{ key: 'abcd-key' }} periods={[]} condition={condition} />
-    )
+    shallow(<QualityGateCondition component={{ key: 'abcd-key' }} condition={condition} />)
   ).toMatchSnapshot();
 });
 
 it('security_rating', () => {
   const condition = mockRatingCondition('security_rating');
   expect(
-    shallow(
-      <QualityGateCondition component={{ key: 'abcd-key' }} periods={[]} condition={condition} />
-    )
+    shallow(<QualityGateCondition component={{ key: 'abcd-key' }} condition={condition} />)
   ).toMatchSnapshot();
 });
 
 it('sqale_rating', () => {
   const condition = mockRatingCondition('sqale_rating');
   expect(
-    shallow(
-      <QualityGateCondition component={{ key: 'abcd-key' }} periods={[]} condition={condition} />
-    )
+    shallow(<QualityGateCondition component={{ key: 'abcd-key' }} condition={condition} />)
   ).toMatchSnapshot();
 });
 
 it('new_reliability_rating', () => {
   const condition = mockRatingCondition('new_reliability_rating');
+  condition.period = 1;
+  condition.measure.periods = periods;
   expect(
-    shallow(
-      <QualityGateCondition component={{ key: 'abcd-key' }} periods={[]} condition={condition} />
-    )
+    shallow(<QualityGateCondition component={{ key: 'abcd-key' }} condition={condition} />)
   ).toMatchSnapshot();
 });
 
 it('new_security_rating', () => {
   const condition = mockRatingCondition('new_security_rating');
+  condition.period = 1;
+  condition.measure.periods = periods;
   expect(
-    shallow(
-      <QualityGateCondition component={{ key: 'abcd-key' }} periods={[]} condition={condition} />
-    )
+    shallow(<QualityGateCondition component={{ key: 'abcd-key' }} condition={condition} />)
   ).toMatchSnapshot();
 });
 
 it('new_sqale_rating', () => {
   const condition = mockRatingCondition('new_sqale_rating');
+  condition.period = 1;
+  condition.measure.periods = periods;
   expect(
-    shallow(
-      <QualityGateCondition component={{ key: 'abcd-key' }} periods={[]} condition={condition} />
-    )
+    shallow(<QualityGateCondition component={{ key: 'abcd-key' }} condition={condition} />)
   ).toMatchSnapshot();
 });
index f220ea81475bedcf910232b6bde23028470dc27b..7a70e96aa6d59b16ee8f5c8cc04b9fd16aae9c3e 100644 (file)
@@ -2,10 +2,10 @@
 
 exports[`new_open_issues 1`] = `
 <DrilldownLink
-  className="overview-quality-gate-condition overview-quality-gate-condition-error"
+  className="overview-quality-gate-condition overview-quality-gate-condition-error overview-quality-gate-condition-leak"
   component="abcd-key"
   metric="new_open_issues"
-  periodDate={null}
+  sinceLeakPeriod={true}
 >
   <div
     className="overview-quality-gate-condition-container"
@@ -53,7 +53,7 @@ exports[`new_open_issues 1`] = `
 
 exports[`new_reliability_rating 1`] = `
 <Link
-  className="overview-quality-gate-condition overview-quality-gate-condition-error"
+  className="overview-quality-gate-condition overview-quality-gate-condition-error overview-quality-gate-condition-leak"
   onlyActiveOnIndex={false}
   style={Object {}}
   to={
@@ -115,7 +115,7 @@ exports[`new_reliability_rating 1`] = `
 
 exports[`new_security_rating 1`] = `
 <Link
-  className="overview-quality-gate-condition overview-quality-gate-condition-error"
+  className="overview-quality-gate-condition overview-quality-gate-condition-error overview-quality-gate-condition-leak"
   onlyActiveOnIndex={false}
   style={Object {}}
   to={
@@ -177,7 +177,7 @@ exports[`new_security_rating 1`] = `
 
 exports[`new_sqale_rating 1`] = `
 <Link
-  className="overview-quality-gate-condition overview-quality-gate-condition-error"
+  className="overview-quality-gate-condition overview-quality-gate-condition-error overview-quality-gate-condition-leak"
   onlyActiveOnIndex={false}
   style={Object {}}
   to={
@@ -241,7 +241,7 @@ exports[`open_issues 1`] = `
   className="overview-quality-gate-condition overview-quality-gate-condition-error"
   component="abcd-key"
   metric="open_issues"
-  periodDate={null}
+  sinceLeakPeriod={false}
 >
   <div
     className="overview-quality-gate-condition-container"
diff --git a/server/sonar-web/src/main/js/apps/overview/types.js b/server/sonar-web/src/main/js/apps/overview/types.js
new file mode 100644 (file)
index 0000000..af71d5a
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info 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.
+ */
+//@flow
+export type Component = {
+  id: string,
+  key: string,
+  qualifier: string
+};
+
+export type Metric = {
+  key: string,
+  name: string,
+  type: string
+};
+
+export type Measure = {
+  metric: Metric,
+  value?: string,
+  periods?: Array<Period>
+};
+
+export type Period = {
+  index: number,
+  date: string,
+  mode: string,
+  parameter?: string
+};
+
+export type MeasuresList = Array<Measure>;
index fddfa7589893a54fed597329ddf2e31312eb16a8..1a0febed8e02fe1323d8b2f97196b5d645a68220 100644 (file)
@@ -17,7 +17,6 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
-import moment from 'moment';
 import React from 'react';
 import { Link } from 'react-router';
 import { getComponentDrilldownUrl, getComponentIssuesUrl } from '../../helpers/urls';
@@ -48,6 +47,16 @@ const ISSUE_MEASURES = [
 ];
 
 export class DrilldownLink extends React.PureComponent {
+  static propTypes = {
+    children: React.PropTypes.oneOfType([
+      React.PropTypes.node,
+      React.PropTypes.arrayOf(React.PropTypes.node)
+    ]),
+    className: React.PropTypes.string,
+    component: React.PropTypes.string.isRequired,
+    metric: React.PropTypes.string.isRequired,
+    sinceLeakPeriod: React.PropTypes.bool
+  };
   isIssueMeasure = () => {
     return ISSUE_MEASURES.indexOf(this.props.metric) !== -1;
   };
@@ -55,8 +64,8 @@ export class DrilldownLink extends React.PureComponent {
   propsToIssueParams = () => {
     const params = {};
 
-    if (this.props.periodDate) {
-      params.createdAfter = moment(this.props.periodDate).format('YYYY-MM-DDTHH:mm:ssZZ');
+    if (this.props.sinceLeakPeriod) {
+      params.sinceLeakPeriod = true;
     }
 
     switch (this.props.metric) {