]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6210 add a rule description in the workspace
authorStas Vilchik <vilchiks@gmail.com>
Fri, 17 Apr 2015 15:21:04 +0000 (17:21 +0200)
committerStas Vilchik <vilchiks@gmail.com>
Fri, 17 Apr 2015 15:21:23 +0000 (17:21 +0200)
15 files changed:
server/sonar-web/src/main/coffee/issue/issue-view.coffee
server/sonar-web/src/main/coffee/issue/views/rule-overlay.coffee [deleted file]
server/sonar-web/src/main/hbs/issue/issue-rule.hbs [deleted file]
server/sonar-web/src/main/hbs/workspace/workspace-item.hbs
server/sonar-web/src/main/hbs/workspace/workspace-rule.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/workspace/workspace-viewer-header.hbs
server/sonar-web/src/main/js/common/handlebars-extensions.js
server/sonar-web/src/main/js/workspace/main.js
server/sonar-web/src/main/js/workspace/views/base-viewer-view.js [new file with mode: 0644]
server/sonar-web/src/main/js/workspace/views/rule-view.js [new file with mode: 0644]
server/sonar-web/src/main/js/workspace/views/viewer-view.js
server/sonar-web/src/test/js/issues-page-spec.js
server/sonar-web/src/test/js/workspace.js
server/sonar-web/src/test/json/issues-spec/rule.json [new file with mode: 0644]
server/sonar-web/src/test/json/workspace/rule.json [new file with mode: 0644]

