]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6331 apply feedback
authorStas Vilchik <vilchiks@gmail.com>
Mon, 26 Oct 2015 17:54:59 +0000 (18:54 +0100)
committerStas Vilchik <vilchiks@gmail.com>
Tue, 27 Oct 2015 09:07:00 +0000 (10:07 +0100)
16 files changed:
server/sonar-web/src/main/js/apps/overview/app.js
server/sonar-web/src/main/js/apps/overview/general/gate-condition.js
server/sonar-web/src/main/js/apps/overview/general/leak-coverage.js
server/sonar-web/src/main/js/apps/overview/general/leak-dups.js
server/sonar-web/src/main/js/apps/overview/general/leak-issues.js
server/sonar-web/src/main/js/apps/overview/general/leak-size.js
server/sonar-web/src/main/js/apps/overview/general/leak.js
server/sonar-web/src/main/js/apps/overview/general/main.js
server/sonar-web/src/main/js/apps/overview/general/nutshell-coverage.js
server/sonar-web/src/main/js/apps/overview/general/nutshell-dups.js
server/sonar-web/src/main/js/apps/overview/general/nutshell-issues.js
server/sonar-web/src/main/js/apps/overview/general/nutshell-size.js
server/sonar-web/src/main/js/apps/overview/main.js
server/sonar-web/src/main/js/components/charts/treemap.js
server/sonar-web/src/main/less/pages/overview.less
server/sonar-web/src/main/webapp/WEB-INF/app/views/overview/index.html.erb

index 6b661b9b592f8207936de87502ebd01da17e6b84..29fabe96cd38a06f0f3515321a9fbc6a580019ff 100644 (file)
@@ -1,7 +1,7 @@
 import $ from 'jquery';
 import _ from 'underscore';
 import React from 'react';
