]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5718 Apply feedback
authorStas Vilchik <vilchiks@gmail.com>
Fri, 28 Nov 2014 15:20:06 +0000 (16:20 +0100)
committerStas Vilchik <vilchiks@gmail.com>
Fri, 28 Nov 2014 16:08:16 +0000 (17:08 +0100)
17 files changed:
server/sonar-web/src/main/coffee/issue/issue-view.coffee
server/sonar-web/src/main/coffee/issue/views/more-actions-view.coffee
server/sonar-web/src/main/coffee/issues/component-viewer/main.coffee
server/sonar-web/src/main/coffee/issues/controller.coffee
server/sonar-web/src/main/hbs/issue/issue-more-actions.hbs
server/sonar-web/src/main/hbs/issue/issue.hbs
server/sonar-web/src/main/hbs/issues/issues-workspace-header.hbs
server/sonar-web/src/main/hbs/source-viewer/source-viewer-coverage-popup.hbs
server/sonar-web/src/main/hbs/source-viewer/source-viewer-scm-popup.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/source-viewer/source-viewer.hbs
server/sonar-web/src/main/js/source-viewer/popups/coverage-popup.js
server/sonar-web/src/main/js/source-viewer/popups/duplication-popup.js
server/sonar-web/src/main/js/source-viewer/popups/scm-popup.js [new file with mode: 0644]
server/sonar-web/src/main/js/source-viewer/viewer.js
server/sonar-web/src/main/less/components/source.less
server/sonar-web/src/main/less/issues.less
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index 24ea55f22de7f0b40d3690b78266aa93f15141bb..a747345efd28e8cf94b146114700028b26dcb380 100644 (file)
@@ -252,3 +252,10 @@ define [
         ruleOverlay = new RuleOverlay
           model: new Backbone.Model r.rule
         ruleOverlay.render()
+
+
+    serializeData: ->
+      componentKey = encodeURIComponent @model.get 'component'
+      issueKey = encodeURIComponent @model.get 'key'
+      _.extend super,
+        permalink: "#{baseUrl}/component/index#component=#{componentKey}&currentIssue=#{issueKey}"
index 8322e90a61ccf7aa858e9cb9d608cf5a5b6c9b4f..19d3a72a68816c009c7012ab9181ff7a66ae471e 100644 (file)
@@ -6,8 +6,6 @@ define [
   PopupView
 ) ->
 
-  $ = jQuery
-
 
   class extends PopupView
     template: Templates['issue-more-actions']
@@ -20,10 +18,3 @@ define [
     action: (e) ->
       actionKey = $(e.currentTarget).data 'action'
       @options.detailView.action actionKey
-
-
-    serializeData: ->
-      componentKey = encodeURIComponent @model.get 'component'
-      issueKey = encodeURIComponent @model.get 'key'
-      _.extend super,
-        permalink: "#{baseUrl}/component/index#component=#{componentKey}&currentIssue=#{issueKey}"
index e3143ceebdd898991877821f31607a3e309810b8..098e878aa454783a3e1457175a3de06b76ab20b9 100644 (file)
@@ -157,7 +157,6 @@ define [
 
 
     requestIssues: ->
-      console.log 'Request issues'
       if @options.app.issues.last().get('component') == @model.get('key')
         r = @options.app.controller.fetchNextPage()
       else r = $.Deferred().resolve().promise()
@@ -165,7 +164,6 @@ define [
         @issues.reset @options.app.issues.filter (issue) => issue.get('component') == @model.key()
         @issues.reset @limitIssues @issues
         @addIssuesPerLineMeta @issues
-        console.log 'Issues loaded'
 
 
     renderIssue: (issue) ->
index 6d8d43b094f1fab8348f6790b9652a5ca378b450..1e2a5800e5890e707f521314dd2b6eadeda390fa 100644 (file)
@@ -210,6 +210,8 @@ define [
 
     closeComponentViewer: ->
       key.setScope 'list'
+      # close all popups
+      $('body').click()
       @options.app.state.unset 'component'
       @options.app.layout.workspaceComponentViewerRegion.reset()
       @options.app.layout.hideComponentViewer()
index 396ee6f6764ea57015f7277609fbdf1f95ac33f2..18917b5f9c18914f92afbd8eafd9246148f758a0 100644 (file)
@@ -1,7 +1,4 @@
 <ul class="issue-more-actions">
-  <li>
-    <a class="issue-action" target="_blank" href="{{permalink}}">Get Permalink</a>
-  </li>
   {{#pluginActions actions}}
     <li>
       <a class="issue-action js-issue-action" data-action="{{this}}">{{t "issue.action" this "formlink"}}</a>
index 96b761442aeb7acde74fc5baf4870ee80b44efff..bd0d07245500c33d4bab0aa8498c558e3201289e 100644 (file)
   <div class="issue-meta">
     {{#inArray actions "assign"}}
       <a class="issue-action issue-action-with-options js-issue-assign">
-        <span class="issue-meta-label">{{#if assignee}}{{default assigneeName assignee}}{{else}}{{t 'unassigned'}}{{/if}}</span>&nbsp;<i class="icon-dropdown"></i>
+        <span
+            class="issue-meta-label">{{#if assignee}}{{default assigneeName assignee}}{{else}}{{t 'unassigned'}}{{/if}}</span>&nbsp;<i
+          class="icon-dropdown"></i>
       </a>
     {{else}}
-      <span class="issue-meta-label">{{#if assignee}}{{default assigneeName assignee}}{{else}}{{t 'unassigned'}}{{/if}}</span>
+      <span
+          class="issue-meta-label">{{#if assignee}}{{default assigneeName assignee}}{{else}}{{t 'unassigned'}}{{/if}}</span>
     {{/inArray}}
   </div>
 
   <div class="issue-meta">
     {{#inArray actions "plan"}}
       <a class="issue-action issue-action-with-options js-issue-plan">
-        <span class="issue-meta-label">{{#if actionPlan}}{{default actionPlanName actionPlan}}{{else}}{{t 'issue.unplanned'}}{{/if}}</span>&nbsp;<i class="icon-dropdown"></i>
+        <span
+            class="issue-meta-label">{{#if actionPlan}}{{default actionPlanName actionPlan}}{{else}}{{t 'issue.unplanned'}}{{/if}}</span>&nbsp;<i
+          class="icon-dropdown"></i>
       </a>
     {{else}}
-      <span class="issue-meta-label">{{#if actionPlan}}{{default actionPlanName actionPlan}}{{else}}{{t 'issue.unplanned'}}{{/if}}</span>
+      <span
+          class="issue-meta-label">{{#if actionPlan}}{{default actionPlanName actionPlan}}{{else}}{{t 'issue.unplanned'}}{{/if}}</span>
     {{/inArray}}
   </div>
 
     </div>
   {{/inArray}}
 
-  <div class="issue-meta">
-    <a class="issue-action issue-action-with-options js-issue-more">
-      <span class="issue-meta-label">{{t 'more'}}</span>&nbsp;<i class="icon-dropdown"></i>
-    </a>
-  </div>
+  {{#ifHasExtraActions actions}}
+    <div class="issue-meta">
+      <a class="issue-action issue-action-with-options js-issue-more">
+        <span class="issue-meta-label">{{t 'more'}}</span>&nbsp;<i class="icon-dropdown"></i>
+      </a>
+    </div>
+  {{/ifHasExtraActions}}
 
   <div class="issue-meta issue-meta-on-right">
     <a class="issue-action issue-action-with-options js-issue-show-changelog" title="{{dt creationDate}}">
     <a class="issue-action js-issue-rule">Rule</a>
   </div>
 
-  {{#if line}}
-    <div class="issue-meta issue-meta-in-corner">
+
+  <div class="issue-meta issue-meta-in-corner">
+    {{#if line}}
       <span class="issue-meta-label">L{{line}}</span>
-    </div>
-  {{/if}}
+      &nbsp;&nbsp;
+    {{/if}}
+    <a class="issue-action js-issue-permalink icon-link" href="{{permalink}}" target="_blank"></a>
+  </div>
+
 </div>
 
 {{#notEmpty comments}}
index 91480af86e253149fe4a6e5bbac756448deecd8b..d693e1d1bb5f2ec4b87b736964ed3d9d06f376c8 100644 (file)
@@ -4,7 +4,7 @@
 
     {{#with state.component}}
       {{qualifierIcon 'TRK'}}&nbsp;<a href="{{dashboardUrl project}}" title="{{projectName}}">{{projectName}}</a>
-      /
+      &nbsp;&nbsp;
       {{qualifierIcon qualifier}}&nbsp;<a href="{{dashboardUrl key}}" title="{{name}}">{{name}}</a>
     {{/with}}
   {{else}}
index be7d99c755af4fdda90d1aedb729697bd6d8acc9..cea9ae48f3c5c6bfb297c7b60fc0f0c05858cda5 100644 (file)
@@ -1,5 +1,17 @@
 <div class="bubble-popup-container">
-  <div class="bubble-popup-title">{{t 'component_viewer.transition.coverage'}}</div>
+  <div class="bubble-popup-title">
+    {{#if row.lineHits}}
+      {{t 'source_viewer.covered'}}
+      {{#if row.conditions}}
+        ({{default row.coveredConditions 0}} of {{row.conditions}} {{t 'source_viewer.conditions'}})
+      {{/if}}
+    {{else}}
+      {{t 'source_viewer.not_covered'}}
+      {{#if row.conditions}}
+        ({{row.conditions}} {{t 'source_viewer.conditions'}})
+      {{/if}}
+    {{/if}}
+  </div>
 
   {{#each testFiles}}
     <div class="bubble-popup-section">
diff --git a/server/sonar-web/src/main/hbs/source-viewer/source-viewer-scm-popup.hbs b/server/sonar-web/src/main/hbs/source-viewer/source-viewer-scm-popup.hbs
new file mode 100644 (file)
index 0000000..9eef858
--- /dev/null
@@ -0,0 +1,13 @@
+<div class="bubble-popup-container">
+  <div class="bubble-popup-section">
+    {{scmAuthor}}
+  </div>
+  <div class="bubble-popup-section">
+    {{dt scmDate}}
+  </div>
+  <div class="bubble-popup-section">
+    {{scmRevision}}
+  </div>
+</div>
+
+<div class="bubble-popup-arrow"></div>
index 3d56acd24a29ea6c7f4b788544de0c859abcc043..2d1cd025d608b9ea6079a60d561bda24094a1966 100644 (file)
@@ -7,23 +7,24 @@
     <tr class="source-line {{#eq line 0}}{{#empty issues}}hidden{{/empty}}{{/eq}}">
       <td class="source-meta source-line-number" {{#if line}}data-line-number="{{line}}"{{/if}}></td>
 
-      <td class="source-meta source-line-scm">
+      <td class="source-meta source-line-scm" {{#if line}}data-line-number="{{line}}"{{/if}}>
         {{#ifSCMChanged2 ../source line}}
           <div class="source-line-scm-inner" title="{{scmAuthor}} {{scmDate}}" data-author="{{scmAuthor}}"></div>
         {{/ifSCMChanged2}}
       </td>
 
-      <td class="source-meta source-line-coverage {{#notNull covered}}source-line-{{covered}}{{/notNull}}"
+      <td class="source-meta source-line-coverage {{#notNull coverageStatus}}source-line-{{coverageStatus}}{{/notNull}}"
           data-line-number="{{line}}">
         <div class="source-line-bar"></div>
       </td>
 
-      <td class="source-meta source-line-duplications {{#if duplicated}}source-line-duplicated{{/if}}">
+      <td class="source-meta source-line-duplications {{#if duplicated}}source-line-duplicated{{/if}}"
+          title="{{t 'source_viewer.expand_duplications'}}">
         <div class="source-line-bar"></div>
       </td>
 
       {{#each duplications}}
-        <td class="source-meta source-line-duplications-extra hidden {{#if this}}source-line-duplicated{{/if}}"
+        <td class="source-meta source-line-duplications-extra {{#if this}}source-line-duplicated{{/if}}"
             data-index="{{this}}" data-line-number="{{line}}">
           <div class="source-line-bar"></div>
         </td>
index de6e419937d6a7e6019ce8aa12aa0b780d456895..c4ca335d0660f7dc55a6cdf431c8b80229c203af 100644 (file)
@@ -2,8 +2,7 @@ define([
   'backbone.marionette',
   'templates/source-viewer',
   'common/popup',
-  'component-viewer/utils'
-], function (Marionette, Templates, Popup, utils) {
+], function (Marionette, Templates, Popup) {
 
   var $ = jQuery;
 
@@ -36,7 +35,10 @@ define([
               tests: testSet
             };
           });
-      return { testFiles: testFiles };
+      return {
+        testFiles: testFiles,
+        row: this.options.row
+      };
     }
   });
 });
index b0677415c136b55e2d4f6781d64bf9b01ab37d93..3dc6ef6a715dd53814242da589c09ed1c48ce256 100644 (file)
@@ -1,7 +1,7 @@
 define([
   'backbone.marionette',
   'templates/component-viewer',
-  'common/popup',
+  'common/popup'
 ], function (Marionette, Templates, Popup) {
 
   var $ = jQuery;
diff --git a/server/sonar-web/src/main/js/source-viewer/popups/scm-popup.js b/server/sonar-web/src/main/js/source-viewer/popups/scm-popup.js
new file mode 100644 (file)
index 0000000..c727c79
--- /dev/null
@@ -0,0 +1,23 @@
+define([
+  'backbone.marionette',
+  'templates/source-viewer',
+  'common/popup',
+], function (Marionette, Templates, Popup) {
+
+  return Popup.extend({
+    template: Templates['source-viewer-scm-popup'],
+
+    events: {
+      'click': 'onClick'
+    },
+
+    onRender: function () {
+      Popup.prototype.onRender.apply(this, arguments);
+      this.$('.bubble-popup-container').isolatedScroll();
+    },
+
+    onClick: function (e) {
+      e.stopPropagation();
+    }
+  });
+});
index 491a14b5527bddd64d245d532517d50dabf50184..48c319431120d8ce67418e6e9cd9b521b922a6e7 100644 (file)
@@ -6,6 +6,7 @@ define([
       'issue/models/issue',
       'issue/collections/issues',
       'issue/issue-view',
+      'source-viewer/popups/scm-popup',
       'source-viewer/popups/coverage-popup',
       'source-viewer/popups/duplication-popup',
       'source-viewer/popups/line-actions-popup'
@@ -17,15 +18,13 @@ define([
               Issue,
               Issues,
               IssueView,
+              SCMPopupView,
               CoveragePopupView,
               DuplicationPopupView,
               LineActionsPopupView) {
 
       var $ = jQuery,
-          HIGHLIGHTED_ROW_CLASS = 'source-line-highlighted',
-          log = function (message) {
-            return console.log('Source Viewer:', message);
-          };
+          HIGHLIGHTED_ROW_CLASS = 'source-line-highlighted';
 
       return Marionette.ItemView.extend({
         className: 'source',
@@ -42,8 +41,10 @@ define([
 
         events: function () {
           return {
+            'click .source-line-scm': 'showSCMPopup',
             'click .source-line-covered': 'showCoveragePopup',
             'click .source-line-partially-covered': 'showCoveragePopup',
+            'click .source-line-uncovered': 'showCoveragePopup',
             'click .source-line-duplications': 'showDuplications',
             'click .source-line-duplications-extra': 'showDuplicationPopup',
             'click .source-line-number[data-line-number]': 'highlightLine'
@@ -62,7 +63,6 @@ define([
         },
 
         onRender: function () {
-          log('Render');
           this.renderIssues();
         },
 
@@ -83,12 +83,10 @@ define([
           this.requestComponent().done(function () {
             that.requestSource()
                 .done(function () {
-                  that.requestCoverage().done(function () {
-                    that.requestDuplications().done(function () {
-                      that.requestIssues().done(function () {
-                        that.render();
-                        that.trigger('loaded');
-                      });
+                  that.requestDuplications().done(function () {
+                    that.requestIssues().done(function () {
+                      that.render();
+                      that.trigger('loaded');
                     });
                   });
                 })
@@ -108,7 +106,6 @@ define([
         },
 
         requestComponent: function () {
-          log('Request component details...');
           var that = this,
               url = baseUrl + '/api/components/app',
               options = { key: this.model.key() };
@@ -124,57 +121,43 @@ define([
           };
         },
 
+        getCoverageStatus: function (row) {
+          var status = null;
+          if (row.lineHits > 0) {
+            status = 'partially-covered';
+          }
+          if (row.lineHits > 0 && row.conditions === row.coveredConditions) {
+            status = 'covered';
+          }
+          if (row.lineHits === 0 || row.coveredConditions === 0) {
+            status = 'uncovered';
+          }
+          return status;
+        },
+
         requestSource: function () {
-          log('Request source...');
           var that = this,
               url = baseUrl + '/api/sources/lines',
               options = _.extend({ uuid: this.model.id }, this.linesLimit());
           return $.get(url, options, function (data) {
-            var source = data.sources || [];
+            var source = (data.sources || []).slice(0);
             if (source.length === 0 || (source.length > 0 && _.first(source).line === 1)) {
               source.unshift({ line: 0 });
             }
-            var firstLine = _.first(source).line;
+            source = source.map(function (row) {
+              return _.extend(row, { coverageStatus: that.getCoverageStatus(row) });
+            });
+            var firstLine = _.first(source).line,
+                linesRequested = options.to - options.from + 1;
             that.model.set({
               source: source,
               hasSourceBefore: firstLine > 1,
-              hasSourceAfter: true
+              hasSourceAfter: data.sources.length === linesRequested
             });
-            log('Source loaded');
-          });
-        },
-
-        requestCoverage: function () {
-          log('Request coverage');
-          var that = this,
-              url = baseUrl + '/api/coverage/show',
-              options = { key: this.model.key() };
-          return $.get(url, options, function (data) {
-            var hasCoverage = (data != null) && (data.coverage != null),
-                coverage = [];
-            that.model.set({ hasCoverage: hasCoverage });
-            if (hasCoverage) {
-              coverage = data.coverage.map(function (c) {
-                var status = 'partially-covered';
-                if (c[1] && c[3] === c[4]) {
-                  status = 'covered';
-                }
-                if (!c[1] || c[4] === 0) {
-                  status = 'uncovered';
-                }
-                return {
-                  line: +c[0],
-                  covered: status
-                };
-              });
-            }
-            that.model.addMeta(coverage);
-            log('Coverage loaded');
           });
         },
 
         requestDuplications: function () {
-          log('Request duplications');
           var that = this,
               url = baseUrl + '/api/duplications/show',
               options = { key: this.model.key() };
@@ -207,12 +190,10 @@ define([
               duplications: data.duplications,
               duplicationFiles: data.files
             });
-            log('Duplications loaded');
           });
         },
 
         requestIssues: function () {
-          log('Request issues');
           var that = this,
               options = {
                 data: {
@@ -226,7 +207,6 @@ define([
           return this.issues.fetch(options).done(function () {
             that.issues.reset(that.limitIssues(that.issues));
             that.addIssuesPerLineMeta(that.issues);
-            log('Issues loaded');
           });
         },
 
@@ -253,9 +233,7 @@ define([
         },
 
         renderIssues: function () {
-          log('Render issues');
           this.issues.forEach(this.renderIssue, this);
-          log('Issues rendered');
         },
 
         renderIssue: function (issue) {
@@ -279,11 +257,24 @@ define([
           this.renderIssue(issue);
         },
 
+        showSCMPopup: function (e) {
+          e.stopPropagation();
+          $('body').click();
+          var line = +$(e.currentTarget).data('line-number'),
+              row = _.findWhere(this.model.get('source'), { line: line }),
+              popup = new SCMPopupView({
+                triggerEl: $(e.currentTarget),
+                model: new Backbone.Model(row)
+              });
+          popup.render();
+        },
+
         showCoveragePopup: function (e) {
           e.stopPropagation();
           $('body').click();
           var r = window.process.addBackgroundProcess(),
               line = $(e.currentTarget).data('line-number'),
+              row = _.findWhere(this.model.get('source'), { line: line }),
               url = baseUrl + '/api/tests/test_cases',
               options = {
                 key: this.model.key(),
@@ -292,6 +283,7 @@ define([
           return $.get(url, options).done(function (data) {
             var popup = new CoveragePopupView({
               model: new Backbone.Model(data),
+              row: row,
               triggerEl: $(e.currentTarget)
             });
             popup.render();
@@ -302,8 +294,7 @@ define([
         },
 
         showDuplications: function () {
-          this.$('.source-line-duplications').addClass('hidden');
-          this.$('.source-line-duplications-extra').removeClass('hidden');
+          this.$el.addClass('source-duplications-expanded');
         },
 
         showDuplicationPopup: function (e) {
index 7ef086a2aaab33a50f44dcbabc379e5386314624..32d1e8001b022fbcb83f947e08d44a2352ef905d 100644 (file)
   background-color: @barBackgroundColor;
 }
 
+.source-line-duplications-extra {
+  display: none;
+}
+
+.source-duplications-expanded {
+  .source-line-duplications {
+    display: none;
+  }
+
+  .source-line-duplications-extra {
+    display: table-cell;
+  }
+}
+
 .source-line-scm {
   padding: 0 5px;
   background-color: @barBackgroundColor;
+
+  &[data-line-number] {
+    cursor: pointer;
+  }
 }
 
 .source-line-scm-inner {
 
 .source-line-uncovered {
   background-color: @red !important;
+  cursor: pointer;
 }
 
 .source-line-partially-covered {
index 17b29cb0e4580e3e24b593b21ac2d4940be1b456..2948a304938c97d8d369c6bd04971cb260278d9f 100644 (file)
 .issues-workspace-list-more {
   margin-top: 10px;
   padding: 5px 10px;
-  border: 1px solid @barBorderColor;
-  background: @barBackgroundColor;
   text-align: center;
 }
 
index 24fd83f4fb7897eec6004ffaef8ff175f0781e7c..c9f037488859a14207560db73ee3ba3c7f2e03de 100644 (file)
@@ -2765,6 +2765,11 @@ component_viewer.workspace.tooltip=Keeps track of history of navigation
 component_viewer.workspace.show_workspace=Show workspace
 component_viewer.workspace.hide_workspace=Hide workspace
 
+source_viewer.covered=Covered
+source_viewer.not_covered=Not covered
+source_viewer.conditions=conditions
+source_viewer.expand_duplications=Click to display more in details all the duplicated blocks of this file
+
 
 #------------------------------------------------------------------------------
 #