index 457f0cffd59100055dc5c2fbfb6e41e044af9ef9..bb2ea79d86b31bcba717ce1ee7d7225faee0535d 100644 (file)
@@ -32,9 +32,10 @@ define [
   'issue/views/plan-form-view'
   'issue/views/set-severity-form-view'
   'issue/views/more-actions-view'
-  'issue/views/rule-overlay'
   'issue/views/tags-form-view'
 
+  'workspace/main'
+
   'templates/issue'
 
 ], (
@@ -51,9 +52,10 @@ define [
   PlanFormView
   SetSeverityFormView
   MoreActionsView
-  RuleOverlay
   TagsFormView
 
+  Workspace
+
 ) ->
 
   $ = jQuery
@@ -261,12 +263,10 @@ define [
 
 
     showRule: ->
+      unless Workspace?
+        Workspace = require 'workspace/main'
       ruleKey = @model.get 'rule'
-      $.get "#{baseUrl}/api/rules/show", key: ruleKey, (r) =>
-        ruleOverlay = new RuleOverlay
-          model: new Backbone.Model r.rule
-          large: true
-        ruleOverlay.render()
+      Workspace.openRule key: ruleKey
 
 
     editTags: (e)->
diff --git a/server/sonar-web/src/main/coffee/issue/views/rule-overlay.coffee b/server/sonar-web/src/main/coffee/issue/views/rule-overlay.coffee
deleted file mode 100644 (file)
index c4dbc5a..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-#
-# SonarQube, open source software quality management tool.
-# Copyright (C) 2008-2014 SonarSource
-# mailto:contact AT sonarsource DOT com
-#
-# SonarQube 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.
-#
-# SonarQube 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.
-#
-
-define [
-  'common/modals'
-  'templates/issue'
-], (
-  ModalView
-) ->
-
-  class extends ModalView
-    template: Templates['issue-rule']
-
-
-    serializeData: ->
-      _.extend super,
-        permalink: "#{baseUrl}/coding_rules#rule_key=#{encodeURIComponent @model.get('key')}"
-        allTags: _.union @model.get('sysTags'), @model.get('tags')
diff --git a/server/sonar-web/src/main/hbs/issue/issue-rule.hbs b/server/sonar-web/src/main/hbs/issue/issue-rule.hbs
deleted file mode 100644 (file)
index 2e11a62..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-<div class="modal-container">
-  <h3 class="coding-rules-detail-header">
-    {{name}}
-    <a class="coding-rules-detail-permalink" target="_blank" href="{{permalink}}">
-      <i class="icon-link"></i> {{t 'coding_rules.permalink'}}
-    </a>
-  </h3>
-
-  <span class="note">{{key}}</span>
-
-  <ul class="coding-rules-detail-properties">
-    <li class="coding-rules-detail-property coding-rules-detail-tag-list">
-      <i class="icon-tags"></i>
-      <span>{{#if allTags}}{{join allTags ', '}}{{else}}{{t 'coding_rules.no_tags'}}{{/if}}</span>
-    </li>
-    {{#if debtCharName}}
-      <li class="coding-rules-detail-property">{{debtCharName}}{{#if debtSubCharName}} > {{debtSubCharName}}{{/if}}</li>
-    {{/if}}
-  </ul>
-
-  <div class="coding-rules-detail-description rule-desc markdown">{{{htmlDesc}}}</div>
-
-  {{#if htmlNote}}
-    <div id="coding-rules-detail-description-extra">
-      <div class="rule-desc markdown">{{{htmlNote}}}</div>
-    </div>
-  {{/if}}
-</div>
-
-<div class="modal-foot">
-  <a class="js-modal-close" href="#">{{t 'close'}}</a>
-</div>
index 24cf2862541a9d8bda79c44c3210062970150c89..a4fb7a98661bc4e4be8b96c7b3bca06718658828 100644 (file)
@@ -2,6 +2,6 @@
   {{qualifierIcon q}}
 {{/if}}
 
-{{default name uuid}}
+{{limitString name}}
 
 <button class="js-close button-clean" style="color: #fff;">&times;</button>
diff --git a/server/sonar-web/src/main/hbs/workspace/workspace-rule.hbs b/server/sonar-web/src/main/hbs/workspace/workspace-rule.hbs
new file mode 100644 (file)
index 0000000..acdf149
--- /dev/null
@@ -0,0 +1,25 @@
+<div class="workspace-viewer-header"></div>
+
+<div class="workspace-viewer-container">
+
+  <ul class="coding-rules-detail-properties">
+    <li class="coding-rules-detail-property coding-rules-detail-tag-list">
+      <i class="icon-tags"></i>
+      <span>{{#if allTags}}{{join allTags ', '}}{{else}}{{t 'coding_rules.no_tags'}}{{/if}}</span>
+    </li>
+    {{#if debtCharName}}
+      <li class="coding-rules-detail-property">{{debtCharName}}{{#if debtSubCharName}} > {{debtSubCharName}}{{/if}}</li>
+    {{/if}}
+    <li class="pull-right">
+      <a class="icon-link" target="_blank" href="{{rulePermalink key}}"></a>
+    </li>
+  </ul>
+
+  <div class="coding-rules-detail-description rule-desc markdown">{{{htmlDesc}}}</div>
+
+  {{#if htmlNote}}
+    <div id="coding-rules-detail-description-extra">
+      <div class="rule-desc markdown">{{{htmlNote}}}</div>
+    </div>
+  {{/if}}
+</div>
index c6546fa7fd66ec7e266e92868828e82f57020481..ef4971f6077b1bdf8b5dea7f0514f91517140e5e 100644 (file)
@@ -1,4 +1,4 @@
-<h6 class="workspace-viewer-name">{{qualifierIcon q}}&nbsp;{{name}}</h6>
+<h6 class="workspace-viewer-name">{{#if q}}{{qualifierIcon q}}&nbsp;{{/if}}{{name}}</h6>
 
 <div class="workspace-viewer-resize js-resize"></div>
 
index 158cf1ac898e9f9ba7f53425cbd75543dce16e9e..83826c5de35cd33921d89cc5cc320636ab0031f8 100644 (file)
   });
 
   Handlebars.registerHelper('limitString', function (str) {
-    var LIMIT = 30;
-    return str.length > LIMIT ? str.substr(0, LIMIT) + '...' : str;
+    if (typeof str === 'string') {
+      var LIMIT = 30;
+      return str.length > LIMIT ? str.substr(0, LIMIT) + '...' : str;
+    }
   });
 
   Handlebars.registerHelper('withSign', function (number) {
index a68efff25ba9c309bac277e4e34a870f3309085b..594f8e783c2cb2feacbd0602e85cbc94ae15de2d 100644 (file)
@@ -21,8 +21,9 @@ define([
   'workspace/models/item',
   'workspace/models/items',
   'workspace/views/items-view',
-  'workspace/views/viewer-view'
-], function (Item, Items, ItemsView, ViewerView) {
+  'workspace/views/viewer-view',
+  'workspace/views/rule-view'
+], function (Item, Items, ItemsView, ViewerView, RuleView) {
 
   var $ = jQuery,
 
@@ -56,10 +57,6 @@ define([
       this.items.save();
     },
 
-    load: function () {
-      this.items.load();
-    },
-
     addComponent: function (model) {
       if (!this.items.has(model)) {
         this.items.add(model);
@@ -76,21 +73,26 @@ define([
       if (model.isComponent()) {
         this.showComponentViewer(model);
       }
+      if (model.isRule()) {
+        this.showRule(model);
+      }
     },
 
     openComponent: function (options) {
       return this.open(_.extend(options, { type: 'component' }));
     },
 
-    showComponentViewer: function (model) {
+    openRule: function (options) {
+      return this.open(_.extend(options, { type: 'rule' }));
+    },
+
+    showViewer: function (Viewer, model) {
       var that = this;
       if (this.viewerView != null) {
         this.viewerView.close();
       }
       $('.source-viewer').addClass('with-workspace');
-      this.viewerView = new ViewerView({
-        model: model
-      });
+      this.viewerView = new Viewer({ model: model });
       this.viewerView
           .on('viewerMinimize', function () {
             that.closeComponentViewer();
@@ -102,11 +104,28 @@ define([
       this.viewerView.render().$el.appendTo(document.body);
     },
 
+    showComponentViewer: function (model) {
+      this.showViewer(ViewerView, model);
+    },
+
     closeComponentViewer: function () {
       if (this.viewerView != null) {
         this.viewerView.close();
         $('.with-workspace').removeClass('with-workspace');
       }
+    },
+
+    showRule: function (model) {
+      this.showViewer(RuleView, model);
+      this.fetchRule(model);
+    },
+
+    fetchRule: function (model) {
+      var url = baseUrl + '/api/rules/show',
+          options = { key: model.get('key') };
+      return $.get(url, options).done(function (r) {
+        model.set(r.rule);
+      });
     }
   };
 
diff --git a/server/sonar-web/src/main/js/workspace/views/base-viewer-view.js b/server/sonar-web/src/main/js/workspace/views/base-viewer-view.js
new file mode 100644 (file)
index 0000000..20396a7
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.
+ */
+define([
+  'workspace/views/viewer-header-view'
+], function (HeaderView) {
+
+  return Marionette.Layout.extend({
+    className: 'workspace-viewer',
+
+    modelEvents: {
+      'destroy': 'close'
+    },
+
+    regions: {
+      headerRegion: '.workspace-viewer-header',
+      viewerRegion: '.workspace-viewer-container'
+    },
+
+    onRender: function () {
+      this.showHeader();
+      this.$('.workspace-viewer-container').isolatedScroll();
+    },
+
+    onViewerMinimize: function () {
+      this.trigger('viewerMinimize');
+    },
+
+    onViewerClose: function () {
+      this.trigger('viewerClose', this.model);
+    },
+
+    showHeader: function () {
+      var headerView = new HeaderView({ model: this.model });
+      this.listenTo(headerView, 'viewerMinimize', this.onViewerMinimize);
+      this.listenTo(headerView, 'viewerClose', this.onViewerClose);
+      this.headerRegion.show(headerView);
+    }
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/workspace/views/rule-view.js b/server/sonar-web/src/main/js/workspace/views/rule-view.js
new file mode 100644 (file)
index 0000000..f362600
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.
+ */
+define([
+  'workspace/views/base-viewer-view',
+  'templates/workspace'
+], function (BaseView) {
+
+  return BaseView.extend({
+    template: Templates['workspace-rule'],
+
+    modelEvents: {
+      'destroy': 'close',
+      'change': 'render'
+    },
+
+    serializeData: function () {
+     return _.extend(Marionette.Layout.prototype.serializeData.apply(this, arguments), {
+       allTags: _.union(this.model.get('sysTags'), this.model.get('tags'))
+     });
+    }
+  });
+
+});
index d294a56a83c700da3c584190b47e3cd38f477632..171186f617974c54d8c21940492d02cc1ce42b20 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 define([
-  'workspace/views/viewer-header-view',
+  'workspace/views/base-viewer-view',
   'source-viewer/viewer',
   'templates/workspace'
-], function (HeaderView, SourceViewer) {
+], function (BaseView, SourceViewer) {
 
-  return Marionette.Layout.extend({
-    className: 'workspace-viewer',
+  return BaseView.extend({
     template: Templates['workspace-viewer'],
 
-    modelEvents: {
-      'destroy': 'close'
-    },
-
-    regions: {
-      headerRegion: '.workspace-viewer-header',
-      viewerRegion: '.workspace-viewer-container'
-    },
-
     onRender: function () {
-      this.showHeader();
+      BaseView.prototype.onRender.apply(this, arguments);
       this.showViewer();
-      this.$('.workspace-viewer-container').isolatedScroll();
-    },
-
-    onViewerMinimize: function () {
-      this.trigger('viewerMinimize');
-    },
-
-    onViewerClose: function () {
-      this.trigger('viewerClose', this.model);
-    },
-
-    showHeader: function () {
-      var headerView = new HeaderView({ model: this.model });
-      this.listenTo(headerView, 'viewerMinimize', this.onViewerMinimize);
-      this.listenTo(headerView, 'viewerClose', this.onViewerClose);
-      this.headerRegion.show(headerView);
     },
 
     showViewer: function () {
index aadd4db0ae195faca84021eb74ff7347f4486113..8928665588385ac9fd4d2befe6d429385c15136f 100644 (file)
@@ -234,6 +234,48 @@ casper.test.begin(testName('Issue Box', 'Transitions'), function (test) {
 });
 
 
+casper.test.begin(testName('Issue Box', 'Rule'), function (test) {
+  casper
+      .start(lib.buildUrl('issues'), function () {
+        lib.setDefaultViewport();
+
+
+        lib.mockRequestFromFile('/api/issue_filters/app', 'app.json');
+        lib.mockRequestFromFile('/api/issues/search', 'search.json');
+        lib.mockRequestFromFile('/api/rules/show', 'rule.json');
+      })
+
+      .then(function () {
+        casper.evaluate(function () {
+          require(['/js/issues/app-new.js']);
+        });
+      })
+
+      .then(function () {
+        casper.waitForSelector('.issue.selected');
+      })
+
+      .then(function () {
+        casper.click('.issue.selected .js-issue-rule');
+        casper.waitForSelector('.workspace-viewer-container .coding-rules-detail-properties');
+      })
+
+      .then(function () {
+        test.assertSelectorContains('.workspace-viewer-name', 'Insufficient branch coverage by unit tests');
+        test.assertSelectorContains('.workspace-viewer-container', 'Reliability > Unit tests coverage');
+        test.assertSelectorContains('.workspace-viewer-container', 'An issue is created on a file as soon as the');
+      })
+
+      .then(function () {
+        lib.sendCoverage();
+      })
+
+      .run(function () {
+        test.done();
+      });
+});
+
+
 casper.test.begin(testName('File-Level Issues'), function (test) {
   var issueKey = '200d4a8b-9666-4e70-9953-7bab57933f97',
       issueSelector = '.issue[data-key="' + issueKey + '"]';
index 35a9ef58026a930c19be6124c8969fdec664f6ef..47ce6bd383924ad617feede36a46c6c0733f6c0f 100644 (file)
@@ -286,3 +286,46 @@ casper.test.begin(testName('Full Screen'), 6, function (test) {
         test.done();
       });
 });
+
+
+casper.test.begin(testName('Rule'), 3, function (test) {
+  casper
+      .start(lib.buildUrl('nav'), function () {
+        lib.setDefaultViewport();
+
+        lib.mockRequestFromFile('/api/rules/show', 'rule.json');
+      })
+
+      .then(function () {
+        casper.evaluate(function () {
+          window.localStorage.setItem('sonarqube-workspace',
+              '[{"key":"common-java:InsufficientBranchCoverage","type":"rule"}]');
+          window.SS.isUserAdmin = false;
+          window.navbarOptions = new Backbone.Model();
+          require(['/js/nav/app.js']);
+        });
+      })
+
+      .then(function () {
+        casper.waitForSelector('.workspace-nav-item');
+      })
+
+      .then(function () {
+        casper.click('.workspace-nav-item');
+        casper.waitForSelector('.workspace-viewer .coding-rules-detail-properties');
+      })
+
+      .then(function () {
+        test.assertSelectorContains('.workspace-viewer-name', 'Insufficient branch coverage by unit tests');
+        test.assertSelectorContains('.workspace-viewer-container', 'Reliability > Unit tests coverage');
+        test.assertSelectorContains('.workspace-viewer-container', 'An issue is created on a file as soon as the');
+      })
+
+      .then(function () {
+        lib.sendCoverage();
+      })
+
+      .run(function () {
+        test.done();
+      });
+});
diff --git a/server/sonar-web/src/test/json/issues-spec/rule.json b/server/sonar-web/src/test/json/issues-spec/rule.json
new file mode 100644 (file)
index 0000000..f4abb0c
--- /dev/null
@@ -0,0 +1,36 @@
+{
+  "rule": {
+    "key": "common-java:InsufficientBranchCoverage",
+    "repo": "common-java",
+    "name": "Insufficient branch coverage by unit tests",
+    "createdAt": "2015-04-13T13:44:07+0200",
+    "severity": "MAJOR",
+    "status": "READY",
+    "internalKey": "InsufficientBranchCoverage",
+    "isTemplate": false,
+    "tags": [],
+    "sysTags": [],
+    "lang": "java",
+    "langName": "Java",
+    "htmlDesc": "<p>An issue is created on a file as soon as the branch coverage on this file is less than the required threshold.It gives the number of branches to be covered in order to reach the required threshold.</p>",
+    "defaultDebtChar": "RELIABILITY",
+    "defaultDebtSubChar": "UNIT_TESTS",
+    "debtChar": "RELIABILITY",
+    "debtSubChar": "UNIT_TESTS",
+    "debtCharName": "Reliability",
+    "debtSubCharName": "Unit tests coverage",
+    "defaultDebtRemFnType": "LINEAR",
+    "defaultDebtRemFnCoeff": "10min",
+    "debtOverloaded": false,
+    "debtRemFnType": "LINEAR",
+    "debtRemFnCoeff": "10min",
+    "params": [
+      {
+        "key": "minimumBranchCoverageRatio",
+        "htmlDesc": "The minimum required branch coverage ratio.",
+        "type": "STRING",
+        "defaultValue": "65.0"
+      }
+    ]
+  }
+}
diff --git a/server/sonar-web/src/test/json/workspace/rule.json b/server/sonar-web/src/test/json/workspace/rule.json
new file mode 100644 (file)
index 0000000..f4abb0c
--- /dev/null
@@ -0,0 +1,36 @@
+{
+  "rule": {
+    "key": "common-java:InsufficientBranchCoverage",
+    "repo": "common-java",
+    "name": "Insufficient branch coverage by unit tests",
+    "createdAt": "2015-04-13T13:44:07+0200",
+    "severity": "MAJOR",
+    "status": "READY",
+    "internalKey": "InsufficientBranchCoverage",
+    "isTemplate": false,
+    "tags": [],
+    "sysTags": [],
+    "lang": "java",
+    "langName": "Java",
+    "htmlDesc": "<p>An issue is created on a file as soon as the branch coverage on this file is less than the required threshold.It gives the number of branches to be covered in order to reach the required threshold.</p>",
+    "defaultDebtChar": "RELIABILITY",
+    "defaultDebtSubChar": "UNIT_TESTS",
+    "debtChar": "RELIABILITY",
+    "debtSubChar": "UNIT_TESTS",
+    "debtCharName": "Reliability",
+    "debtSubCharName": "Unit tests coverage",
+    "defaultDebtRemFnType": "LINEAR",
+    "defaultDebtRemFnCoeff": "10min",
+    "debtOverloaded": false,
+    "debtRemFnType": "LINEAR",
+    "debtRemFnCoeff": "10min",
+    "params": [
+      {
+        "key": "minimumBranchCoverageRatio",
+        "htmlDesc": "The minimum required branch coverage ratio.",
+        "type": "STRING",
+        "defaultValue": "65.0"
+      }
+    ]
+  }
+}