-import Main from './main';
+import { Overview } from './main';
 
 class App {
   start (options) {
@@ -9,7 +9,7 @@ class App {
     _.extend(opts.component, options.component);
     $('html').toggleClass('dashboard-page', opts.component.hasSnapshot);
     let el = document.querySelector(opts.el);
-    React.render(<Main {...opts}/>, el);
+    React.render(<Overview {...opts}/>, el);
   }
 }
 
index eb947c8eaf7b4825edaf14d21a0ec1efb70eb403..32727972d0390ad3484110d1700ed66bccd2f68a 100644 (file)
@@ -1,26 +1,30 @@
 import React from 'react';
+
 import Measure from './../helpers/measure';
 import { periodLabel, getPeriodDate } from './../helpers/period-label';
 import DrilldownLink from './../helpers/drilldown-link';
 
+
 export default React.createClass({
   render() {
     let metricName = window.t('metric', this.props.condition.metric.name, 'name'),
         threshold = this.props.condition.level === 'ERROR' ?
-            this.props.condition.error : this.props.condition.warning,
-        iconClassName = 'icon-alert-' + this.props.condition.level.toLowerCase(),
+                    this.props.condition.error : this.props.condition.warning,
         period = this.props.condition.period ?
-            `(${periodLabel(this.props.component.periods, this.props.condition.period)})` : null,
+                 `(${periodLabel(this.props.component.periods, this.props.condition.period)})` : null,
         periodDate = getPeriodDate(this.props.component.periods, this.props.condition.period);
 
+    let classes = 'alert_' + this.props.condition.level.toUpperCase();
+
     return (
         <div>
           <h4 className="overview-gate-condition-metric">{metricName}<br/><span className="nowrap">{period}</span></h4>
           <div className="overview-gate-condition-value">
-            <i className={iconClassName}/>&nbsp;
             <DrilldownLink component={this.props.component.key} metric={this.props.condition.metric.name}
                            period={this.props.condition.period} periodDate={periodDate}>
-              <Measure value={this.props.condition.actual} type={this.props.condition.metric.type}/>
+              <span className={classes}>
+                <Measure value={this.props.condition.actual} type={this.props.condition.metric.type}/>
+              </span>
             </DrilldownLink>&nbsp;
             <span className="overview-gate-condition-itself">
               {window.t('quality_gates.operator', this.props.condition.op, 'short')}&nbsp;
index 5af186b9933ae7375ffb31d55b4d4e926d5f954a..23e3fabd7e1770074519e51e55019387ba065b5f 100644 (file)
@@ -26,12 +26,12 @@ export default React.createClass({
               <Donut data={donutData} size="47"/>
             </div>
             <div className="measure measure-big" data-metric="new_coverage">
+              <span className="measure-name">{window.t('overview.metric.new_coverage')}</span>
               <span className="measure-value">
-                <DrilldownLink component={this.props.component.key} metric="new_coverage" period="3">
+                <DrilldownLink component={this.props.component.key} metric="new_coverage" period="1">
                   <Measure value={newCoverage} type="PERCENT"/>
                 </DrilldownLink>
               </span>
-              <span className="measure-name">{window.t('overview.metric.new_coverage')}</span>
             </div>
           </div>
           <ul className="list-inline big-spacer-top measures-chart-indent">
index bdd2188c4df8acae713b2d21d5e7ec91510f28af..f59e996c96766395fd47b7d2aee0b64cbbc11616 100644 (file)
@@ -24,10 +24,10 @@ export default React.createClass({
               <Donut data={donutData} size="47"/>
             </div>
             <div className="measure measure-big" data-metric="duplicated_lines_density">
+              <span className="measure-name">{window.t('overview.metric.duplications')}</span>
               <span className="measure-value">
                 <MeasureVariation value={density} type="PERCENT"/>
               </span>
-              <span className="measure-name">{window.t('overview.metric.duplications')}</span>
             </div>
           </div>
           <ul className="list-inline big-spacer-top measures-chart-indent">
index fc33b7c3065665959ae55eb99b92d9021e10ecb2..29574509109f684798d9107669bb061319a21746 100644 (file)
@@ -16,28 +16,28 @@ export default React.createClass({
         blockerIssues = this.props.leak.newBlockerIssues,
         criticalIssues = this.props.leak.newCriticalIssues,
         issuesToReview = this.props.leak.newOpenIssues + this.props.leak.newReopenedIssues,
-        periodDate = moment(getPeriodDate(this.props.component.periods, '3')).format('YYYY-MM-DDTHH:mm:ssZZ');
+        periodDate = moment(getPeriodDate(this.props.component.periods, '1')).format('YYYY-MM-DDTHH:mm:ssZZ');
 
     return (
         <Card>
           <div className="measures">
             <div className="measure measure-big" data-metric="sqale_index">
+              <span className="measure-name">{window.t('overview.metric.new_debt')}</span>
               <span className="measure-value">
                 <IssuesLink component={this.props.component.key}
                             params={{ resolved: 'false', createdAfter: periodDate, facetMode: 'debt' }}>
                   <Measure value={newDebt} type="SHORT_WORK_DUR"/>
                 </IssuesLink>
               </span>
-              <span className="measure-name">{window.t('overview.metric.new_debt')}</span>
             </div>
             <div className="measure measure-big" data-metric="violations">
+              <span className="measure-name">{window.t('overview.metric.new_issues')}</span>
               <span className="measure-value">
                 <IssuesLink component={this.props.component.key}
                             params={{ resolved: 'false', createdAfter: periodDate }}>
                   <Measure value={issues} type="SHORT_INT"/>
                 </IssuesLink>
               </span>
-              <span className="measure-name">{window.t('overview.metric.new_issues')}</span>
             </div>
           </div>
           <ul className="list-inline big-spacer-top">
index 771623743121425a32308dab1fe6cb33d2073b48..5b09ddf0eed7f4ffad748d82b8e038f326e5fe08 100644 (file)
@@ -12,16 +12,16 @@ export default React.createClass({
         <Card>
           <div className="measures">
             <div className="measure measure-big" data-metric="lines">
+              <span className="measure-name">{window.t('overview.metric.lines')}</span>
               <span className="measure-value">
                 <MeasureVariation value={lines} type="SHORT_INT"/>
               </span>
-              <span className="measure-name">{window.t('overview.metric.lines')}</span>
             </div>
             <div className="measure measure-big" data-metric="files">
+              <span className="measure-name">{window.t('overview.metric.files')}</span>
               <span className="measure-value">
                 <MeasureVariation value={files} type="SHORT_INT"/>
               </span>
-              <span className="measure-name">{window.t('overview.metric.files')}</span>
             </div>
           </div>
         </Card>
index 20db93ff6c3657d1ea04c679b4d47a5c9636f1d1..1cef6139954c0deba50b9441a7a482ad7b4970b7 100644 (file)
@@ -1,25 +1,29 @@
 import _ from 'underscore';
+import moment from 'moment';
 import React from 'react';
+
 import Cards from './cards';
 import LeakIssues from './leak-issues';
 import LeakCoverage from './leak-coverage';
 import LeakSize from './leak-size';
 import LeakDups from './leak-dups';
-import {periodLabel} from './../helpers/period-label';
+import { periodLabel, getPeriodDate } from './../helpers/period-label';
+
 
 export default React.createClass({
   render() {
-    if (_.size(this.props.component.periods) < 3) {
+    if (_.size(this.props.component.periods) < 1) {
       return null;
     }
 
-    let period = periodLabel(this.props.component.periods, '3');
+    let period = periodLabel(this.props.component.periods, '1');
+    let periodDate = getPeriodDate(this.props.component.periods, '1');
 
     return (
         <div className="overview-leak">
           <h2 className="overview-title">
             {window.t('overview.water_leak')}
-            <span className="overview-leak-period">{period}</span>
+            <span className="overview-leak-period">{period} / {moment(periodDate).format('LL')}</span>
           </h2>
           <Cards>
             <LeakIssues component={this.props.component} leak={this.props.leak} measures={this.props.measures}/>
index a55eacf2d1d9bab488e63ffb1b102d6dff979c36..fc0cc1a1199ca46070491d12d2b56e57a83d7baa 100644 (file)
@@ -22,7 +22,7 @@ export default React.createClass({
   },
 
   _hasWaterLeak() {
-    return !!_.findWhere(this.props.component.periods, { index: '3' });
+    return !!_.findWhere(this.props.component.periods, { index: '1' });
   },
 
   _requestIssues(data) {
@@ -33,7 +33,7 @@ export default React.createClass({
   },
 
   requestLeakIssues() {
-    let createdAfter = moment(getPeriodDate(this.props.component.periods, '3')).format('YYYY-MM-DDTHH:mm:ssZZ');
+    let createdAfter = moment(getPeriodDate(this.props.component.periods, '1')).format('YYYY-MM-DDTHH:mm:ssZZ');
     this._requestIssues({ resolved: 'false', createdAfter, facets: 'severities,statuses' }).done(r => {
       let
           severitiesFacet = _.findWhere(r.facets, { property: 'severities' }).values,
@@ -70,7 +70,7 @@ export default React.createClass({
   },
 
   requestLeakDebt() {
-    let createdAfter = moment(getPeriodDate(this.props.component.periods, '3')).format('YYYY-MM-DDTHH:mm:ssZZ');
+    let createdAfter = moment(getPeriodDate(this.props.component.periods, '1')).format('YYYY-MM-DDTHH:mm:ssZZ');
     this._requestIssues({ resolved: 'false', createdAfter, facets: 'severities', facetMode: 'debt' }).done(r => {
       this.setState({
         leak: _.extend({}, this.state.leak, { newDebt: r.debtTotal })
index d7cbec6055366584121f392f66569fe7d5ece6d9..20d8444d7981e13a25e950972df4f609760266b9 100644 (file)
@@ -27,12 +27,12 @@ export default React.createClass({
               <Donut data={donutData} size="47"/>
             </div>
             <div className="measure measure-big">
+              <span className="measure-name">{window.t('overview.metric.coverage')}</span>
               <span className="measure-value">
                 <DrilldownLink component={this.props.component.key} metric="overall_coverage">
                   <Measure value={coverage} type="PERCENT"/>
                 </DrilldownLink>
               </span>
-              <span className="measure-name">{window.t('overview.metric.coverage')}</span>
             </div>
           </div>
           <ul className="list-inline big-spacer-top measures-chart-indent">
index 92594c6c6ab9c184d22ea12a98c8d9fb7fa10be5..277d1662dacdc86b527c0b7858e29f407ebead64 100644 (file)
@@ -27,12 +27,12 @@ export default React.createClass({
               <Donut data={donutData} size="47"/>
             </div>
             <div className="measure measure-big">
+              <span className="measure-name">{window.t('overview.metric.duplications')}</span>
               <span className="measure-value">
                 <DrilldownLink component={this.props.component.key} metric="duplicated_lines_density">
                   <Measure value={density} type="PERCENT"/>
                 </DrilldownLink>
               </span>
-              <span className="measure-name">{window.t('overview.metric.duplications')}</span>
             </div>
           </div>
           <ul className="list-inline big-spacer-top measures-chart-indent">
index 8856bac3a3b229b5feb6ca69e31d0c90f3e988c9..2d72a7d024397c1b453be06df69592abbdccfac4 100644 (file)
@@ -28,20 +28,20 @@ export default React.createClass({
               </DrilldownLink>
             </div>
             <div className="measure measure-big" data-metric="sqale_index">
+              <span className="measure-name">{window.t('overview.metric.debt')}</span>
               <span className="measure-value">
                 <IssuesLink component={this.props.component.key} params={{ resolved: 'false', facetMode: 'debt' }}>
                   <Measure value={debt} type="SHORT_WORK_DUR"/>
                 </IssuesLink>
               </span>
-              <span className="measure-name">{window.t('overview.metric.debt')}</span>
             </div>
             <div className="measure measure-big" data-metric="violations">
+              <span className="measure-name">{window.t('overview.metric.issues')}</span>
               <span className="measure-value">
                 <IssuesLink component={this.props.component.key} params={{ resolved: 'false' }}>
                   <Measure value={issues} type="SHORT_INT"/>
                 </IssuesLink>
               </span>
-              <span className="measure-name">{window.t('overview.metric.issues')}</span>
             </div>
           </div>
           <ul className="list-inline big-spacer-top">
index 967f752fb88840bbd2f9de8824daf0a4c85f9d26..e1136d228bb15a34a27ac2abbcd225ddd373a572 100644 (file)
@@ -15,20 +15,20 @@ export default React.createClass({
         <Card linkTo="size" active={active} onRoute={this.props.onRoute}>
           <div className="measures">
             <div className="measure measure-big" data-metric="lines">
+              <span className="measure-name">{window.t('overview.metric.lines')}</span>
               <span className="measure-value">
                 <DrilldownLink component={this.props.component.key} metric="lines">
                   <Measure value={lines} type="SHORT_INT"/>
                 </DrilldownLink>
               </span>
-              <span className="measure-name">{window.t('overview.metric.lines')}</span>
             </div>
             <div className="measure measure-big" data-metric="files">
+              <span className="measure-name">{window.t('overview.metric.files')}</span>
               <span className="measure-value">
                 <DrilldownLink component={this.props.component.key} metric="files">
                   <Measure value={files} type="SHORT_INT"/>
                 </DrilldownLink>
               </span>
-              <span className="measure-name">{window.t('overview.metric.files')}</span>
             </div>
           </div>
         </Card>
index f2111487d3fd3b16caca9f90d0d0ea75cb6a66de..aa7ba34cb607ef41db27948ca312425b7c565bbb 100644 (file)
@@ -10,30 +10,48 @@ import Meta from './meta';
 
 import { getMetrics } from '../../api/metrics';
 
-export default class Overview extends React.Component {
-  constructor () {
-    super();
+
+export const Overview = React.createClass({
+  getInitialState () {
     let hash = window.location.hash;
-    this.state = { section: hash.length ? hash.substr(1) : null };
-  }
+    return { section: hash.length ? hash.substr(1) : null };
+  },
+
+  componentWillMount () {
+    window.addEventListener('hashchange', this.handleHashChange);
+  },
 
   componentDidMount () {
     this.requestMetrics();
-  }
+  },
+
+  componentWillUnmount () {
+    window.removeEventListener('hashchange', this.handleHashChange);
+  },
 
   requestMetrics () {
     return getMetrics().then(metrics => this.setState({ metrics }));
-  }
+  },
 
   handleRoute (section, el) {
-    this.setState({ section }, () => this.scrollToEl(el));
-    window.location.href = '#' + section;
-  }
+    if (section !== this.state.section) {
+      this.setState({ section }, () => this.scrollToEl(el));
+      window.location.href = '#' + section;
+    } else {
+      this.setState({ section: null });
+      window.location.href = '#';
+    }
+  },
+
+  handleHashChange () {
+    let hash = window.location.hash;
+    this.setState({ section: hash.substr(1) });
+  },
 
   scrollToEl (el) {
     let top = offset(el).top - el.getBoundingClientRect().height;
     window.scrollTo(0, top);
-  }
+  },
 
   render () {
     if (!this.state.metrics) {
@@ -60,10 +78,10 @@ export default class Overview extends React.Component {
 
     return <div className="overview">
       <div className="overview-main">
-        <GeneralMain {...this.props} section={this.state.section} onRoute={this.handleRoute.bind(this)}/>
+        <GeneralMain {...this.props} section={this.state.section} onRoute={this.handleRoute}/>
         {child}
       </div>
       <Meta component={this.props.component}/>
     </div>;
   }
-}
+});
index 51b140e003d797d529de24ab377c96d0ba640417..9e311a838e37c6793ccb850f1ffe58546029214f 100644 (file)
@@ -55,9 +55,10 @@ export const TreemapRect = React.createClass({
       fontSize: SIZE_SCALE(this.props.width / this.props.label.length),
       lineHeight: `${this.props.height}px`
     };
+    let isTextVisible = this.props.width >= 40 && this.props.height >= 40;
     return <div className="treemap-cell" {...tooltipAttrs} style={cellStyles}>
       <div className="treemap-inner" dangerouslySetInnerHTML={{ __html: this.props.label }}
-           style={{ maxWidth: this.props.width }}/>
+           style={{ maxWidth: this.props.width, visibility: isTextVisible ? 'visible': 'hidden' }}/>
     </div>;
   }
 });
@@ -89,7 +90,8 @@ export const Treemap = React.createClass({
                     .size([this.state.width, 360]);
     let nodes = treemap
         .nodes({ children: this.props.items })
-        .filter(d => !d.children);
+        .filter(d => !d.children)
+        .filter(d => !!d.dx && !!d.dy);
 
     let prefix = mostCommitPrefix(this.props.items.map(item => item.label)),
         prefixLength = prefix.length;
index 9b43ba81fdfb6a486a0f6cd9a0995d4c15c39a83..4798e0df32bf56f9da973e2373d8b1bfb0650614 100644 (file)
@@ -17,7 +17,7 @@
 
 .overview-gate {
   .clearfix;
-  padding: 50px 30px;
+  padding: 50px 0 25px;
 }
 
 .overview-gate-box {
   margin-top: 8px;
   font-weight: 300;
   font-size: 22px;
-
-  i {
-    position: relative;
-    top: -1px;
-  }
 }
 
 .overview-gate-condition-itself {
 }
 
 .overview-leak {
-  padding: 50px 30px;
+  padding: 50px 0 25px;
   border-top: 1px solid @barBorderColor;
   border-bottom: 1px solid @barBorderColor;
 }
 
 .overview-title {
-  margin-bottom: 20px;
+  padding: 0 30px;
   font-size: 18px;
   font-weight: 400;
 
 }
 
 .overview-nutshell {
-  padding: 50px 30px 0;
-
-  .overview-card {
-    padding-bottom: 25px;
-  }
+  padding: 50px 0 0;
 }
 
 .overview-cards {
 
 .overview-card {
   flex: 1 0 25%;
+  padding: 25px 30px;
   box-sizing: border-box;
 
   .overview-gate & {
     margin-left: 30px;
   }
 
+  .measure-big .measure-name {
+    margin-top: 0;
+    margin-bottom: 2px;
+  }
+
   .list-inline {
     margin-left: -10px;
     margin-right: -10px;
 }
 
 .overview-card-section {
+  position: relative;
+  z-index: 100;
   cursor: pointer;
 
   &:hover, &.active {
-    border-bottom: 4px solid #2c3946;
+    &:before {
+      position: absolute;
+      top: 100%;
+      left: 50%;
+      margin-left: -10px;
+      width: 0;
+      height: 0;
+      border: solid transparent;
+      border-width: 10px;
+      border-top-color: #fff;
+      content: '';
+      pointer-events: none;
+    }
   }
 }
 
 
 .overview-meta {
   width: 240px;
-  padding: 50px 30px;
   border-left: 1px solid @barBorderColor;
   box-sizing: border-box;
   background-color: @barBackgroundColor;
 
 .overview-meta .overview-card {
   width: auto;
-  margin-bottom: 30px;
 }
 
 .overview-meta-description {
 
 .overview-domain-section {
   padding: 50px 30px;
+
+  .overview-title {
+    margin-bottom: 25px;
+    padding-left: 0;
+    padding-right: 0;
+  }
 }
 
 .overview-domain-header {
index 41fe87144015a93f4218d11ed123ddf41bae28da..c86e998a5181837ab071bbb624ece0f6579c04aa 100644 (file)
         <% if @snapshot %>
         // coverage
         <% if @snapshot.measure('new_overall_coverage') %>
-        newCoverage: '<%= @snapshot.measure('new_overall_coverage').variation(3) -%>',
+        newCoverage: '<%= @snapshot.measure('new_overall_coverage').variation(1) -%>',
         <% end %>
         <% if @snapshot.measure('tests') %>
-        tests: '<%= @snapshot.measure('tests').variation(3) -%>',
+        tests: '<%= @snapshot.measure('tests').variation(1) -%>',
         <% end %>
 
         // duplications
-        duplications: '<%= @snapshot.measure('duplicated_lines_density').variation(3) -%>',
-        duplicatedLines: '<%= @snapshot.measure('duplicated_lines').variation(3) -%>',
-        duplicatedBlocks: '<%= @snapshot.measure('duplicated_blocks').variation(3) -%>',
+        duplications: '<%= @snapshot.measure('duplicated_lines_density').variation(1) -%>',
+        duplicatedLines: '<%= @snapshot.measure('duplicated_lines').variation(1) -%>',
+        duplicatedBlocks: '<%= @snapshot.measure('duplicated_blocks').variation(1) -%>',
 
         // size
-        lines: '<%= @snapshot.measure('lines').variation(3) -%>',
-        files: '<%= @snapshot.measure('files').variation(3) -%>'
+        lines: '<%= @snapshot.measure('lines').variation(1) -%>',
+        files: '<%= @snapshot.measure('files').variation(1) -%>'
         <% end %>
       };