'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'
], (
PlanFormView
SetSeverityFormView
MoreActionsView
- RuleOverlay
TagsFormView
+ Workspace
+
) ->
$ = jQuery
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)->
+++ /dev/null
-#
-# 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')
+++ /dev/null
-<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>
{{qualifierIcon q}}
{{/if}}
-{{default name uuid}}
+{{limitString name}}
<button class="js-close button-clean" style="color: #fff;">×</button>
--- /dev/null
+<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>
-<h6 class="workspace-viewer-name">{{qualifierIcon q}} {{name}}</h6>
+<h6 class="workspace-viewer-name">{{#if q}}{{qualifierIcon q}} {{/if}}{{name}}</h6>
<div class="workspace-viewer-resize js-resize"></div>
});
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) {
'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,
this.items.save();
},
- load: function () {
- this.items.load();
- },
-
addComponent: function (model) {
if (!this.items.has(model)) {
this.items.add(model);
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();
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);
+ });
}
};
--- /dev/null
+/*
+ * 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);
+ }
+ });
+
+});
--- /dev/null
+/*
+ * 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'))
+ });
+ }
+ });
+
+});
* 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 () {
});
+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 + '"]';
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();
+ });
+});
--- /dev/null
+{
+ "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"
+ }
+ ]
+ }
+}
--- /dev/null
+{
+ "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"
+ }
+ ]
+ }
+}