]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-7066 Improve display of leak period on the overview page
authorStas Vilchik <vilchiks@gmail.com>
Thu, 26 Nov 2015 08:21:27 +0000 (09:21 +0100)
committerStas Vilchik <vilchiks@gmail.com>
Thu, 26 Nov 2015 08:21:56 +0000 (09:21 +0100)
server/sonar-web/src/main/js/apps/overview/components/legend.js
server/sonar-web/src/main/js/apps/overview/domains/coverage-domain.js
server/sonar-web/src/main/js/apps/overview/domains/debt-domain.js
server/sonar-web/src/main/js/apps/overview/domains/duplications-domain.js
server/sonar-web/src/main/js/apps/overview/domains/size-domain.js
server/sonar-web/src/main/js/apps/overview/main/components.js
server/sonar-web/src/main/js/apps/overview/main/issues.js
server/sonar-web/src/main/js/apps/overview/main/main.js
server/sonar-web/src/main/less/pages/overview.less
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index 1c38b7d17b12c9a1a251fe7bd7a1addc28eb47d0..4e4de8f5882d0c3e1c7b772dc579751e5bfd0505 100644 (file)
@@ -1,15 +1,12 @@
 import React from 'react';
+import moment from 'moment';
 
 import { DomainLeakTitle } from '../main/components';
 
 
 export const Legend = React.createClass({
   render() {
-    if (!this.props.leakPeriodDate) {
-      return null;
-    }
-    return <div className="overview-legend">
-      <span className="overview-legend-leak"/>
+    return <div className="overview-legend overview-leak">
       <DomainLeakTitle label={this.props.leakPeriodLabel} date={this.props.leakPeriodDate}/>
     </div>;
   }
index 79a45f6340842f7f8ea465ac185ae73fa2939508..6b0cbc391bc90717b1483731b4029645ae731211 100644 (file)
@@ -9,7 +9,7 @@ import { CoverageSelectionMixin } from '../components/coverage-selection-mixin';
 import { getPeriodLabel, getPeriodDate } from './../helpers/periods';
 import { TooltipsMixin } from '../../../components/mixins/tooltips-mixin';
 import { filterMetrics, filterMetricsForDomains } from '../helpers/metrics';
-import { Legend } from '../components/legend';
+import { DomainLeakTitle } from '../main/components';
 import { CHART_COLORS_RANGE_PERCENT } from '../../../helpers/constants';
 import { CoverageMeasuresList } from '../components/coverage-measures-list';
 
@@ -74,7 +74,7 @@ export const CoverageMain = React.createClass({
   },
 
   renderLegend () {
-    return <Legend leakPeriodDate={this.state.leakPeriodDate} leakPeriodLabel={this.state.leakPeriodLabel}/>;
+    return <DomainLeakTitle inline={true} label={this.state.leakPeriodLabel} date={this.state.leakPeriodDate}/>
   },
 
   render () {
index bf521c4b69c69f7bac6d305fbc6f4d631f3fa563..f3a28a07ef40bff795cf9d97dba10143abe8b841 100644 (file)
@@ -10,7 +10,6 @@ import { DomainBubbleChart } from '../components/domain-bubble-chart';
 import { getPeriodLabel, getPeriodDate } from './../helpers/periods';
 import { TooltipsMixin } from '../../../components/mixins/tooltips-mixin';
 import { filterMetrics, filterMetricsForDomains } from '../helpers/metrics';
-import { Legend } from '../components/legend';
 import { CHART_COLORS_RANGE_PERCENT } from '../../../helpers/constants';
 import { AddedRemovedMeasure, AddedRemovedDebt, OnNewCodeMeasure, SeverityMeasure } from './../components/issue-measure';
 import { IssuesTags } from './../components/issues-tags';
@@ -19,6 +18,7 @@ import { getFacet, extractAssignees } from '../../../api/issues';
 import StatusHelper from '../../../components/shared/status-helper';
 import { Rating } from '../../../components/shared/rating';
 import { DrilldownLink } from '../../../components/shared/drilldown-link';
+import { DomainLeakTitle } from '../main/components';
 
 
 const KNOWN_METRICS = ['violations', 'sqale_index', 'sqale_rating', 'sqale_debt_ratio', 'blocker_violations',
@@ -102,7 +102,7 @@ export const IssuesMain = React.createClass({
   },
 
   renderLegend () {
-    return <Legend leakPeriodDate={this.state.leakPeriodDate} leakPeriodLabel={this.state.leakPeriodLabel}/>;
+    return <DomainLeakTitle inline={true} label={this.state.leakPeriodLabel} date={this.state.leakPeriodDate}/>
   },
 
   renderOtherMeasures() {
index 48067d57a17c1a611c11bab050e101520c75c365..946b6f1663b32c57a203e423387c9a48e242efd2 100644 (file)
@@ -9,7 +9,7 @@ import { DomainBubbleChart } from '../components/domain-bubble-chart';
 import { getPeriodLabel, getPeriodDate } from './../helpers/periods';
 import { TooltipsMixin } from '../../../components/mixins/tooltips-mixin';
 import { filterMetrics, filterMetricsForDomains } from '../helpers/metrics';
-import { Legend } from '../components/legend';
+import { DomainLeakTitle } from '../main/components';
 import { CHART_COLORS_RANGE_PERCENT } from '../../../helpers/constants';
 
 
@@ -65,7 +65,7 @@ export const DuplicationsMain = React.createClass({
   },
 
   renderLegend () {
-    return <Legend leakPeriodDate={this.state.leakPeriodDate} leakPeriodLabel={this.state.leakPeriodLabel}/>;
+    return <DomainLeakTitle inline={true} label={this.state.leakPeriodLabel} date={this.state.leakPeriodDate}/>
   },
 
   renderMeasures() {
index 45b4728d73e917192a07ae22d09fd91ec6209c41..ed309e8d7f4da655885ef8fe49b7b65a22df1622 100644 (file)
@@ -9,7 +9,7 @@ import { DomainTreemap } from '../components/domain-treemap';
 import { getPeriodLabel, getPeriodDate } from './../helpers/periods';
 import { TooltipsMixin } from '../../../components/mixins/tooltips-mixin';
 import { filterMetrics, filterMetricsForDomains } from '../helpers/metrics';
-import { Legend } from '../components/legend';
+import { DomainLeakTitle } from '../main/components';
 
 
 export const SizeMain = React.createClass({
@@ -64,7 +64,7 @@ export const SizeMain = React.createClass({
   },
 
   renderLegend () {
-    return <Legend leakPeriodDate={this.state.leakPeriodDate} leakPeriodLabel={this.state.leakPeriodLabel}/>;
+    return <DomainLeakTitle inline={true} label={this.state.leakPeriodLabel} date={this.state.leakPeriodDate}/>
   },
 
   renderOtherMeasures(domain, hiddenMetrics) {
index 87b920f7ea0375543d85a4a79901d87a511500f2..33f802d61a458c257384a2f30e703c03f61c3922 100644 (file)
@@ -2,7 +2,6 @@ import moment from 'moment';
 import React from 'react';
 
 import { Timeline } from './timeline';
-import { Legend } from '../components/legend';
 
 
 export const Domain = React.createClass({
@@ -21,7 +20,9 @@ export const DomainTitle = React.createClass({
         <div className="overview-title">
           {this.props.children}
           <a className="small big-spacer-left link-no-underline" href={url}>
-            More <i className="icon-chevron-right" style={{ position: 'relative', top: -1 }}/></a>
+            {window.t('more')}&nbsp;
+            <i className="icon-chevron-right" style={{ position: 'relative', top: -1 }}/>
+          </a>
         </div>
       </div>;
     } else {
@@ -32,14 +33,28 @@ export const DomainTitle = React.createClass({
 
 
 export const DomainLeakTitle = React.createClass({
+  renderInline (tooltip, fromNow) {
+    return <span title={tooltip} data-toggle="tooltip">
+      <span>{window.tp('overview.leak_period_x', this.props.label)}</span>
+      <span className="note spacer-left">{window.tp('overview.started_x', fromNow)}</span>
+    </span>;
+  },
+
   render() {
     if (!this.props.label || !this.props.date) {
       return null;
     }
     let momentDate = moment(this.props.date);
     let fromNow = momentDate.fromNow();
-    let tooltip = 'Started ' + fromNow + ', ' + momentDate.format('LL');
-    return <span title={tooltip} data-toggle="tooltip">Water Leak: {this.props.label}</span>;
+    let tooltip = 'Started on ' + momentDate.format('LL');
+    if (this.props.inline) {
+      return this.renderInline(tooltip, fromNow);
+    }
+    return <span title={tooltip} data-toggle="tooltip">
+      <span>{window.tp('overview.leak_period_x', this.props.label)}</span>
+      <br/>
+      <span className="note">{window.tp('overview.started_x', fromNow)}</span>
+    </span>;
   }
 });
 
@@ -48,7 +63,6 @@ export const DomainHeader = React.createClass({
   render () {
     return <div className="overview-card-header">
       <DomainTitle {...this.props}>{this.props.title}</DomainTitle>
-      <Legend leakPeriodLabel={this.props.leakPeriodLabel} leakPeriodDate={this.props.leakPeriodDate}/>
     </div>;
   }
 });
@@ -122,7 +136,13 @@ export const Measure = React.createClass({
 
 
 export const DomainMixin = {
-  renderTimeline(range) {
+  renderTimelineStartDate() {
+    let momentDate = moment(this.props.historyStartDate),
+        fromNow = momentDate.fromNow();
+    return <span className="overview-domain-timeline-date">{window.tp('overview.started_x', fromNow)}</span>;
+  },
+
+  renderTimeline(range, displayDate) {
     if (!this.props.history) {
       return null;
     }
@@ -130,6 +150,7 @@ export const DomainMixin = {
     props[range] = this.props.leakPeriodDate;
     return <div className="overview-domain-timeline">
       <Timeline {...props}/>
+      {displayDate ? this.renderTimelineStartDate(range) : null}
     </div>;
   },
 
index b291d8243eb3c9763dd353e1f87822ce68d741ab..e0772a6310000800e4bda8307a90879093d80d35 100644 (file)
@@ -7,6 +7,7 @@ import { IssuesLink } from '../../../components/shared/issues-link';
 import { DrilldownLink } from '../../../components/shared/drilldown-link';
 import SeverityIcon from '../../../components/shared/severity-icon';
 import { TooltipsMixin } from '../../../components/mixins/tooltips-mixin';
+import { Legend } from '../components/legend';
 import { getMetricName } from '../helpers/metrics';
 import { formatMeasure } from '../../../helpers/measures';
 
@@ -27,6 +28,8 @@ export const GeneralIssues = React.createClass({
     let createdAfter = moment(this.props.leakPeriodDate).format('YYYY-MM-DDTHH:mm:ssZZ');
 
     return <DomainLeak>
+      <Legend leakPeriodLabel={this.props.leakPeriodLabel} leakPeriodDate={this.props.leakPeriodDate}/>
+
       <MeasuresList>
         <Measure label={getMetricName('new_debt')}>
           <IssuesLink component={this.props.component.key}
@@ -47,8 +50,7 @@ export const GeneralIssues = React.createClass({
 
   render () {
     return <Domain>
-      <DomainHeader component={this.props.component} title={window.t('overview.domain.debt')} linkTo="/issues"
-                    leakPeriodLabel={this.props.leakPeriodLabel} leakPeriodDate={this.props.leakPeriodDate}/>
+      <DomainHeader component={this.props.component} title={window.t('overview.domain.debt')} linkTo="/issues"/>
 
       <DomainPanel domain="issues">
         <DomainNutshell>
@@ -69,7 +71,7 @@ export const GeneralIssues = React.createClass({
               </IssuesLink>
             </Measure>
           </MeasuresList>
-          {this.renderTimeline('before')}
+          {this.renderTimeline('before', true)}
         </DomainNutshell>
         {this.renderLeak()}
       </DomainPanel>
index 7d4037a9150cebdb36b7dfcc5b001f47a9774e7d..71c4542805275e83bb339e879028ea4f0d83f4f3 100644 (file)
@@ -132,7 +132,8 @@ export default React.createClass({
           return { date, value };
         });
       });
-      this.setState({ history });
+      let historyStartDate = history[HISTORY_METRICS_LIST[0]][0].date;
+      this.setState({ history, historyStartDate });
     });
   },
 
index 972b04cbee033b1b82a188923f8970f6853ca8a1..3f616043e1f54f021b3a508dab14fb288f0f0576 100644 (file)
 }
 
 .overview-card {
-  margin: 30px 20px;
+  margin: 15px 20px;
 }
 
 .overview-card-fixed-width {
   margin-top: 10px;
   border: 1px solid @barBorderColor;
   background-color: #fff;
-  overflow: hidden;
 
   .overview-bar-chart {
     padding: 0;
 .overview-domain-leak {
   position: relative;
   display: flex;
-  padding: 30px 10px;
+  padding: 15px 10px;
 }
 
 .overview-domain-nutshell {
   }
 }
 
+.overview-domain-timeline-date {
+  position: absolute;
+  bottom: 2px;
+  left: 5px;
+  color: fade(@secondFontColor, 60%);
+  font-size: 11px;
+}
+
 /*
  * Detailed Pages
  */
   padding: 0 10px;
 }
 
-.overview-legend-leak {
-  display: inline-block;
-  vertical-align: middle;
-  width: 16px;
-  height: 16px;
-  margin-top: -2px;
-  margin-left: 16px;
-  margin-right: 8px;
+.overview-legend {
+  position: absolute;
+  bottom: 100%;
+  left: 0;
+  right: -1px;
+  padding: 5px 0 2px;
   border: 1px solid @barBorderColor;
-  box-sizing: border-box;
-  background-color: #fffae7;
+  border-bottom: none;
+  font-size: 14px;
+  text-align: center;
 }
 
 /*
index aa4069ea98974ea18f15453e79d0810ededc3700..cd8c9af424af597f5d13b67b1288bd881434a8c5 100644 (file)
@@ -3108,7 +3108,8 @@ system.log_level.warning=Current level has performance impacts, please make sure
 #------------------------------------------------------------------------------
 overview.quality_gate=Quality Gate
 overview.quality_profiles=Quality Profiles
-overview.water_leak=Water Leak
+overview.leak_period_x=Leak Period {0}
+overview.started_x=started {0}
 overview.project_in_a_nutshell=Project In a Nutshell
 overview.unmanaged_issues=Unmanaged Issues