aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-server/src
diff options
context:
space:
mode:
authorStas Vilchik <vilchiks@gmail.com>2014-03-06 17:36:10 +0100
committerStas Vilchik <vilchiks@gmail.com>2014-03-06 17:36:17 +0100
commitc12eff0418cb450cf97d387a3fc599b189302927 (patch)
treec9f1971fe6a32a6ffab628a6153cb2ec9142f7d9 /sonar-server/src
parentfac55bf34a7a4bc24b4a5864a3ff6ff44a8431de (diff)
downloadsonarqube-c12eff0418cb450cf97d387a3fc599b189302927.tar.gz
sonarqube-c12eff0418cb450cf97d387a3fc599b189302927.zip
SONAR-5007 Add first POC
Diffstat (limited to 'sonar-server/src')
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/controllers/coding_rules_controller.rb30
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/models/navigation.rb1
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/index.html.erb18
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_actions_template.hbs.erb7
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_detail_template.hbs.erb38
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_filter_bar_template.hbs.erb4
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_header_template.hbs.erb7
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_layout.hbs.erb7
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_list_empty_template.hbs.erb3
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_list_item_template.hbs.erb4
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/issues/templates/_no_issues.hbs.erb4
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_head.html.erb1
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb3
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/navigator/templates/_more_criteria_filter_template.hbs.erb2
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/index.html.erb2
-rw-r--r--sonar-server/src/main/webapp/javascripts/coding-rules/app.coffee277
-rw-r--r--sonar-server/src/main/webapp/javascripts/coding-rules/app.js244
-rw-r--r--sonar-server/src/main/webapp/javascripts/coding-rules/collections/coding-rules.coffee19
-rw-r--r--sonar-server/src/main/webapp/javascripts/coding-rules/collections/coding-rules.js32
-rw-r--r--sonar-server/src/main/webapp/javascripts/coding-rules/layout.coffee28
-rw-r--r--sonar-server/src/main/webapp/javascripts/coding-rules/layout.js43
-rw-r--r--sonar-server/src/main/webapp/javascripts/coding-rules/mockjax.coffee135
-rw-r--r--sonar-server/src/main/webapp/javascripts/coding-rules/mockjax.js122
-rw-r--r--sonar-server/src/main/webapp/javascripts/coding-rules/models/coding-rule.coffee16
-rw-r--r--sonar-server/src/main/webapp/javascripts/coding-rules/models/coding-rule.js36
-rw-r--r--sonar-server/src/main/webapp/javascripts/coding-rules/router.coffee46
-rw-r--r--sonar-server/src/main/webapp/javascripts/coding-rules/router.js76
-rw-r--r--sonar-server/src/main/webapp/javascripts/coding-rules/views/actions-view.coffee18
-rw-r--r--sonar-server/src/main/webapp/javascripts/coding-rules/views/actions-view.js33
-rw-r--r--sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-detail-view.coffee9
-rw-r--r--sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-detail-view.js23
-rw-r--r--sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-list-empty-view.coffee11
-rw-r--r--sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-list-empty-view.js27
-rw-r--r--sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-list-item-view.coffee27
-rw-r--r--sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-list-item-view.js47
-rw-r--r--sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-list-view.coffee23
-rw-r--r--sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-list-view.js40
-rw-r--r--sonar-server/src/main/webapp/javascripts/coding-rules/views/filter-bar-view.coffee67
-rw-r--r--sonar-server/src/main/webapp/javascripts/coding-rules/views/filter-bar-view.js100
-rw-r--r--sonar-server/src/main/webapp/javascripts/coding-rules/views/filters/quality-profile-filter-view.coffee19
-rw-r--r--sonar-server/src/main/webapp/javascripts/coding-rules/views/filters/quality-profile-filter-view.js41
-rw-r--r--sonar-server/src/main/webapp/javascripts/coding-rules/views/header-view.coffee9
-rw-r--r--sonar-server/src/main/webapp/javascripts/coding-rules/views/header-view.js23
-rw-r--r--sonar-server/src/main/webapp/javascripts/issues/extra.js2
-rw-r--r--sonar-server/src/main/webapp/javascripts/navigator/filters/ajax-select-filters.js7
-rw-r--r--sonar-server/src/main/webapp/javascripts/navigator/filters/choice-filters.js2
-rw-r--r--sonar-server/src/main/webapp/javascripts/navigator/filters/filter-bar.js16
-rw-r--r--sonar-server/src/main/webapp/javascripts/quality-gate/app.coffee8
-rw-r--r--sonar-server/src/main/webapp/javascripts/quality-gate/app.js8
-rw-r--r--sonar-server/src/main/webapp/javascripts/quality-gate/layout.coffee2
-rw-r--r--sonar-server/src/main/webapp/javascripts/quality-gate/layout.js2
-rw-r--r--sonar-server/src/main/webapp/javascripts/tests/translateSpec.coffee5
-rw-r--r--sonar-server/src/main/webapp/javascripts/tests/translateSpec.js6
-rw-r--r--sonar-server/src/main/webapp/javascripts/third-party/jquery.mockjax.js598
-rw-r--r--sonar-server/src/main/webapp/javascripts/translate.js22
-rw-r--r--sonar-server/src/main/webapp/stylesheets/coding-rules.css67
-rw-r--r--sonar-server/src/main/webapp/stylesheets/coding-rules.less82
-rw-r--r--sonar-server/src/main/webapp/stylesheets/navigator.css15
-rw-r--r--sonar-server/src/main/webapp/stylesheets/navigator/base.css15
-rw-r--r--sonar-server/src/main/webapp/stylesheets/navigator/base.less18
-rw-r--r--sonar-server/src/main/webapp/stylesheets/quality-gates.css329
-rw-r--r--sonar-server/src/main/webapp/stylesheets/quality-gates.less6
-rw-r--r--sonar-server/src/main/webapp/stylesheets/variables.less1
63 files changed, 2557 insertions, 376 deletions
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/coding_rules_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/coding_rules_controller.rb
new file mode 100644
index 00000000000..c06947b9349
--- /dev/null
+++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/coding_rules_controller.rb
@@ -0,0 +1,30 @@
+#
+# SonarQube, open source software quality management tool.
+# Copyright (C) 2008-2013 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.
+#
+
+class CodingRulesController < ApplicationController
+
+ SECTION=Navigation::SECTION_CODING_RULES
+
+ # GET /coding_rules/index
+ def index
+
+ end
+
+end
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/navigation.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/navigation.rb
index 5dc495bdc29..22c1ae1e64a 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/models/navigation.rb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/models/navigation.rb
@@ -35,4 +35,5 @@ class Navigation
SECTION_MEASURES = Navigation.new('measures', false)
SECTION_QUALITY_PROFILES = Navigation.new('quality_profiles', false)
SECTION_QUALITY_GATES = Navigation.new('quality_gates', false)
+ SECTION_CODING_RULES = Navigation.new('coding_rules', false)
end
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/index.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/index.html.erb
new file mode 100644
index 00000000000..e5bb24f38a9
--- /dev/null
+++ b/sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/index.html.erb
@@ -0,0 +1,18 @@
+<% content_for :script do %>
+ <script data-main="<%= ApplicationController.root_context -%>/javascripts/coding-rules/app" src="<%= ApplicationController.root_context -%>/javascripts/third-party/require.js"></script>
+<% end %>
+
+
+<div id="coding-rules-page-loader" class="navigator-page-loader">
+ <i class="spinner"></i>
+</div>
+
+
+<%= render :partial => '/navigator/filter_templates' -%>
+<%= render :partial => '/coding_rules/templates/coding_rules_layout.hbs' -%>
+<%= render :partial => '/coding_rules/templates/coding_rules_header_template.hbs' -%>
+<%= render :partial => '/coding_rules/templates/coding_rules_actions_template.hbs' -%>
+<%= render :partial => '/coding_rules/templates/coding_rules_filter_bar_template.hbs' -%>
+<%= render :partial => '/coding_rules/templates/coding_rules_list_item_template.hbs' -%>
+<%= render :partial => '/coding_rules/templates/coding_rules_list_empty_template.hbs' -%>
+<%= render :partial => '/coding_rules/templates/coding_rules_detail_template.hbs' -%>
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_actions_template.hbs.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_actions_template.hbs.erb
new file mode 100644
index 00000000000..3cea3eb051c
--- /dev/null
+++ b/sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_actions_template.hbs.erb
@@ -0,0 +1,7 @@
+<script id="coding-rules-status-template" type="text/x-handlebars-template">
+ <div class="navigator-actions-total">
+ {{t 'coding_rules.found'}}: <strong>{{paging.fTotal}}</strong>
+ <a class="navigator-actions-bulk"
+ title="{{t 'bulk_change'}}"><i class="icon-settings-multiple"></i></a>
+ </div>
+</script>
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_detail_template.hbs.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_detail_template.hbs.erb
new file mode 100644
index 00000000000..18aad2a85ca
--- /dev/null
+++ b/sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_detail_template.hbs.erb
@@ -0,0 +1,38 @@
+<script id="coding-rules-detail-template" type="text/x-handlebars-template">
+ <h3 class="coding-rules-detail-header">{{name}}</h3>
+ <div class="coding-rules-detail-language">{{language}}</div>
+ <div class="coding-rules-detail-description rule-desc">{{{description}}}</div>
+
+ <h3 class="coding-rules-detail-header coding-rules-detail-quality-profiles-header">{{t 'coding_rules.quality_profiles'}}</h3>
+ <ul class="coding-rules-detail-quality-profiles">
+ {{#each qualityProfiles}}
+ <li class="coding-rules-detail-quality-profile">
+ <div class="coding-rules-detail-quality-profile-severity">{{severityIcon severity}}</div>
+ <div class="coding-rules-detail-quality-profile-name">{{name}}</div>
+ {{#if canDeactivate}}
+ <div class="button-group coding-rules-detail-quality-profile-actions">
+ <button class="button-red">{{t 'coding_rules.deactivate_quality_profile'}}</button>
+ </div>
+ {{/if}}
+ <ul class="coding-rules-detail-quality-profile-parameters">
+ {{#each parameters}}
+ <li class="coding-rules-detail-quality-profile-parameter">
+ {{#if ../canUpdate}}
+ <label class="coding-rules-detail-quality-profile-parameter-key">{{key}}</label>
+ <input class="coding-rules-detail-quality-profile-parameter-value" type="text" value="{{value}}">
+ <div class="button-group coding-rules-detail-quality-profile-parameter-actions">
+ <button class="coding-rules-detail-quality-profile-parameter-update">{{t 'update'}}</button>
+ </div>
+ {{else}}
+ {{key}}: {{value}}
+ {{/if}}
+ </li>
+ {{/each}}
+ </ul>
+ </li>
+ {{/each}}
+ </ul>
+ <div class="button-group coding-rules-detail-quality-profiles-activation">
+ <button>{{t 'coding_rules.activate_quality_profile'}}</button>
+ </div>
+</script>
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_filter_bar_template.hbs.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_filter_bar_template.hbs.erb
new file mode 100644
index 00000000000..9ca665e0121
--- /dev/null
+++ b/sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_filter_bar_template.hbs.erb
@@ -0,0 +1,4 @@
+<script id="filter-bar-template" type="text/x-handlebars-template">
+ <div class="navigator-filters-list"></div>
+ <button class="navigator-filter-submit">{{t 'search_verb'}}</button>
+</script>
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_header_template.hbs.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_header_template.hbs.erb
new file mode 100644
index 00000000000..bfee909e900
--- /dev/null
+++ b/sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_header_template.hbs.erb
@@ -0,0 +1,7 @@
+<script id="coding-rules-header-template" type="text/x-handlebars-template">
+ <h1 class="navigator-header-title">{{t 'coding_rules.page'}}</h1>
+
+ <div class="navigator-header-actions button-group">
+ <button id="issues-new-search">{{t 'coding_rules.new_search'}}</button>
+ </div>
+</script>
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_layout.hbs.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_layout.hbs.erb
new file mode 100644
index 00000000000..debdccc91f1
--- /dev/null
+++ b/sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_layout.hbs.erb
@@ -0,0 +1,7 @@
+<script id="coding-rules-layout" type="text/x-handlebars-template">
+ <div class="navigator-header"></div>
+ <div class="navigator-filters"></div>
+ <div class="navigator-actions"></div>
+ <div class="navigator-results"></div>
+ <div class="navigator-details"></div>
+</script>
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_list_empty_template.hbs.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_list_empty_template.hbs.erb
new file mode 100644
index 00000000000..011edf1776d
--- /dev/null
+++ b/sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_list_empty_template.hbs.erb
@@ -0,0 +1,3 @@
+<script id="coding-rules-list-empty-template" type="text/x-handlebars-template">
+ {{t 'coding_rules.no_results'}}
+</script>
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_list_item_template.hbs.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_list_item_template.hbs.erb
new file mode 100644
index 00000000000..82f12144bbe
--- /dev/null
+++ b/sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_list_item_template.hbs.erb
@@ -0,0 +1,4 @@
+<script id="coding-rules-list-item-template" type="text/x-handlebars-template">
+ <div class="line line-nowrap" title="{{name}}">{{name}}</div>
+ <div class="line line-small">{{language}}</div>
+</script>
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/issues/templates/_no_issues.hbs.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/templates/_no_issues.hbs.erb
index 34ac7da0457..fe956141c56 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/views/issues/templates/_no_issues.hbs.erb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/templates/_no_issues.hbs.erb
@@ -1,5 +1,3 @@
<script id="no-issues-template" type="text/x-handlebars-template">
- <div class="navigator-results-no-issues">
- <p><%= message('issue_filter.no_issues') -%></p>
- </div>
+ <%= message('issue_filter.no_issues') -%>
</script>
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_head.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_head.html.erb
index f1dc7f7d8be..92221785ae6 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_head.html.erb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_head.html.erb
@@ -37,6 +37,7 @@
<%= stylesheet_link_tag 'select-list', :media => 'all' %>
<%= stylesheet_link_tag 'navigator', :media => 'all' %>
<%= stylesheet_link_tag 'quality-gates', :media => 'all' %>
+ <%= stylesheet_link_tag 'coding-rules', :media => 'all' %>
<%= yield :style -%>
<%= javascript_include_tag 'third-party/jquery' %>
<%= javascript_include_tag 'third-party/jquery-ui' %>
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb
index 48e9b19095e..ecec918cc28 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb
@@ -25,6 +25,9 @@
<a href="<%= ApplicationController.root_context -%>/profiles" class="<%= 'selected' if selected_section==Navigation::SECTION_QUALITY_PROFILES -%>"><%= message('quality_profiles.page') -%></a>
</li>
<li>
+ <a href="<%= ApplicationController.root_context -%>/coding_rules" class="<%= 'selected' if selected_section==Navigation::SECTION_CODING_RULES -%>"><%= message('coding_rules.page') -%></a>
+ </li>
+ <li>
<a href="<%= ApplicationController.root_context -%>/quality_gates" class="<%= 'selected' if selected_section==Navigation::SECTION_QUALITY_GATES -%>"><%= message('quality_gates.page') -%></a>
</li>
</ul>
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/navigator/templates/_more_criteria_filter_template.hbs.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/navigator/templates/_more_criteria_filter_template.hbs.erb
index b2f7e3ffae1..c1159abf464 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/views/navigator/templates/_more_criteria_filter_template.hbs.erb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/views/navigator/templates/_more_criteria_filter_template.hbs.erb
@@ -1,3 +1,3 @@
<script id="more-criteria-filter-template" type="text/x-handlebars-template">
- {{translate "moreCriteria"}}
+ {{t "moreCriteria"}}
</script>
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/index.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/index.html.erb
index 5402dcae379..37251d2951d 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/index.html.erb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/index.html.erb
@@ -2,7 +2,7 @@
<script data-main="<%= ApplicationController.root_context -%>/javascripts/quality-gate/app" src="<%= ApplicationController.root_context -%>/javascripts/third-party/require.js"></script>
<% end %>
-<div class="quality-gate-page-loader">
+<div id="quality-gate-page-loader" class="navigator-page-loader">
<i class="spinner"></i>
</div>
diff --git a/sonar-server/src/main/webapp/javascripts/coding-rules/app.coffee b/sonar-server/src/main/webapp/javascripts/coding-rules/app.coffee
new file mode 100644
index 00000000000..81c81b65187
--- /dev/null
+++ b/sonar-server/src/main/webapp/javascripts/coding-rules/app.coffee
@@ -0,0 +1,277 @@
+requirejs.config
+ baseUrl: "#{baseUrl}/javascripts"
+
+ paths:
+ 'backbone': 'third-party/backbone'
+ 'backbone.marionette': 'third-party/backbone.marionette'
+ 'handlebars': 'third-party/handlebars'
+ 'jquery.mockjax': 'third-party/jquery.mockjax'
+
+ shim:
+ 'backbone.marionette':
+ deps: ['backbone']
+ exports: 'Marionette'
+ 'backbone':
+ exports: 'Backbone'
+ 'handlebars':
+ exports: 'Handlebars'
+
+
+requirejs [
+ 'backbone', 'backbone.marionette',
+
+ 'coding-rules/layout',
+ 'coding-rules/router',
+
+ # models & collections
+ 'coding-rules/collections/coding-rules',
+
+ # views
+ 'coding-rules/views/header-view',
+ 'coding-rules/views/actions-view',
+ 'coding-rules/views/filter-bar-view',
+ 'coding-rules/views/coding-rules-list-view',
+
+ # filters
+ 'navigator/filters/base-filters',
+ 'navigator/filters/choice-filters',
+ 'navigator/filters/string-filters',
+ 'coding-rules/views/filters/quality-profile-filter-view',
+
+ 'coding-rules/mockjax'
+], (
+ Backbone, Marionette,
+
+ CodingRulesLayout,
+ CodingRulesRouter,
+
+ # models & collections
+ CodingRules,
+
+ # views
+ CodingRulesHeaderView,
+ CodingRulesActionsView,
+ CodingRulesFilterBarView,
+ CodingRulesListView,
+
+ # filters
+ BaseFilters,
+ ChoiceFilters,
+ StringFilterView,
+ QualityProfileFilterView
+) ->
+
+ # Create a generic error handler for ajax requests
+ jQuery.ajaxSetup
+ error: (jqXHR) ->
+ text = jqXHR.responseText
+ errorBox = jQuery('.modal-error')
+ if jqXHR.responseJSON?.errors?
+ text = _.pluck(jqXHR.responseJSON.errors, 'msg').join '. '
+ if errorBox.length > 0
+ errorBox.show().text text
+ else
+ alert text
+
+
+ # Add html class to mark the page as navigator page
+ jQuery('html').addClass('navigator-page coding-rules-page');
+
+
+ # Create an Application
+ App = new Marionette.Application
+
+
+ App.getQuery = ->
+ @filterBarView.getQuery()
+
+
+ App.restoreSorting = ->
+
+
+
+ App.storeQuery = (query, sorting) ->
+ if sorting
+ _.extend query,
+ sort: sorting.sort
+ asc: '' + sorting.asc
+ queryString = _.map query, (v, k) -> "#{k}=#{encodeURIComponent(v)}"
+ @router.navigate queryString.join('|'), replace: true
+
+
+
+ App.fetchList = (firstPage) ->
+ query = @getQuery()
+ fetchQuery = _.extend { pageIndex: @pageIndex }, query
+
+ if @codingRules.sorting
+ _.extend fetchQuery,
+ sort: @codingRules.sorting.sort,
+ asc: @codingRules.sorting.asc
+
+ @storeQuery query, @codingRules.sorting
+
+ @layout.showSpinner 'resultsRegion'
+ @codingRules.fetch(data: fetchQuery, remove: !!firstPage).done =>
+ @codingRulesListView = new CodingRulesListView
+ app: @
+ collection: @codingRules
+ @layout.resultsRegion.show @codingRulesListView
+ @codingRulesListView.selectFirst()
+
+
+ App.fetchFirstPage = ->
+ @pageIndex = 1
+ App.fetchList true
+
+
+ App.fetchNextPage = ->
+ if @pageIndex < @codingRules.paging.pages
+ @pageIndex++
+ App.fetchList false
+
+
+ # Construct layout
+ App.addInitializer ->
+ @layout = new CodingRulesLayout app: @
+ jQuery('body').append @layout.render().el
+
+
+ # Construct header
+ App.addInitializer ->
+ @codingRulesHeaderView = new CodingRulesHeaderView app: @
+ @layout.headerRegion.show @codingRulesHeaderView
+
+
+ # Define coding rules
+ App.addInitializer ->
+ @codingRules = new CodingRules
+
+
+ # Construct status bar
+ App.addInitializer ->
+ @codingRulesActionsView = new CodingRulesActionsView
+ app: @
+ collection: @codingRules
+ @layout.actionsRegion.show @codingRulesActionsView
+
+
+ # Define filters
+ App.addInitializer ->
+ @filters = new BaseFilters.Filters
+
+ @filters.add new BaseFilters.Filter
+ name: t 'coding_rules.filters.name_key'
+ property: 'searchtext'
+ type: StringFilterView
+ enabled: true
+ optional: false
+
+ @filters.add new BaseFilters.Filter
+ name: t 'coding_rules.filters.repository'
+ property: 'repositories'
+ type: ChoiceFilters.ChoiceFilterView
+ enabled: true
+ optional: false
+ choices:
+ 'checkstyle': 'Checkstyle'
+ 'common-java': 'Common SonarQube'
+ 'findbugs': 'FindBugs'
+ 'pmd': 'PMD'
+ 'pmd-unit-tests': 'PMD Unit Tests'
+ 'squid': 'SonarQube'
+
+ @filters.add new BaseFilters.Filter
+ name: t 'coding_rules.filters.severity'
+ property: 'severities'
+ type: ChoiceFilters.ChoiceFilterView
+ enabled: true
+ optional: false
+ choices:
+ 'BLOCKER': t 'severity.BLOCKER'
+ 'CRITICAL': t 'severity.CRITICAL'
+ 'MAJOR': t 'severity.MAJOR'
+ 'MINOR': t 'severity.MINOR'
+ 'INFO': t 'severity.INFO'
+ choiceIcons:
+ 'BLOCKER': 'severity-blocker'
+ 'CRITICAL': 'severity-critical'
+ 'MAJOR': 'severity-major'
+ 'MINOR': 'severity-minor'
+ 'INFO': 'severity-info'
+
+ @filters.add new BaseFilters.Filter
+ name: t 'coding_rules.filters.status'
+ property: 'statuses'
+ type: ChoiceFilters.ChoiceFilterView
+ enabled: true
+ optional: false
+ choices:
+ 'BETA': 'Beta'
+ 'DEPRECATED': 'Deprecated'
+ 'READY': 'Ready'
+
+ @filters.add new BaseFilters.Filter
+ name: t 'coding_rules.filters.tag'
+ property: 'tags'
+ type: ChoiceFilters.ChoiceFilterView
+ enabled: true
+ optional: false
+ choices:
+ 'brain-overload': 'brain-overload'
+ 'bug': 'bug'
+ 'comment': 'comment'
+ 'convention': 'convention'
+ 'error-handling': 'error-handling'
+ 'formatting': 'formatting'
+ 'java8': 'java8'
+ 'multithreading': 'multithreading'
+ 'naming': 'naming'
+ 'pitfall': 'pitfall'
+ 'security': 'security'
+ 'size': 'size'
+ 'unused': 'unused'
+ 'unused-code': 'unused-code'
+
+ @filters.add new BaseFilters.Filter
+ name: t 'coding_rules.filters.active_in'
+ property: 'active_in'
+ type: QualityProfileFilterView
+ enabled: false,
+ optional: true
+
+ @filters.add new BaseFilters.Filter
+ name: t 'coding_rules.filters.inactive_in'
+ property: 'inactive_in'
+ type: QualityProfileFilterView
+ enabled: false,
+ optional: true
+
+ @filterBarView = new CodingRulesFilterBarView
+ app: @
+ collection: @filters,
+ extra: sort: '', asc: false
+ @layout.filtersRegion.show @filterBarView
+
+
+ # Start router
+ App.addInitializer ->
+ @router = new CodingRulesRouter app: @
+ Backbone.history.start()
+
+
+ # Call app before start the application
+ appXHR = jQuery.ajax
+ url: "#{baseUrl}/api/codingrules/app"
+
+ jQuery.when(appXHR)
+ .done (r) ->
+ App.appState = new Backbone.Model
+ App.state = new Backbone.Model
+ window.messages = r.messages
+
+ # Remove the initial spinner
+ jQuery('#coding-rules-page-loader').remove()
+
+ # Start the application
+ App.start()
diff --git a/sonar-server/src/main/webapp/javascripts/coding-rules/app.js b/sonar-server/src/main/webapp/javascripts/coding-rules/app.js
new file mode 100644
index 00000000000..4736322069f
--- /dev/null
+++ b/sonar-server/src/main/webapp/javascripts/coding-rules/app.js
@@ -0,0 +1,244 @@
+// Generated by CoffeeScript 1.6.3
+(function() {
+ requirejs.config({
+ baseUrl: "" + baseUrl + "/javascripts",
+ paths: {
+ 'backbone': 'third-party/backbone',
+ 'backbone.marionette': 'third-party/backbone.marionette',
+ 'handlebars': 'third-party/handlebars',
+ 'jquery.mockjax': 'third-party/jquery.mockjax'
+ },
+ shim: {
+ 'backbone.marionette': {
+ deps: ['backbone'],
+ exports: 'Marionette'
+ },
+ 'backbone': {
+ exports: 'Backbone'
+ },
+ 'handlebars': {
+ exports: 'Handlebars'
+ }
+ }
+ });
+
+ requirejs(['backbone', 'backbone.marionette', 'coding-rules/layout', 'coding-rules/router', 'coding-rules/collections/coding-rules', 'coding-rules/views/header-view', 'coding-rules/views/actions-view', 'coding-rules/views/filter-bar-view', 'coding-rules/views/coding-rules-list-view', 'navigator/filters/base-filters', 'navigator/filters/choice-filters', 'navigator/filters/string-filters', 'coding-rules/views/filters/quality-profile-filter-view', 'coding-rules/mockjax'], function(Backbone, Marionette, CodingRulesLayout, CodingRulesRouter, CodingRules, CodingRulesHeaderView, CodingRulesActionsView, CodingRulesFilterBarView, CodingRulesListView, BaseFilters, ChoiceFilters, StringFilterView, QualityProfileFilterView) {
+ var App, appXHR;
+ jQuery.ajaxSetup({
+ error: function(jqXHR) {
+ var errorBox, text, _ref;
+ text = jqXHR.responseText;
+ errorBox = jQuery('.modal-error');
+ if (((_ref = jqXHR.responseJSON) != null ? _ref.errors : void 0) != null) {
+ text = _.pluck(jqXHR.responseJSON.errors, 'msg').join('. ');
+ }
+ if (errorBox.length > 0) {
+ return errorBox.show().text(text);
+ } else {
+ return alert(text);
+ }
+ }
+ });
+ jQuery('html').addClass('navigator-page coding-rules-page');
+ App = new Marionette.Application;
+ App.getQuery = function() {
+ return this.filterBarView.getQuery();
+ };
+ App.restoreSorting = function() {};
+ App.storeQuery = function(query, sorting) {
+ var queryString;
+ if (sorting) {
+ _.extend(query, {
+ sort: sorting.sort,
+ asc: '' + sorting.asc
+ });
+ }
+ queryString = _.map(query, function(v, k) {
+ return "" + k + "=" + (encodeURIComponent(v));
+ });
+ return this.router.navigate(queryString.join('|'), {
+ replace: true
+ });
+ };
+ App.fetchList = function(firstPage) {
+ var fetchQuery, query,
+ _this = this;
+ query = this.getQuery();
+ fetchQuery = _.extend({
+ pageIndex: this.pageIndex
+ }, query);
+ if (this.codingRules.sorting) {
+ _.extend(fetchQuery, {
+ sort: this.codingRules.sorting.sort,
+ asc: this.codingRules.sorting.asc
+ });
+ }
+ this.storeQuery(query, this.codingRules.sorting);
+ this.layout.showSpinner('resultsRegion');
+ return this.codingRules.fetch({
+ data: fetchQuery,
+ remove: !!firstPage
+ }).done(function() {
+ _this.codingRulesListView = new CodingRulesListView({
+ app: _this,
+ collection: _this.codingRules
+ });
+ _this.layout.resultsRegion.show(_this.codingRulesListView);
+ return _this.codingRulesListView.selectFirst();
+ });
+ };
+ App.fetchFirstPage = function() {
+ this.pageIndex = 1;
+ return App.fetchList(true);
+ };
+ App.fetchNextPage = function() {
+ if (this.pageIndex < this.codingRules.paging.pages) {
+ this.pageIndex++;
+ return App.fetchList(false);
+ }
+ };
+ App.addInitializer(function() {
+ this.layout = new CodingRulesLayout({
+ app: this
+ });
+ return jQuery('body').append(this.layout.render().el);
+ });
+ App.addInitializer(function() {
+ this.codingRulesHeaderView = new CodingRulesHeaderView({
+ app: this
+ });
+ return this.layout.headerRegion.show(this.codingRulesHeaderView);
+ });
+ App.addInitializer(function() {
+ return this.codingRules = new CodingRules;
+ });
+ App.addInitializer(function() {
+ this.codingRulesActionsView = new CodingRulesActionsView({
+ app: this,
+ collection: this.codingRules
+ });
+ return this.layout.actionsRegion.show(this.codingRulesActionsView);
+ });
+ App.addInitializer(function() {
+ this.filters = new BaseFilters.Filters;
+ this.filters.add(new BaseFilters.Filter({
+ name: t('coding_rules.filters.name_key'),
+ property: 'searchtext',
+ type: StringFilterView,
+ enabled: true,
+ optional: false
+ }));
+ this.filters.add(new BaseFilters.Filter({
+ name: t('coding_rules.filters.repository'),
+ property: 'repositories',
+ type: ChoiceFilters.ChoiceFilterView,
+ enabled: true,
+ optional: false,
+ choices: {
+ 'checkstyle': 'Checkstyle',
+ 'common-java': 'Common SonarQube',
+ 'findbugs': 'FindBugs',
+ 'pmd': 'PMD',
+ 'pmd-unit-tests': 'PMD Unit Tests',
+ 'squid': 'SonarQube'
+ }
+ }));
+ this.filters.add(new BaseFilters.Filter({
+ name: t('coding_rules.filters.severity'),
+ property: 'severities',
+ type: ChoiceFilters.ChoiceFilterView,
+ enabled: true,
+ optional: false,
+ choices: {
+ 'BLOCKER': t('severity.BLOCKER'),
+ 'CRITICAL': t('severity.CRITICAL'),
+ 'MAJOR': t('severity.MAJOR'),
+ 'MINOR': t('severity.MINOR'),
+ 'INFO': t('severity.INFO')
+ },
+ choiceIcons: {
+ 'BLOCKER': 'severity-blocker',
+ 'CRITICAL': 'severity-critical',
+ 'MAJOR': 'severity-major',
+ 'MINOR': 'severity-minor',
+ 'INFO': 'severity-info'
+ }
+ }));
+ this.filters.add(new BaseFilters.Filter({
+ name: t('coding_rules.filters.status'),
+ property: 'statuses',
+ type: ChoiceFilters.ChoiceFilterView,
+ enabled: true,
+ optional: false,
+ choices: {
+ 'BETA': 'Beta',
+ 'DEPRECATED': 'Deprecated',
+ 'READY': 'Ready'
+ }
+ }));
+ this.filters.add(new BaseFilters.Filter({
+ name: t('coding_rules.filters.tag'),
+ property: 'tags',
+ type: ChoiceFilters.ChoiceFilterView,
+ enabled: true,
+ optional: false,
+ choices: {
+ 'brain-overload': 'brain-overload',
+ 'bug': 'bug',
+ 'comment': 'comment',
+ 'convention': 'convention',
+ 'error-handling': 'error-handling',
+ 'formatting': 'formatting',
+ 'java8': 'java8',
+ 'multithreading': 'multithreading',
+ 'naming': 'naming',
+ 'pitfall': 'pitfall',
+ 'security': 'security',
+ 'size': 'size',
+ 'unused': 'unused',
+ 'unused-code': 'unused-code'
+ }
+ }));
+ this.filters.add(new BaseFilters.Filter({
+ name: t('coding_rules.filters.active_in'),
+ property: 'active_in',
+ type: QualityProfileFilterView,
+ enabled: false,
+ optional: true
+ }));
+ this.filters.add(new BaseFilters.Filter({
+ name: t('coding_rules.filters.inactive_in'),
+ property: 'inactive_in',
+ type: QualityProfileFilterView,
+ enabled: false,
+ optional: true
+ }));
+ this.filterBarView = new CodingRulesFilterBarView({
+ app: this,
+ collection: this.filters,
+ extra: {
+ sort: '',
+ asc: false
+ }
+ });
+ return this.layout.filtersRegion.show(this.filterBarView);
+ });
+ App.addInitializer(function() {
+ this.router = new CodingRulesRouter({
+ app: this
+ });
+ return Backbone.history.start();
+ });
+ appXHR = jQuery.ajax({
+ url: "" + baseUrl + "/api/codingrules/app"
+ });
+ return jQuery.when(appXHR).done(function(r) {
+ App.appState = new Backbone.Model;
+ App.state = new Backbone.Model;
+ window.messages = r.messages;
+ jQuery('#coding-rules-page-loader').remove();
+ return App.start();
+ });
+ });
+
+}).call(this);
diff --git a/sonar-server/src/main/webapp/javascripts/coding-rules/collections/coding-rules.coffee b/sonar-server/src/main/webapp/javascripts/coding-rules/collections/coding-rules.coffee
new file mode 100644
index 00000000000..b24c7516c98
--- /dev/null
+++ b/sonar-server/src/main/webapp/javascripts/coding-rules/collections/coding-rules.coffee
@@ -0,0 +1,19 @@
+define [
+ 'backbone',
+ 'coding-rules/models/coding-rule'
+], (
+ Backbone,
+ CodingRule
+) ->
+
+ class CodingRules extends Backbone.Collection
+ model: CodingRule
+
+
+ url: ->
+ "#{baseUrl}/api/codingrules/search"
+
+
+ parse: (r) ->
+ @paging = r.paging
+ r.codingrules
diff --git a/sonar-server/src/main/webapp/javascripts/coding-rules/collections/coding-rules.js b/sonar-server/src/main/webapp/javascripts/coding-rules/collections/coding-rules.js
new file mode 100644
index 00000000000..14264ade1e7
--- /dev/null
+++ b/sonar-server/src/main/webapp/javascripts/coding-rules/collections/coding-rules.js
@@ -0,0 +1,32 @@
+// Generated by CoffeeScript 1.6.3
+(function() {
+ var __hasProp = {}.hasOwnProperty,
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
+
+ define(['backbone', 'coding-rules/models/coding-rule'], function(Backbone, CodingRule) {
+ var CodingRules, _ref;
+ return CodingRules = (function(_super) {
+ __extends(CodingRules, _super);
+
+ function CodingRules() {
+ _ref = CodingRules.__super__.constructor.apply(this, arguments);
+ return _ref;
+ }
+
+ CodingRules.prototype.model = CodingRule;
+
+ CodingRules.prototype.url = function() {
+ return "" + baseUrl + "/api/codingrules/search";
+ };
+
+ CodingRules.prototype.parse = function(r) {
+ this.paging = r.paging;
+ return r.codingrules;
+ };
+
+ return CodingRules;
+
+ })(Backbone.Collection);
+ });
+
+}).call(this);
diff --git a/sonar-server/src/main/webapp/javascripts/coding-rules/layout.coffee b/sonar-server/src/main/webapp/javascripts/coding-rules/layout.coffee
new file mode 100644
index 00000000000..0e3abd4cfd2
--- /dev/null
+++ b/sonar-server/src/main/webapp/javascripts/coding-rules/layout.coffee
@@ -0,0 +1,28 @@
+define [
+ 'backbone.marionette',
+ 'common/handlebars-extensions'
+], (
+ Marionette
+) ->
+
+ class AppLayout extends Marionette.Layout
+ className: 'navigator coding-rules-navigator'
+ template: getTemplate '#coding-rules-layout'
+ spinner: '<i class="spinner"></i>'
+
+
+ regions:
+ headerRegion: '.navigator-header'
+ actionsRegion: '.navigator-actions'
+ resultsRegion: '.navigator-results'
+ detailsRegion: '.navigator-details'
+ filtersRegion: '.navigator-filters'
+
+
+ onRender: ->
+ # Adjust details region height
+ @$(@detailsRegion.el).css 'bottom', jQuery('#footer').outerHeight()
+
+
+ showSpinner: (region) ->
+ @$(@[region].el).html @spinner
diff --git a/sonar-server/src/main/webapp/javascripts/coding-rules/layout.js b/sonar-server/src/main/webapp/javascripts/coding-rules/layout.js
new file mode 100644
index 00000000000..91d7c1067ee
--- /dev/null
+++ b/sonar-server/src/main/webapp/javascripts/coding-rules/layout.js
@@ -0,0 +1,43 @@
+// Generated by CoffeeScript 1.6.3
+(function() {
+ var __hasProp = {}.hasOwnProperty,
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
+
+ define(['backbone.marionette', 'common/handlebars-extensions'], function(Marionette) {
+ var AppLayout, _ref;
+ return AppLayout = (function(_super) {
+ __extends(AppLayout, _super);
+
+ function AppLayout() {
+ _ref = AppLayout.__super__.constructor.apply(this, arguments);
+ return _ref;
+ }
+
+ AppLayout.prototype.className = 'navigator coding-rules-navigator';
+
+ AppLayout.prototype.template = getTemplate('#coding-rules-layout');
+
+ AppLayout.prototype.spinner = '<i class="spinner"></i>';
+
+ AppLayout.prototype.regions = {
+ headerRegion: '.navigator-header',
+ actionsRegion: '.navigator-actions',
+ resultsRegion: '.navigator-results',
+ detailsRegion: '.navigator-details',
+ filtersRegion: '.navigator-filters'
+ };
+
+ AppLayout.prototype.onRender = function() {
+ return this.$(this.detailsRegion.el).css('bottom', jQuery('#footer').outerHeight());
+ };
+
+ AppLayout.prototype.showSpinner = function(region) {
+ return this.$(this[region].el).html(this.spinner);
+ };
+
+ return AppLayout;
+
+ })(Marionette.Layout);
+ });
+
+}).call(this);
diff --git a/sonar-server/src/main/webapp/javascripts/coding-rules/mockjax.coffee b/sonar-server/src/main/webapp/javascripts/coding-rules/mockjax.coffee
new file mode 100644
index 00000000000..efaaa42739e
--- /dev/null
+++ b/sonar-server/src/main/webapp/javascripts/coding-rules/mockjax.coffee
@@ -0,0 +1,135 @@
+define ['jquery.mockjax'], ->
+
+ jQuery.mockjaxSettings.contentType = 'text/json';
+ jQuery.mockjaxSettings.responseTime = 250;
+
+ # GET /api/codingrules/app
+ jQuery.mockjax
+ url: "#{baseUrl}/api/codingrules/app"
+ responseText: JSON.stringify
+ messages:
+ 'all': 'All'
+ 'bulk_change': 'Bulk Change'
+ 'moreCriteria': '+ More Criteria'
+ 'search_verb': 'Search'
+ 'update': 'Update'
+
+ 'severity.BLOCKER': 'Blocker'
+ 'severity.CRITICAL': 'Critical'
+ 'severity.MAJOR': 'Major'
+ 'severity.MINOR': 'Minor'
+ 'severity.INFO': 'Info'
+
+ 'coding_rules.page': 'Coding Rules'
+ 'coding_rules.new_search': 'New Search'
+ 'coding_rules.no_results': 'No Coding Rules'
+ 'coding_rules.found': 'Found'
+ 'coding_rules.quality_profiles': 'Quality Profiles'
+ 'coding_rules.activate_quality_profile': 'Activate Quality Profile'
+ 'coding_rules.deactivate_quality_profile': 'Deactivate'
+
+ 'coding_rules.filters.active_in': 'Active In'
+ 'coding_rules.filters.inactive_in': 'Inactive In'
+ 'coding_rules.filters.name_key': 'Name/Key'
+ 'coding_rules.filters.repository': 'Repository'
+ 'coding_rules.filters.severity': 'Severity'
+ 'coding_rules.filters.status': 'Status'
+ 'coding_rules.filters.tag': 'Tag'
+
+
+ # GET /api/codingrules/search
+ jQuery.mockjax
+ url: "#{baseUrl}/api/codingrules/search"
+ responseText: JSON.stringify
+ codingrules: [
+ {
+ name: 'Array designators "[]" should be located after the type in method signatures'
+ language: 'Java'
+ },
+ {
+ name: 'Avoid Array Loops'
+ language: 'Java'
+ },
+ {
+ name: 'Bad practice - Abstract class defines covariant compareTo() method'
+ language: 'Java'
+ },
+ {
+ name: 'Correctness - Use of class without a hashCode() method in a hashed data structure'
+ language: 'Java'
+ },
+ {
+ name: 'Useless Operation On Immutable'
+ language: 'Java'
+ }
+ ]
+ paging:
+ total: 5
+ fTotal: '5'
+
+
+ # GET /api/codingrules/show
+ jQuery.mockjax
+ url: "#{baseUrl}/api/codingrules/show"
+ responseText: JSON.stringify
+ codingrule:
+ name: 'Array designators "[]" should be located after the type in method signatures'
+ language: 'Java'
+ description: '''
+ <p>
+ According to the Java Language Specification:
+ </p>
+
+ <pre>For compatibility with older versions of the Java SE platform,
+ the declaration of a method that returns an array is allowed to place (some or all of) the empty bracket pairs that form the declaration of the array type after the formal parameter list.
+ This obsolescent syntax should not be used in new code.
+ </pre>
+
+ <p>The following code snippet illustrates this rule:</p>
+
+ <pre>public int getVector()[] { /* ... */ } // Non-Compliant
+
+ public int[] getVector() { /* ... */ } // Compliant
+
+ public int[] getMatrix()[] { /* ... */ } // Non-Compliant
+
+ public int[][] getMatrix() { /* ... */ } // Compliant
+ </pre>'''
+
+ qualityprofiles: [
+ {
+ name: 'SonarWay'
+ severity: 'MINOR'
+ canDeactivate: false
+ canUpdate: false
+ parameters: [
+ { key: 'max', value: 8 }
+ ]
+
+ },
+ {
+ name: 'Quality Profile 1'
+ severity: 'MAJOR'
+ canDeactivate: true
+ canUpdate: true
+ parameters: [
+ { key: 'max', value: 6 }
+ ]
+
+ }
+ ]
+
+
+
+ # GET /api/qualityprofiles/list
+ jQuery.mockjax
+ url: "#{baseUrl}/api/qualityprofiles/list"
+ responseText: JSON.stringify
+ more: false
+ results: [
+ { id: 'sonarway', text: 'Sonar Way' },
+ { id: 'qp1', text: 'Quality Profile 1' },
+ { id: 'qp2', text: 'Quality Profile 2' },
+ { id: 'qp3', text: 'Quality Profile 3' },
+ ]
+
diff --git a/sonar-server/src/main/webapp/javascripts/coding-rules/mockjax.js b/sonar-server/src/main/webapp/javascripts/coding-rules/mockjax.js
new file mode 100644
index 00000000000..26c8b1bdbe1
--- /dev/null
+++ b/sonar-server/src/main/webapp/javascripts/coding-rules/mockjax.js
@@ -0,0 +1,122 @@
+// Generated by CoffeeScript 1.6.3
+(function() {
+ define(['jquery.mockjax'], function() {
+ jQuery.mockjaxSettings.contentType = 'text/json';
+ jQuery.mockjaxSettings.responseTime = 250;
+ jQuery.mockjax({
+ url: "" + baseUrl + "/api/codingrules/app",
+ responseText: JSON.stringify({
+ messages: {
+ 'all': 'All',
+ 'bulk_change': 'Bulk Change',
+ 'moreCriteria': '+ More Criteria',
+ 'search_verb': 'Search',
+ 'update': 'Update',
+ 'severity.BLOCKER': 'Blocker',
+ 'severity.CRITICAL': 'Critical',
+ 'severity.MAJOR': 'Major',
+ 'severity.MINOR': 'Minor',
+ 'severity.INFO': 'Info',
+ 'coding_rules.page': 'Coding Rules',
+ 'coding_rules.new_search': 'New Search',
+ 'coding_rules.no_results': 'No Coding Rules',
+ 'coding_rules.found': 'Found',
+ 'coding_rules.quality_profiles': 'Quality Profiles',
+ 'coding_rules.activate_quality_profile': 'Activate Quality Profile',
+ 'coding_rules.deactivate_quality_profile': 'Deactivate',
+ 'coding_rules.filters.active_in': 'Active In',
+ 'coding_rules.filters.inactive_in': 'Inactive In',
+ 'coding_rules.filters.name_key': 'Name/Key',
+ 'coding_rules.filters.repository': 'Repository',
+ 'coding_rules.filters.severity': 'Severity',
+ 'coding_rules.filters.status': 'Status',
+ 'coding_rules.filters.tag': 'Tag'
+ }
+ })
+ });
+ jQuery.mockjax({
+ url: "" + baseUrl + "/api/codingrules/search",
+ responseText: JSON.stringify({
+ codingrules: [
+ {
+ name: 'Array designators "[]" should be located after the type in method signatures',
+ language: 'Java'
+ }, {
+ name: 'Avoid Array Loops',
+ language: 'Java'
+ }, {
+ name: 'Bad practice - Abstract class defines covariant compareTo() method',
+ language: 'Java'
+ }, {
+ name: 'Correctness - Use of class without a hashCode() method in a hashed data structure',
+ language: 'Java'
+ }, {
+ name: 'Useless Operation On Immutable',
+ language: 'Java'
+ }
+ ],
+ paging: {
+ total: 5,
+ fTotal: '5'
+ }
+ })
+ });
+ jQuery.mockjax({
+ url: "" + baseUrl + "/api/codingrules/show",
+ responseText: JSON.stringify({
+ codingrule: {
+ name: 'Array designators "[]" should be located after the type in method signatures',
+ language: 'Java',
+ description: '<p>\nAccording to the Java Language Specification:\n</p>\n\n<pre>For compatibility with older versions of the Java SE platform,\nthe declaration of a method that returns an array is allowed to place (some or all of) the empty bracket pairs that form the declaration of the array type after the formal parameter list.\nThis obsolescent syntax should not be used in new code.\n</pre>\n\n<p>The following code snippet illustrates this rule:</p>\n\n<pre>public int getVector()[] { /* ... */ } // Non-Compliant\n\npublic int[] getVector() { /* ... */ } // Compliant\n\npublic int[] getMatrix()[] { /* ... */ } // Non-Compliant\n\npublic int[][] getMatrix() { /* ... */ } // Compliant\n</pre>'
+ },
+ qualityprofiles: [
+ {
+ name: 'SonarWay',
+ severity: 'MINOR',
+ canDeactivate: false,
+ canUpdate: false,
+ parameters: [
+ {
+ key: 'max',
+ value: 8
+ }
+ ]
+ }, {
+ name: 'Quality Profile 1',
+ severity: 'MAJOR',
+ canDeactivate: true,
+ canUpdate: true,
+ parameters: [
+ {
+ key: 'max',
+ value: 6
+ }
+ ]
+ }
+ ]
+ })
+ });
+ return jQuery.mockjax({
+ url: "" + baseUrl + "/api/qualityprofiles/list",
+ responseText: JSON.stringify({
+ more: false,
+ results: [
+ {
+ id: 'sonarway',
+ text: 'Sonar Way'
+ }, {
+ id: 'qp1',
+ text: 'Quality Profile 1'
+ }, {
+ id: 'qp2',
+ text: 'Quality Profile 2'
+ }, {
+ id: 'qp3',
+ text: 'Quality Profile 3'
+ }
+ ]
+ })
+ });
+ });
+
+}).call(this);
diff --git a/sonar-server/src/main/webapp/javascripts/coding-rules/models/coding-rule.coffee b/sonar-server/src/main/webapp/javascripts/coding-rules/models/coding-rule.coffee
new file mode 100644
index 00000000000..75618486e7b
--- /dev/null
+++ b/sonar-server/src/main/webapp/javascripts/coding-rules/models/coding-rule.coffee
@@ -0,0 +1,16 @@
+define [
+ 'backbone'
+], (
+ Backbone
+) ->
+
+ class CodingRule extends Backbone.Model
+
+ url: ->
+ "#{baseUrl}/api/codingrules/show"
+
+
+ parse: (r) ->
+ model = if r.codingrule? then r.codingrule else r
+ _.extend model, qualityProfiles: r.qualityprofiles if r.qualityprofiles?
+ model
diff --git a/sonar-server/src/main/webapp/javascripts/coding-rules/models/coding-rule.js b/sonar-server/src/main/webapp/javascripts/coding-rules/models/coding-rule.js
new file mode 100644
index 00000000000..accd6f9af0c
--- /dev/null
+++ b/sonar-server/src/main/webapp/javascripts/coding-rules/models/coding-rule.js
@@ -0,0 +1,36 @@
+// Generated by CoffeeScript 1.6.3
+(function() {
+ var __hasProp = {}.hasOwnProperty,
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
+
+ define(['backbone'], function(Backbone) {
+ var CodingRule, _ref;
+ return CodingRule = (function(_super) {
+ __extends(CodingRule, _super);
+
+ function CodingRule() {
+ _ref = CodingRule.__super__.constructor.apply(this, arguments);
+ return _ref;
+ }
+
+ CodingRule.prototype.url = function() {
+ return "" + baseUrl + "/api/codingrules/show";
+ };
+
+ CodingRule.prototype.parse = function(r) {
+ var model;
+ model = r.codingrule != null ? r.codingrule : r;
+ if (r.qualityprofiles != null) {
+ _.extend(model, {
+ qualityProfiles: r.qualityprofiles
+ });
+ }
+ return model;
+ };
+
+ return CodingRule;
+
+ })(Backbone.Model);
+ });
+
+}).call(this);
diff --git a/sonar-server/src/main/webapp/javascripts/coding-rules/router.coffee b/sonar-server/src/main/webapp/javascripts/coding-rules/router.coffee
new file mode 100644
index 00000000000..7d55132405a
--- /dev/null
+++ b/sonar-server/src/main/webapp/javascripts/coding-rules/router.coffee
@@ -0,0 +1,46 @@
+define [
+ 'backbone',
+], (
+ Backbone,
+) ->
+
+ class AppRouter extends Backbone.Router
+
+ routes:
+ '': 'index'
+ ':query': 'index'
+
+
+ initialize: (options) ->
+ @app = options.app
+
+
+ parseQuery: (query, separator) ->
+ (query || '').split(separator || '|').map (t) ->
+ tokens = t.split('=')
+ key: tokens[0], value: decodeURIComponent(tokens[1])
+
+
+ emptyQuery: ->
+ @navigate '', trigger: true, replace: true
+
+
+ index: (query) ->
+ params = this.parseQuery(query)
+ idObj = _.findWhere(params, { key: 'id' })
+ if (idObj)
+ f = this.app.favoriteFilter
+ @app.canSave = false
+ f.set('id', idObj.value)
+ f.fetch
+ success: =>
+ params = _.extend({}, @parseQuery(f.get('query')), params)
+ @loadResults(params)
+ else
+ @loadResults(params)
+
+
+ loadResults: (params) ->
+ @app.filterBarView.restoreFromQuery(params)
+ @app.restoreSorting(params)
+ @app.fetchFirstPage()
diff --git a/sonar-server/src/main/webapp/javascripts/coding-rules/router.js b/sonar-server/src/main/webapp/javascripts/coding-rules/router.js
new file mode 100644
index 00000000000..2fa7aacc723
--- /dev/null
+++ b/sonar-server/src/main/webapp/javascripts/coding-rules/router.js
@@ -0,0 +1,76 @@
+// Generated by CoffeeScript 1.6.3
+(function() {
+ var __hasProp = {}.hasOwnProperty,
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
+
+ define(['backbone'], function(Backbone) {
+ var AppRouter, _ref;
+ return AppRouter = (function(_super) {
+ __extends(AppRouter, _super);
+
+ function AppRouter() {
+ _ref = AppRouter.__super__.constructor.apply(this, arguments);
+ return _ref;
+ }
+
+ AppRouter.prototype.routes = {
+ '': 'index',
+ ':query': 'index'
+ };
+
+ AppRouter.prototype.initialize = function(options) {
+ return this.app = options.app;
+ };
+
+ AppRouter.prototype.parseQuery = function(query, separator) {
+ return (query || '').split(separator || '|').map(function(t) {
+ var tokens;
+ tokens = t.split('=');
+ return {
+ key: tokens[0],
+ value: decodeURIComponent(tokens[1])
+ };
+ });
+ };
+
+ AppRouter.prototype.emptyQuery = function() {
+ return this.navigate('', {
+ trigger: true,
+ replace: true
+ });
+ };
+
+ AppRouter.prototype.index = function(query) {
+ var f, idObj, params,
+ _this = this;
+ params = this.parseQuery(query);
+ idObj = _.findWhere(params, {
+ key: 'id'
+ });
+ if (idObj) {
+ f = this.app.favoriteFilter;
+ this.app.canSave = false;
+ f.set('id', idObj.value);
+ return f.fetch({
+ success: function() {
+ params = _.extend({}, _this.parseQuery(f.get('query')), params);
+ return _this.loadResults(params);
+ }
+ });
+ } else {
+ return this.loadResults(params);
+ }
+ };
+
+ AppRouter.prototype.loadResults = function(params) {
+ this.app.filterBarView.restoreFromQuery(params);
+ this.app.restoreSorting(params);
+ return this.app.fetchFirstPage();
+ };
+
+ return AppRouter;
+
+ })(Backbone.Router);
+ });
+
+}).call(this);
diff --git a/sonar-server/src/main/webapp/javascripts/coding-rules/views/actions-view.coffee b/sonar-server/src/main/webapp/javascripts/coding-rules/views/actions-view.coffee
new file mode 100644
index 00000000000..8220be5a30c
--- /dev/null
+++ b/sonar-server/src/main/webapp/javascripts/coding-rules/views/actions-view.coffee
@@ -0,0 +1,18 @@
+define [
+ 'backbone.marionette',
+ 'common/handlebars-extensions'
+], (
+ Marionette
+) ->
+
+ class CodingRulesStatusView extends Marionette.ItemView
+ template: getTemplate '#coding-rules-status-template'
+
+
+ collectionEvents:
+ 'all': 'render'
+
+
+ serializeData: ->
+ _.extend super,
+ paging: @collection.paging
diff --git a/sonar-server/src/main/webapp/javascripts/coding-rules/views/actions-view.js b/sonar-server/src/main/webapp/javascripts/coding-rules/views/actions-view.js
new file mode 100644
index 00000000000..d2cefc37634
--- /dev/null
+++ b/sonar-server/src/main/webapp/javascripts/coding-rules/views/actions-view.js
@@ -0,0 +1,33 @@
+// Generated by CoffeeScript 1.6.3
+(function() {
+ var __hasProp = {}.hasOwnProperty,
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
+
+ define(['backbone.marionette', 'common/handlebars-extensions'], function(Marionette) {
+ var CodingRulesStatusView, _ref;
+ return CodingRulesStatusView = (function(_super) {
+ __extends(CodingRulesStatusView, _super);
+
+ function CodingRulesStatusView() {
+ _ref = CodingRulesStatusView.__super__.constructor.apply(this, arguments);
+ return _ref;
+ }
+
+ CodingRulesStatusView.prototype.template = getTemplate('#coding-rules-status-template');
+
+ CodingRulesStatusView.prototype.collectionEvents = {
+ 'all': 'render'
+ };
+
+ CodingRulesStatusView.prototype.serializeData = function() {
+ return _.extend(CodingRulesStatusView.__super__.serializeData.apply(this, arguments), {
+ paging: this.collection.paging
+ });
+ };
+
+ return CodingRulesStatusView;
+
+ })(Marionette.ItemView);
+ });
+
+}).call(this);
diff --git a/sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-detail-view.coffee b/sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-detail-view.coffee
new file mode 100644
index 00000000000..0f5c741241e
--- /dev/null
+++ b/sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-detail-view.coffee
@@ -0,0 +1,9 @@
+define [
+ 'backbone.marionette',
+ 'common/handlebars-extensions'
+], (
+ Marionette,
+) ->
+
+ class CodingRulesDetailView extends Marionette.ItemView
+ template: getTemplate '#coding-rules-detail-template'
diff --git a/sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-detail-view.js b/sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-detail-view.js
new file mode 100644
index 00000000000..06fd6527ad6
--- /dev/null
+++ b/sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-detail-view.js
@@ -0,0 +1,23 @@
+// Generated by CoffeeScript 1.6.3
+(function() {
+ var __hasProp = {}.hasOwnProperty,
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
+
+ define(['backbone.marionette', 'common/handlebars-extensions'], function(Marionette) {
+ var CodingRulesDetailView, _ref;
+ return CodingRulesDetailView = (function(_super) {
+ __extends(CodingRulesDetailView, _super);
+
+ function CodingRulesDetailView() {
+ _ref = CodingRulesDetailView.__super__.constructor.apply(this, arguments);
+ return _ref;
+ }
+
+ CodingRulesDetailView.prototype.template = getTemplate('#coding-rules-detail-template');
+
+ return CodingRulesDetailView;
+
+ })(Marionette.ItemView);
+ });
+
+}).call(this);
diff --git a/sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-list-empty-view.coffee b/sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-list-empty-view.coffee
new file mode 100644
index 00000000000..203fcad6a7a
--- /dev/null
+++ b/sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-list-empty-view.coffee
@@ -0,0 +1,11 @@
+define [
+ 'backbone.marionette',
+ 'common/handlebars-extensions'
+], (
+ Marionette,
+) ->
+
+ class CodingRulesListEmptyView extends Marionette.ItemView
+ tagName: 'li'
+ className: 'navigator-results-no-results'
+ template: getTemplate '#coding-rules-list-empty-template'
diff --git a/sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-list-empty-view.js b/sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-list-empty-view.js
new file mode 100644
index 00000000000..828d78f1b75
--- /dev/null
+++ b/sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-list-empty-view.js
@@ -0,0 +1,27 @@
+// Generated by CoffeeScript 1.6.3
+(function() {
+ var __hasProp = {}.hasOwnProperty,
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
+
+ define(['backbone.marionette', 'common/handlebars-extensions'], function(Marionette) {
+ var CodingRulesListEmptyView, _ref;
+ return CodingRulesListEmptyView = (function(_super) {
+ __extends(CodingRulesListEmptyView, _super);
+
+ function CodingRulesListEmptyView() {
+ _ref = CodingRulesListEmptyView.__super__.constructor.apply(this, arguments);
+ return _ref;
+ }
+
+ CodingRulesListEmptyView.prototype.tagName = 'li';
+
+ CodingRulesListEmptyView.prototype.className = 'navigator-results-no-results';
+
+ CodingRulesListEmptyView.prototype.template = getTemplate('#coding-rules-list-empty-template');
+
+ return CodingRulesListEmptyView;
+
+ })(Marionette.ItemView);
+ });
+
+}).call(this);
diff --git a/sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-list-item-view.coffee b/sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-list-item-view.coffee
new file mode 100644
index 00000000000..844a446681e
--- /dev/null
+++ b/sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-list-item-view.coffee
@@ -0,0 +1,27 @@
+define [
+ 'backbone.marionette',
+ 'coding-rules/views/coding-rules-detail-view',
+ 'common/handlebars-extensions'
+], (
+ Marionette,
+ CodingRulesDetailView
+) ->
+
+ class CodingRulesListItemView extends Marionette.ItemView
+ tagName: 'li'
+ template: getTemplate '#coding-rules-list-item-template'
+ activeClass: 'active'
+
+
+ events: ->
+ 'click': 'showDetail'
+
+
+ showDetail: ->
+ @$el.siblings().removeClass @activeClass
+ @$el.addClass @activeClass
+
+ @options.app.layout.showSpinner 'detailsRegion'
+ @model.fetch().done =>
+ detailView = new CodingRulesDetailView model: @model
+ @options.app.layout.detailsRegion.show detailView
diff --git a/sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-list-item-view.js b/sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-list-item-view.js
new file mode 100644
index 00000000000..1d9895a15c2
--- /dev/null
+++ b/sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-list-item-view.js
@@ -0,0 +1,47 @@
+// Generated by CoffeeScript 1.6.3
+(function() {
+ var __hasProp = {}.hasOwnProperty,
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
+
+ define(['backbone.marionette', 'coding-rules/views/coding-rules-detail-view', 'common/handlebars-extensions'], function(Marionette, CodingRulesDetailView) {
+ var CodingRulesListItemView, _ref;
+ return CodingRulesListItemView = (function(_super) {
+ __extends(CodingRulesListItemView, _super);
+
+ function CodingRulesListItemView() {
+ _ref = CodingRulesListItemView.__super__.constructor.apply(this, arguments);
+ return _ref;
+ }
+
+ CodingRulesListItemView.prototype.tagName = 'li';
+
+ CodingRulesListItemView.prototype.template = getTemplate('#coding-rules-list-item-template');
+
+ CodingRulesListItemView.prototype.activeClass = 'active';
+
+ CodingRulesListItemView.prototype.events = function() {
+ return {
+ 'click': 'showDetail'
+ };
+ };
+
+ CodingRulesListItemView.prototype.showDetail = function() {
+ var _this = this;
+ this.$el.siblings().removeClass(this.activeClass);
+ this.$el.addClass(this.activeClass);
+ this.options.app.layout.showSpinner('detailsRegion');
+ return this.model.fetch().done(function() {
+ var detailView;
+ detailView = new CodingRulesDetailView({
+ model: _this.model
+ });
+ return _this.options.app.layout.detailsRegion.show(detailView);
+ });
+ };
+
+ return CodingRulesListItemView;
+
+ })(Marionette.ItemView);
+ });
+
+}).call(this);
diff --git a/sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-list-view.coffee b/sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-list-view.coffee
new file mode 100644
index 00000000000..93db305b2b5
--- /dev/null
+++ b/sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-list-view.coffee
@@ -0,0 +1,23 @@
+define [
+ 'backbone.marionette',
+ 'coding-rules/views/coding-rules-list-item-view',
+ 'coding-rules/views/coding-rules-list-empty-view'
+], (
+ Marionette,
+ CodingRulesListItemView,
+ CodingRulesListEmptyView
+) ->
+
+ class CodingRulesListView extends Marionette.CollectionView
+ tagName: 'ol'
+ className: 'navigator-results-list'
+ itemView: CodingRulesListItemView,
+ emptyView: CodingRulesListEmptyView,
+
+
+ itemViewOptions: ->
+ listView: @, app: @options.app
+
+
+ selectFirst: ->
+ @$el.find('*:first').click()
diff --git a/sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-list-view.js b/sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-list-view.js
new file mode 100644
index 00000000000..b8a82439838
--- /dev/null
+++ b/sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-list-view.js
@@ -0,0 +1,40 @@
+// Generated by CoffeeScript 1.6.3
+(function() {
+ var __hasProp = {}.hasOwnProperty,
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
+
+ define(['backbone.marionette', 'coding-rules/views/coding-rules-list-item-view', 'coding-rules/views/coding-rules-list-empty-view'], function(Marionette, CodingRulesListItemView, CodingRulesListEmptyView) {
+ var CodingRulesListView, _ref;
+ return CodingRulesListView = (function(_super) {
+ __extends(CodingRulesListView, _super);
+
+ function CodingRulesListView() {
+ _ref = CodingRulesListView.__super__.constructor.apply(this, arguments);
+ return _ref;
+ }
+
+ CodingRulesListView.prototype.tagName = 'ol';
+
+ CodingRulesListView.prototype.className = 'navigator-results-list';
+
+ CodingRulesListView.prototype.itemView = CodingRulesListItemView;
+
+ CodingRulesListView.prototype.emptyView = CodingRulesListEmptyView;
+
+ CodingRulesListView.prototype.itemViewOptions = function() {
+ return {
+ listView: this,
+ app: this.options.app
+ };
+ };
+
+ CodingRulesListView.prototype.selectFirst = function() {
+ return this.$el.find('*:first').click();
+ };
+
+ return CodingRulesListView;
+
+ })(Marionette.CollectionView);
+ });
+
+}).call(this);
diff --git a/sonar-server/src/main/webapp/javascripts/coding-rules/views/filter-bar-view.coffee b/sonar-server/src/main/webapp/javascripts/coding-rules/views/filter-bar-view.coffee
new file mode 100644
index 00000000000..f6b7cf4b745
--- /dev/null
+++ b/sonar-server/src/main/webapp/javascripts/coding-rules/views/filter-bar-view.coffee
@@ -0,0 +1,67 @@
+define [
+ 'navigator/filters/filter-bar',
+ 'navigator/filters/base-filters',
+ 'navigator/filters/favorite-filters',
+ 'navigator/filters/more-criteria-filters'
+], (
+ FilterBarView,
+ BaseFilters,
+ FavoriteFiltersModule,
+ MoreCriteriaFilters
+) ->
+
+ class CodingRulesFilterBarView extends FilterBarView
+
+ collectionEvents:
+ 'change:enabled': 'changeEnabled'
+
+
+ events:
+ 'click .navigator-filter-submit': 'search'
+
+
+ getQuery: ->
+ query = {}
+ @collection.each (filter) ->
+ _.extend query, filter.view.formatValue()
+ query
+
+
+ onAfterItemAdded: (itemView) ->
+ if itemView.model.get('type') == FavoriteFiltersModule.FavoriteFilterView
+ jQuery('.navigator-header').addClass 'navigator-header-favorite'
+
+
+ addMoreCriteriaFilter: ->
+ disabledFilters = this.collection.where enabled: false
+ if disabledFilters.length > 0
+ @moreCriteriaFilter = new BaseFilters.Filter
+ type: MoreCriteriaFilters.MoreCriteriaFilterView,
+ enabled: true,
+ optional: false,
+ filters: disabledFilters
+ @collection.add @moreCriteriaFilter
+
+
+ changeEnabled: ->
+ disabledFilters = _.reject @collection.where(enabled: false), (filter) ->
+ filter.get('type') == MoreCriteriaFilters.MoreCriteriaFilterView
+
+ if disabledFilters.length == 0
+ @moreCriteriaFilter.set { enabled: false }, { silent: true }
+ else
+ @moreCriteriaFilter.set { enabled: true }, { silent: true }
+
+ @moreCriteriaFilter.set { filters: disabledFilters }, { silent: true }
+ @moreCriteriaFilter.trigger 'change:filters'
+
+
+ search: ->
+ @options.app.state.set
+ query: this.options.app.getQuery(),
+ search: true
+ @options.app.fetchFirstPage()
+
+
+ fetchNextPage: ->
+ @options.app.fetchNextPage()
diff --git a/sonar-server/src/main/webapp/javascripts/coding-rules/views/filter-bar-view.js b/sonar-server/src/main/webapp/javascripts/coding-rules/views/filter-bar-view.js
new file mode 100644
index 00000000000..475ac88981f
--- /dev/null
+++ b/sonar-server/src/main/webapp/javascripts/coding-rules/views/filter-bar-view.js
@@ -0,0 +1,100 @@
+// Generated by CoffeeScript 1.6.3
+(function() {
+ var __hasProp = {}.hasOwnProperty,
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
+
+ define(['navigator/filters/filter-bar', 'navigator/filters/base-filters', 'navigator/filters/favorite-filters', 'navigator/filters/more-criteria-filters'], function(FilterBarView, BaseFilters, FavoriteFiltersModule, MoreCriteriaFilters) {
+ var CodingRulesFilterBarView, _ref;
+ return CodingRulesFilterBarView = (function(_super) {
+ __extends(CodingRulesFilterBarView, _super);
+
+ function CodingRulesFilterBarView() {
+ _ref = CodingRulesFilterBarView.__super__.constructor.apply(this, arguments);
+ return _ref;
+ }
+
+ CodingRulesFilterBarView.prototype.collectionEvents = {
+ 'change:enabled': 'changeEnabled'
+ };
+
+ CodingRulesFilterBarView.prototype.events = {
+ 'click .navigator-filter-submit': 'search'
+ };
+
+ CodingRulesFilterBarView.prototype.getQuery = function() {
+ var query;
+ query = {};
+ this.collection.each(function(filter) {
+ return _.extend(query, filter.view.formatValue());
+ });
+ return query;
+ };
+
+ CodingRulesFilterBarView.prototype.onAfterItemAdded = function(itemView) {
+ if (itemView.model.get('type') === FavoriteFiltersModule.FavoriteFilterView) {
+ return jQuery('.navigator-header').addClass('navigator-header-favorite');
+ }
+ };
+
+ CodingRulesFilterBarView.prototype.addMoreCriteriaFilter = function() {
+ var disabledFilters;
+ disabledFilters = this.collection.where({
+ enabled: false
+ });
+ if (disabledFilters.length > 0) {
+ this.moreCriteriaFilter = new BaseFilters.Filter({
+ type: MoreCriteriaFilters.MoreCriteriaFilterView,
+ enabled: true,
+ optional: false,
+ filters: disabledFilters
+ });
+ return this.collection.add(this.moreCriteriaFilter);
+ }
+ };
+
+ CodingRulesFilterBarView.prototype.changeEnabled = function() {
+ var disabledFilters;
+ disabledFilters = _.reject(this.collection.where({
+ enabled: false
+ }), function(filter) {
+ return filter.get('type') === MoreCriteriaFilters.MoreCriteriaFilterView;
+ });
+ if (disabledFilters.length === 0) {
+ this.moreCriteriaFilter.set({
+ enabled: false
+ }, {
+ silent: true
+ });
+ } else {
+ this.moreCriteriaFilter.set({
+ enabled: true
+ }, {
+ silent: true
+ });
+ }
+ this.moreCriteriaFilter.set({
+ filters: disabledFilters
+ }, {
+ silent: true
+ });
+ return this.moreCriteriaFilter.trigger('change:filters');
+ };
+
+ CodingRulesFilterBarView.prototype.search = function() {
+ this.options.app.state.set({
+ query: this.options.app.getQuery(),
+ search: true
+ });
+ return this.options.app.fetchFirstPage();
+ };
+
+ CodingRulesFilterBarView.prototype.fetchNextPage = function() {
+ return this.options.app.fetchNextPage();
+ };
+
+ return CodingRulesFilterBarView;
+
+ })(FilterBarView);
+ });
+
+}).call(this);
diff --git a/sonar-server/src/main/webapp/javascripts/coding-rules/views/filters/quality-profile-filter-view.coffee b/sonar-server/src/main/webapp/javascripts/coding-rules/views/filters/quality-profile-filter-view.coffee
new file mode 100644
index 00000000000..3561ff936ce
--- /dev/null
+++ b/sonar-server/src/main/webapp/javascripts/coding-rules/views/filters/quality-profile-filter-view.coffee
@@ -0,0 +1,19 @@
+define [
+ 'navigator/filters/ajax-select-filters'
+], (
+ AjaxSelectFilters
+) ->
+
+ class QualityProfileSuggestions extends AjaxSelectFilters.Suggestions
+
+ url: ->
+ "#{baseUrl}/api/qualityprofiles/list"
+
+
+
+ class QualityProfileFilterView extends AjaxSelectFilters.AjaxSelectFilterView
+
+ initialize: ->
+ super
+ @choices = new QualityProfileSuggestions
+
diff --git a/sonar-server/src/main/webapp/javascripts/coding-rules/views/filters/quality-profile-filter-view.js b/sonar-server/src/main/webapp/javascripts/coding-rules/views/filters/quality-profile-filter-view.js
new file mode 100644
index 00000000000..a8ce1a54ef2
--- /dev/null
+++ b/sonar-server/src/main/webapp/javascripts/coding-rules/views/filters/quality-profile-filter-view.js
@@ -0,0 +1,41 @@
+// Generated by CoffeeScript 1.6.3
+(function() {
+ var __hasProp = {}.hasOwnProperty,
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
+
+ define(['navigator/filters/ajax-select-filters'], function(AjaxSelectFilters) {
+ var QualityProfileFilterView, QualityProfileSuggestions, _ref, _ref1;
+ QualityProfileSuggestions = (function(_super) {
+ __extends(QualityProfileSuggestions, _super);
+
+ function QualityProfileSuggestions() {
+ _ref = QualityProfileSuggestions.__super__.constructor.apply(this, arguments);
+ return _ref;
+ }
+
+ QualityProfileSuggestions.prototype.url = function() {
+ return "" + baseUrl + "/api/qualityprofiles/list";
+ };
+
+ return QualityProfileSuggestions;
+
+ })(AjaxSelectFilters.Suggestions);
+ return QualityProfileFilterView = (function(_super) {
+ __extends(QualityProfileFilterView, _super);
+
+ function QualityProfileFilterView() {
+ _ref1 = QualityProfileFilterView.__super__.constructor.apply(this, arguments);
+ return _ref1;
+ }
+
+ QualityProfileFilterView.prototype.initialize = function() {
+ QualityProfileFilterView.__super__.initialize.apply(this, arguments);
+ return this.choices = new QualityProfileSuggestions;
+ };
+
+ return QualityProfileFilterView;
+
+ })(AjaxSelectFilters.AjaxSelectFilterView);
+ });
+
+}).call(this);
diff --git a/sonar-server/src/main/webapp/javascripts/coding-rules/views/header-view.coffee b/sonar-server/src/main/webapp/javascripts/coding-rules/views/header-view.coffee
new file mode 100644
index 00000000000..b14bb2986d3
--- /dev/null
+++ b/sonar-server/src/main/webapp/javascripts/coding-rules/views/header-view.coffee
@@ -0,0 +1,9 @@
+define [
+ 'backbone.marionette',
+ 'common/handlebars-extensions'
+], (
+ Marionette
+) ->
+
+ class CodingRulesHeaderView extends Marionette.ItemView
+ template: getTemplate '#coding-rules-header-template'
diff --git a/sonar-server/src/main/webapp/javascripts/coding-rules/views/header-view.js b/sonar-server/src/main/webapp/javascripts/coding-rules/views/header-view.js
new file mode 100644
index 00000000000..21891dacac6
--- /dev/null
+++ b/sonar-server/src/main/webapp/javascripts/coding-rules/views/header-view.js
@@ -0,0 +1,23 @@
+// Generated by CoffeeScript 1.6.3
+(function() {
+ var __hasProp = {}.hasOwnProperty,
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
+
+ define(['backbone.marionette', 'common/handlebars-extensions'], function(Marionette) {
+ var CodingRulesHeaderView, _ref;
+ return CodingRulesHeaderView = (function(_super) {
+ __extends(CodingRulesHeaderView, _super);
+
+ function CodingRulesHeaderView() {
+ _ref = CodingRulesHeaderView.__super__.constructor.apply(this, arguments);
+ return _ref;
+ }
+
+ CodingRulesHeaderView.prototype.template = getTemplate('#coding-rules-header-template');
+
+ return CodingRulesHeaderView;
+
+ })(Marionette.ItemView);
+ });
+
+}).call(this);
diff --git a/sonar-server/src/main/webapp/javascripts/issues/extra.js b/sonar-server/src/main/webapp/javascripts/issues/extra.js
index 2c5bdbd7e0c..89b29704a67 100644
--- a/sonar-server/src/main/webapp/javascripts/issues/extra.js
+++ b/sonar-server/src/main/webapp/javascripts/issues/extra.js
@@ -229,6 +229,8 @@ define(
var NoIssuesView = Marionette.ItemView.extend({
+ tagName: 'li',
+ className: 'navigator-results-no-results',
template: Handlebars.compile(jQuery('#no-issues-template').html() || '')
});
diff --git a/sonar-server/src/main/webapp/javascripts/navigator/filters/ajax-select-filters.js b/sonar-server/src/main/webapp/javascripts/navigator/filters/ajax-select-filters.js
index 070164abf0f..dd2e246d217 100644
--- a/sonar-server/src/main/webapp/javascripts/navigator/filters/ajax-select-filters.js
+++ b/sonar-server/src/main/webapp/javascripts/navigator/filters/ajax-select-filters.js
@@ -192,6 +192,13 @@ define(['backbone', 'navigator/filters/base-filters', 'navigator/filters/choice-
var AjaxSelectFilterView = ChoiceFilters.ChoiceFilterView.extend({
+ initialize: function() {
+ ChoiceFilters.ChoiceFilterView.prototype.initialize.call(this, {
+ detailsView: AjaxSelectDetailsFilterView
+ });
+ },
+
+
isDefaultValue: function() {
return this.getSelected().length === 0;
},
diff --git a/sonar-server/src/main/webapp/javascripts/navigator/filters/choice-filters.js b/sonar-server/src/main/webapp/javascripts/navigator/filters/choice-filters.js
index a01b65f175f..cf74a21562e 100644
--- a/sonar-server/src/main/webapp/javascripts/navigator/filters/choice-filters.js
+++ b/sonar-server/src/main/webapp/javascripts/navigator/filters/choice-filters.js
@@ -240,7 +240,7 @@ define(['handlebars', 'navigator/filters/base-filters', 'common/handlebars-exten
}),
defaultValue = this.model.has('defaultValue') ?
this.model.get('defaultValue') :
- this.model.get('multiple') ? window.SS.phrases.all : window.SS.phrases.any;
+ this.model.get('multiple') ? t('all') : t('any');
return this.isDefaultValue() ? defaultValue : value.join(', ');
},
diff --git a/sonar-server/src/main/webapp/javascripts/navigator/filters/filter-bar.js b/sonar-server/src/main/webapp/javascripts/navigator/filters/filter-bar.js
index 35e182d923c..a859c721382 100644
--- a/sonar-server/src/main/webapp/javascripts/navigator/filters/filter-bar.js
+++ b/sonar-server/src/main/webapp/javascripts/navigator/filters/filter-bar.js
@@ -44,13 +44,15 @@ define(
addMoreCriteriaFilter: function() {
var disabledFilters = this.collection.where({ enabled: false });
- this.moreCriteriaFilter = new BaseFilters.Filter({
- type: require('navigator/filters/more-criteria-filters').MoreCriteriaFilterView,
- enabled: true,
- optional: false,
- filters: disabledFilters
- });
- this.collection.add(this.moreCriteriaFilter);
+ if (disabledFilters.length > 0) {
+ this.moreCriteriaFilter = new BaseFilters.Filter({
+ type: require('navigator/filters/more-criteria-filters').MoreCriteriaFilterView,
+ enabled: true,
+ optional: false,
+ filters: disabledFilters
+ });
+ this.collection.add(this.moreCriteriaFilter);
+ }
},
diff --git a/sonar-server/src/main/webapp/javascripts/quality-gate/app.coffee b/sonar-server/src/main/webapp/javascripts/quality-gate/app.coffee
index 49f9bdb693b..ca7e143da88 100644
--- a/sonar-server/src/main/webapp/javascripts/quality-gate/app.coffee
+++ b/sonar-server/src/main/webapp/javascripts/quality-gate/app.coffee
@@ -91,9 +91,9 @@ requirejs [
# Construct actions bar
App.addInitializer ->
- @qualityGateActionsView = new QualityGateActionsView
+ @codingRulesHeaderView = new QualityGateActionsView
app: @
- @layout.actionsRegion.show @qualityGateActionsView
+ @layout.actionsRegion.show @codingRulesHeaderView
# Construct sidebar
@@ -101,7 +101,7 @@ requirejs [
@qualityGateSidebarListView = new QualityGateSidebarListItemView
collection: @qualityGates
app: @
- @layout.listRegion.show @qualityGateSidebarListView
+ @layout.resultsRegion.show @qualityGateSidebarListView
# Construct edit view
@@ -136,7 +136,7 @@ requirejs [
jQuery.when(qualityGatesXHR, appXHR)
.done ->
# Remove the initial spinner
- jQuery('.quality-gate-page-loader').remove()
+ jQuery('#quality-gate-page-loader').remove()
# Start the application
App.start()
diff --git a/sonar-server/src/main/webapp/javascripts/quality-gate/app.js b/sonar-server/src/main/webapp/javascripts/quality-gate/app.js
index dd1301494f5..0ffb6472aa9 100644
--- a/sonar-server/src/main/webapp/javascripts/quality-gate/app.js
+++ b/sonar-server/src/main/webapp/javascripts/quality-gate/app.js
@@ -78,17 +78,17 @@
return jQuery('body').append(this.layout.render().el);
});
App.addInitializer(function() {
- this.qualityGateActionsView = new QualityGateActionsView({
+ this.codingRulesHeaderView = new QualityGateActionsView({
app: this
});
- return this.layout.actionsRegion.show(this.qualityGateActionsView);
+ return this.layout.actionsRegion.show(this.codingRulesHeaderView);
});
App.addInitializer(function() {
this.qualityGateSidebarListView = new QualityGateSidebarListItemView({
collection: this.qualityGates,
app: this
});
- return this.layout.listRegion.show(this.qualityGateSidebarListView);
+ return this.layout.resultsRegion.show(this.qualityGateSidebarListView);
});
App.addInitializer(function() {
this.qualityGateEditView = new QualityGateEditView({
@@ -119,7 +119,7 @@
});
qualityGatesXHR = App.qualityGates.fetch();
return jQuery.when(qualityGatesXHR, appXHR).done(function() {
- jQuery('.quality-gate-page-loader').remove();
+ jQuery('#quality-gate-page-loader').remove();
return App.start();
});
});
diff --git a/sonar-server/src/main/webapp/javascripts/quality-gate/layout.coffee b/sonar-server/src/main/webapp/javascripts/quality-gate/layout.coffee
index bb3abdb19c1..e9805d05953 100644
--- a/sonar-server/src/main/webapp/javascripts/quality-gate/layout.coffee
+++ b/sonar-server/src/main/webapp/javascripts/quality-gate/layout.coffee
@@ -13,7 +13,7 @@ define [
regions:
headerRegion: '.navigator-header'
actionsRegion: '.navigator-actions'
- listRegion: '.navigator-results'
+ resultsRegion: '.navigator-results'
detailsRegion: '.navigator-details'
diff --git a/sonar-server/src/main/webapp/javascripts/quality-gate/layout.js b/sonar-server/src/main/webapp/javascripts/quality-gate/layout.js
index b18e10cdccd..0ffc92a02f0 100644
--- a/sonar-server/src/main/webapp/javascripts/quality-gate/layout.js
+++ b/sonar-server/src/main/webapp/javascripts/quality-gate/layout.js
@@ -20,7 +20,7 @@
AppLayout.prototype.regions = {
headerRegion: '.navigator-header',
actionsRegion: '.navigator-actions',
- listRegion: '.navigator-results',
+ resultsRegion: '.navigator-results',
detailsRegion: '.navigator-details'
};
diff --git a/sonar-server/src/main/webapp/javascripts/tests/translateSpec.coffee b/sonar-server/src/main/webapp/javascripts/tests/translateSpec.coffee
index 24185180c23..7b4576bcfff 100644
--- a/sonar-server/src/main/webapp/javascripts/tests/translateSpec.coffee
+++ b/sonar-server/src/main/webapp/javascripts/tests/translateSpec.coffee
@@ -68,3 +68,8 @@ describe 'translation "translate" suite', ->
it 'returns the key when no translation', ->
expect(translate('something_another')).toBe 'something_another'
+
+ it 'does not fail when there is no dictionary', ->
+ window.SS = undefined
+ expect(translate('something_another')).toBe 'something_another'
+
diff --git a/sonar-server/src/main/webapp/javascripts/tests/translateSpec.js b/sonar-server/src/main/webapp/javascripts/tests/translateSpec.js
index b634742ec8d..2f3aafe2652 100644
--- a/sonar-server/src/main/webapp/javascripts/tests/translateSpec.js
+++ b/sonar-server/src/main/webapp/javascripts/tests/translateSpec.js
@@ -60,7 +60,11 @@
it('translates with braces', function() {
return expect(translate('something_with{braces}')).toBe('SOMETHING_WITH{braces}');
});
- return it('returns the key when no translation', function() {
+ it('returns the key when no translation', function() {
+ return expect(translate('something_another')).toBe('something_another');
+ });
+ return it('does not fail when there is no dictionary', function() {
+ window.SS = void 0;
return expect(translate('something_another')).toBe('something_another');
});
});
diff --git a/sonar-server/src/main/webapp/javascripts/third-party/jquery.mockjax.js b/sonar-server/src/main/webapp/javascripts/third-party/jquery.mockjax.js
new file mode 100644
index 00000000000..b8e13145e40
--- /dev/null
+++ b/sonar-server/src/main/webapp/javascripts/third-party/jquery.mockjax.js
@@ -0,0 +1,598 @@
+/*!
+ * MockJax - jQuery Plugin to Mock Ajax requests
+ *
+ * Version: 1.5.3
+ * Released:
+ * Home: http://github.com/appendto/jquery-mockjax
+ * Author: Jonathan Sharp (http://jdsharp.com)
+ * License: MIT,GPL
+ *
+ * Copyright (c) 2011 appendTo LLC.
+ * Dual licensed under the MIT or GPL licenses.
+ * http://appendto.com/open-source-licenses
+ */
+(function($) {
+ var _ajax = $.ajax,
+ mockHandlers = [],
+ mockedAjaxCalls = [],
+ CALLBACK_REGEX = /=\?(&|$)/,
+ jsc = (new Date()).getTime();
+
+
+ // Parse the given XML string.
+ function parseXML(xml) {
+ if ( window.DOMParser == undefined && window.ActiveXObject ) {
+ DOMParser = function() { };
+ DOMParser.prototype.parseFromString = function( xmlString ) {
+ var doc = new ActiveXObject('Microsoft.XMLDOM');
+ doc.async = 'false';
+ doc.loadXML( xmlString );
+ return doc;
+ };
+ }
+
+ try {
+ var xmlDoc = ( new DOMParser() ).parseFromString( xml, 'text/xml' );
+ if ( $.isXMLDoc( xmlDoc ) ) {
+ var err = $('parsererror', xmlDoc);
+ if ( err.length == 1 ) {
+ throw('Error: ' + $(xmlDoc).text() );
+ }
+ } else {
+ throw('Unable to parse XML');
+ }
+ return xmlDoc;
+ } catch( e ) {
+ var msg = ( e.name == undefined ? e : e.name + ': ' + e.message );
+ $(document).trigger('xmlParseError', [ msg ]);
+ return undefined;
+ }
+ }
+
+ // Trigger a jQuery event
+ function trigger(s, type, args) {
+ (s.context ? $(s.context) : $.event).trigger(type, args);
+ }
+
+ // Check if the data field on the mock handler and the request match. This
+ // can be used to restrict a mock handler to being used only when a certain
+ // set of data is passed to it.
+ function isMockDataEqual( mock, live ) {
+ var identical = true;
+ // Test for situations where the data is a querystring (not an object)
+ if (typeof live === 'string') {
+ // Querystring may be a regex
+ return $.isFunction( mock.test ) ? mock.test(live) : mock == live;
+ }
+ $.each(mock, function(k) {
+ if ( live[k] === undefined ) {
+ identical = false;
+ return identical;
+ } else {
+ // This will allow to compare Arrays
+ if ( typeof live[k] === 'object' && live[k] !== null ) {
+ identical = identical && isMockDataEqual(mock[k], live[k]);
+ } else {
+ if ( mock[k] && $.isFunction( mock[k].test ) ) {
+ identical = identical && mock[k].test(live[k]);
+ } else {
+ identical = identical && ( mock[k] == live[k] );
+ }
+ }
+ }
+ });
+
+ return identical;
+ }
+
+ // See if a mock handler property matches the default settings
+ function isDefaultSetting(handler, property) {
+ return handler[property] === $.mockjaxSettings[property];
+ }
+
+ // Check the given handler should mock the given request
+ function getMockForRequest( handler, requestSettings ) {
+ // If the mock was registered with a function, let the function decide if we
+ // want to mock this request
+ if ( $.isFunction(handler) ) {
+ return handler( requestSettings );
+ }
+
+ // Inspect the URL of the request and check if the mock handler's url
+ // matches the url for this ajax request
+ if ( $.isFunction(handler.url.test) ) {
+ // The user provided a regex for the url, test it
+ if ( !handler.url.test( requestSettings.url ) ) {
+ return null;
+ }
+ } else {
+ // Look for a simple wildcard '*' or a direct URL match
+ var star = handler.url.indexOf('*');
+ if (handler.url !== requestSettings.url && star === -1 ||
+ !new RegExp(handler.url.replace(/[-[\]{}()+?.,\\^$|#\s]/g, "\\$&").replace(/\*/g, '.+')).test(requestSettings.url)) {
+ return null;
+ }
+ }
+
+ // Inspect the data submitted in the request (either POST body or GET query string)
+ if ( handler.data && requestSettings.data ) {
+ if ( !isMockDataEqual(handler.data, requestSettings.data) ) {
+ // They're not identical, do not mock this request
+ return null;
+ }
+ }
+ // Inspect the request type
+ if ( handler && handler.type &&
+ handler.type.toLowerCase() != requestSettings.type.toLowerCase() ) {
+ // The request type doesn't match (GET vs. POST)
+ return null;
+ }
+
+ return handler;
+ }
+
+ // Process the xhr objects send operation
+ function _xhrSend(mockHandler, requestSettings, origSettings) {
+
+ // This is a substitute for < 1.4 which lacks $.proxy
+ var process = (function(that) {
+ return function() {
+ return (function() {
+ var onReady;
+
+ // The request has returned
+ this.status = mockHandler.status;
+ this.statusText = mockHandler.statusText;
+ this.readyState = 4;
+
+ // We have an executable function, call it to give
+ // the mock handler a chance to update it's data
+ if ( $.isFunction(mockHandler.response) ) {
+ mockHandler.response(origSettings);
+ }
+ // Copy over our mock to our xhr object before passing control back to
+ // jQuery's onreadystatechange callback
+ if ( requestSettings.dataType == 'json' && ( typeof mockHandler.responseText == 'object' ) ) {
+ this.responseText = JSON.stringify(mockHandler.responseText);
+ } else if ( requestSettings.dataType == 'xml' ) {
+ if ( typeof mockHandler.responseXML == 'string' ) {
+ this.responseXML = parseXML(mockHandler.responseXML);
+ //in jQuery 1.9.1+, responseXML is processed differently and relies on responseText
+ this.responseText = mockHandler.responseXML;
+ } else {
+ this.responseXML = mockHandler.responseXML;
+ }
+ } else {
+ this.responseText = mockHandler.responseText;
+ }
+ if( typeof mockHandler.status == 'number' || typeof mockHandler.status == 'string' ) {
+ this.status = mockHandler.status;
+ }
+ if( typeof mockHandler.statusText === "string") {
+ this.statusText = mockHandler.statusText;
+ }
+ // jQuery 2.0 renamed onreadystatechange to onload
+ onReady = this.onreadystatechange || this.onload;
+
+ // jQuery < 1.4 doesn't have onreadystate change for xhr
+ if ( $.isFunction( onReady ) ) {
+ if( mockHandler.isTimeout) {
+ this.status = -1;
+ }
+ onReady.call( this, mockHandler.isTimeout ? 'timeout' : undefined );
+ } else if ( mockHandler.isTimeout ) {
+ // Fix for 1.3.2 timeout to keep success from firing.
+ this.status = -1;
+ }
+ }).apply(that);
+ };
+ })(this);
+
+ if ( mockHandler.proxy ) {
+ // We're proxying this request and loading in an external file instead
+ _ajax({
+ global: false,
+ url: mockHandler.proxy,
+ type: mockHandler.proxyType,
+ data: mockHandler.data,
+ dataType: requestSettings.dataType === "script" ? "text/plain" : requestSettings.dataType,
+ complete: function(xhr) {
+ mockHandler.responseXML = xhr.responseXML;
+ mockHandler.responseText = xhr.responseText;
+ // Don't override the handler status/statusText if it's specified by the config
+ if (isDefaultSetting(mockHandler, 'status')) {
+ mockHandler.status = xhr.status;
+ }
+ if (isDefaultSetting(mockHandler, 'statusText')) {
+ mockHandler.statusText = xhr.statusText;
+ }
+
+ this.responseTimer = setTimeout(process, mockHandler.responseTime || 0);
+ }
+ });
+ } else {
+ // type == 'POST' || 'GET' || 'DELETE'
+ if ( requestSettings.async === false ) {
+ // TODO: Blocking delay
+ process();
+ } else {
+ this.responseTimer = setTimeout(process, mockHandler.responseTime || 50);
+ }
+ }
+ }
+
+ // Construct a mocked XHR Object
+ function xhr(mockHandler, requestSettings, origSettings, origHandler) {
+ // Extend with our default mockjax settings
+ mockHandler = $.extend(true, {}, $.mockjaxSettings, mockHandler);
+
+ if (typeof mockHandler.headers === 'undefined') {
+ mockHandler.headers = {};
+ }
+ if ( mockHandler.contentType ) {
+ mockHandler.headers['content-type'] = mockHandler.contentType;
+ }
+
+ return {
+ status: mockHandler.status,
+ statusText: mockHandler.statusText,
+ readyState: 1,
+ open: function() { },
+ send: function() {
+ origHandler.fired = true;
+ _xhrSend.call(this, mockHandler, requestSettings, origSettings);
+ },
+ abort: function() {
+ clearTimeout(this.responseTimer);
+ },
+ setRequestHeader: function(header, value) {
+ mockHandler.headers[header] = value;
+ },
+ getResponseHeader: function(header) {
+ // 'Last-modified', 'Etag', 'content-type' are all checked by jQuery
+ if ( mockHandler.headers && mockHandler.headers[header] ) {
+ // Return arbitrary headers
+ return mockHandler.headers[header];
+ } else if ( header.toLowerCase() == 'last-modified' ) {
+ return mockHandler.lastModified || (new Date()).toString();
+ } else if ( header.toLowerCase() == 'etag' ) {
+ return mockHandler.etag || '';
+ } else if ( header.toLowerCase() == 'content-type' ) {
+ return mockHandler.contentType || 'text/plain';
+ }
+ },
+ getAllResponseHeaders: function() {
+ var headers = '';
+ $.each(mockHandler.headers, function(k, v) {
+ headers += k + ': ' + v + "\n";
+ });
+ return headers;
+ }
+ };
+ }
+
+ // Process a JSONP mock request.
+ function processJsonpMock( requestSettings, mockHandler, origSettings ) {
+ // Handle JSONP Parameter Callbacks, we need to replicate some of the jQuery core here
+ // because there isn't an easy hook for the cross domain script tag of jsonp
+
+ processJsonpUrl( requestSettings );
+
+ requestSettings.dataType = "json";
+ if(requestSettings.data && CALLBACK_REGEX.test(requestSettings.data) || CALLBACK_REGEX.test(requestSettings.url)) {
+ createJsonpCallback(requestSettings, mockHandler, origSettings);
+
+ // We need to make sure
+ // that a JSONP style response is executed properly
+
+ var rurl = /^(\w+:)?\/\/([^\/?#]+)/,
+ parts = rurl.exec( requestSettings.url ),
+ remote = parts && (parts[1] && parts[1] !== location.protocol || parts[2] !== location.host);
+
+ requestSettings.dataType = "script";
+ if(requestSettings.type.toUpperCase() === "GET" && remote ) {
+ var newMockReturn = processJsonpRequest( requestSettings, mockHandler, origSettings );
+
+ // Check if we are supposed to return a Deferred back to the mock call, or just
+ // signal success
+ if(newMockReturn) {
+ return newMockReturn;
+ } else {
+ return true;
+ }
+ }
+ }
+ return null;
+ }
+
+ // Append the required callback parameter to the end of the request URL, for a JSONP request
+ function processJsonpUrl( requestSettings ) {
+ if ( requestSettings.type.toUpperCase() === "GET" ) {
+ if ( !CALLBACK_REGEX.test( requestSettings.url ) ) {
+ requestSettings.url += (/\?/.test( requestSettings.url ) ? "&" : "?") +
+ (requestSettings.jsonp || "callback") + "=?";
+ }
+ } else if ( !requestSettings.data || !CALLBACK_REGEX.test(requestSettings.data) ) {
+ requestSettings.data = (requestSettings.data ? requestSettings.data + "&" : "") + (requestSettings.jsonp || "callback") + "=?";
+ }
+ }
+
+ // Process a JSONP request by evaluating the mocked response text
+ function processJsonpRequest( requestSettings, mockHandler, origSettings ) {
+ // Synthesize the mock request for adding a script tag
+ var callbackContext = origSettings && origSettings.context || requestSettings,
+ newMock = null;
+
+
+ // If the response handler on the moock is a function, call it
+ if ( mockHandler.response && $.isFunction(mockHandler.response) ) {
+ mockHandler.response(origSettings);
+ } else {
+
+ // Evaluate the responseText javascript in a global context
+ if( typeof mockHandler.responseText === 'object' ) {
+ $.globalEval( '(' + JSON.stringify( mockHandler.responseText ) + ')');
+ } else {
+ $.globalEval( '(' + mockHandler.responseText + ')');
+ }
+ }
+
+ // Successful response
+ jsonpSuccess( requestSettings, callbackContext, mockHandler );
+ jsonpComplete( requestSettings, callbackContext, mockHandler );
+
+ // If we are running under jQuery 1.5+, return a deferred object
+ if($.Deferred){
+ newMock = new $.Deferred();
+ if(typeof mockHandler.responseText == "object"){
+ newMock.resolveWith( callbackContext, [mockHandler.responseText] );
+ }
+ else{
+ newMock.resolveWith( callbackContext, [$.parseJSON( mockHandler.responseText )] );
+ }
+ }
+ return newMock;
+ }
+
+
+ // Create the required JSONP callback function for the request
+ function createJsonpCallback( requestSettings, mockHandler, origSettings ) {
+ var callbackContext = origSettings && origSettings.context || requestSettings;
+ var jsonp = requestSettings.jsonpCallback || ("jsonp" + jsc++);
+
+ // Replace the =? sequence both in the query string and the data
+ if ( requestSettings.data ) {
+ requestSettings.data = (requestSettings.data + "").replace(CALLBACK_REGEX, "=" + jsonp + "$1");
+ }
+
+ requestSettings.url = requestSettings.url.replace(CALLBACK_REGEX, "=" + jsonp + "$1");
+
+
+ // Handle JSONP-style loading
+ window[ jsonp ] = window[ jsonp ] || function( tmp ) {
+ data = tmp;
+ jsonpSuccess( requestSettings, callbackContext, mockHandler );
+ jsonpComplete( requestSettings, callbackContext, mockHandler );
+ // Garbage collect
+ window[ jsonp ] = undefined;
+
+ try {
+ delete window[ jsonp ];
+ } catch(e) {}
+
+ if ( head ) {
+ head.removeChild( script );
+ }
+ };
+ }
+
+ // The JSONP request was successful
+ function jsonpSuccess(requestSettings, callbackContext, mockHandler) {
+ // If a local callback was specified, fire it and pass it the data
+ if ( requestSettings.success ) {
+ requestSettings.success.call( callbackContext, mockHandler.responseText || "", status, {} );
+ }
+
+ // Fire the global callback
+ if ( requestSettings.global ) {
+ trigger(requestSettings, "ajaxSuccess", [{}, requestSettings] );
+ }
+ }
+
+ // The JSONP request was completed
+ function jsonpComplete(requestSettings, callbackContext) {
+ // Process result
+ if ( requestSettings.complete ) {
+ requestSettings.complete.call( callbackContext, {} , status );
+ }
+
+ // The request was completed
+ if ( requestSettings.global ) {
+ trigger( "ajaxComplete", [{}, requestSettings] );
+ }
+
+ // Handle the global AJAX counter
+ if ( requestSettings.global && ! --$.active ) {
+ $.event.trigger( "ajaxStop" );
+ }
+ }
+
+
+ // The core $.ajax replacement.
+ function handleAjax( url, origSettings ) {
+ var mockRequest, requestSettings, mockHandler;
+
+ // If url is an object, simulate pre-1.5 signature
+ if ( typeof url === "object" ) {
+ origSettings = url;
+ url = undefined;
+ } else {
+ // work around to support 1.5 signature
+ origSettings.url = url;
+ }
+
+ // Extend the original settings for the request
+ requestSettings = $.extend(true, {}, $.ajaxSettings, origSettings);
+
+ // Iterate over our mock handlers (in registration order) until we find
+ // one that is willing to intercept the request
+ for(var k = 0; k < mockHandlers.length; k++) {
+ if ( !mockHandlers[k] ) {
+ continue;
+ }
+
+ mockHandler = getMockForRequest( mockHandlers[k], requestSettings );
+ if(!mockHandler) {
+ // No valid mock found for this request
+ continue;
+ }
+
+ mockedAjaxCalls.push(requestSettings);
+
+ // If logging is enabled, log the mock to the console
+ $.mockjaxSettings.log( mockHandler, requestSettings );
+
+
+ if ( requestSettings.dataType === "jsonp" ) {
+ if ((mockRequest = processJsonpMock( requestSettings, mockHandler, origSettings ))) {
+ // This mock will handle the JSONP request
+ return mockRequest;
+ }
+ }
+
+
+ // Removed to fix #54 - keep the mocking data object intact
+ //mockHandler.data = requestSettings.data;
+
+ mockHandler.cache = requestSettings.cache;
+ mockHandler.timeout = requestSettings.timeout;
+ mockHandler.global = requestSettings.global;
+
+ copyUrlParameters(mockHandler, origSettings);
+
+ (function(mockHandler, requestSettings, origSettings, origHandler) {
+ mockRequest = _ajax.call($, $.extend(true, {}, origSettings, {
+ // Mock the XHR object
+ xhr: function() { return xhr( mockHandler, requestSettings, origSettings, origHandler ); }
+ }));
+ })(mockHandler, requestSettings, origSettings, mockHandlers[k]);
+
+ return mockRequest;
+ }
+
+ // We don't have a mock request
+ if($.mockjaxSettings.throwUnmocked === true) {
+ throw('AJAX not mocked: ' + origSettings.url);
+ }
+ else { // trigger a normal request
+ return _ajax.apply($, [origSettings]);
+ }
+ }
+
+ /**
+ * Copies URL parameter values if they were captured by a regular expression
+ * @param {Object} mockHandler
+ * @param {Object} origSettings
+ */
+ function copyUrlParameters(mockHandler, origSettings) {
+ //parameters aren't captured if the URL isn't a RegExp
+ if (!(mockHandler.url instanceof RegExp)) {
+ return;
+ }
+ //if no URL params were defined on the handler, don't attempt a capture
+ if (!mockHandler.hasOwnProperty('urlParams')) {
+ return;
+ }
+ var captures = mockHandler.url.exec(origSettings.url);
+ //the whole RegExp match is always the first value in the capture results
+ if (captures.length === 1) {
+ return;
+ }
+ captures.shift();
+ //use handler params as keys and capture resuts as values
+ var i = 0,
+ capturesLength = captures.length,
+ paramsLength = mockHandler.urlParams.length,
+ //in case the number of params specified is less than actual captures
+ maxIterations = Math.min(capturesLength, paramsLength),
+ paramValues = {};
+ for (i; i < maxIterations; i++) {
+ var key = mockHandler.urlParams[i];
+ paramValues[key] = captures[i];
+ }
+ origSettings.urlParams = paramValues;
+ }
+
+
+ // Public
+
+ $.extend({
+ ajax: handleAjax
+ });
+
+ $.mockjaxSettings = {
+ //url: null,
+ //type: 'GET',
+ log: function( mockHandler, requestSettings ) {
+ if ( mockHandler.logging === false ||
+ ( typeof mockHandler.logging === 'undefined' && $.mockjaxSettings.logging === false ) ) {
+ return;
+ }
+ if ( window.console && console.log ) {
+ var message = 'MOCK ' + requestSettings.type.toUpperCase() + ': ' + requestSettings.url;
+ var request = $.extend({}, requestSettings);
+
+ if (typeof console.log === 'function') {
+ console.log(message, request);
+ } else {
+ try {
+ console.log( message + ' ' + JSON.stringify(request) );
+ } catch (e) {
+ console.log(message);
+ }
+ }
+ }
+ },
+ logging: true,
+ status: 200,
+ statusText: "OK",
+ responseTime: 500,
+ isTimeout: false,
+ throwUnmocked: false,
+ contentType: 'text/plain',
+ response: '',
+ responseText: '',
+ responseXML: '',
+ proxy: '',
+ proxyType: 'GET',
+
+ lastModified: null,
+ etag: '',
+ headers: {
+ etag: 'IJF@H#@923uf8023hFO@I#H#',
+ 'content-type' : 'text/plain'
+ }
+ };
+
+ $.mockjax = function(settings) {
+ var i = mockHandlers.length;
+ mockHandlers[i] = settings;
+ return i;
+ };
+ $.mockjaxClear = function(i) {
+ if ( arguments.length == 1 ) {
+ mockHandlers[i] = null;
+ } else {
+ mockHandlers = [];
+ }
+ mockedAjaxCalls = [];
+ };
+ $.mockjax.handler = function(i) {
+ if ( arguments.length == 1 ) {
+ return mockHandlers[i];
+ }
+ };
+ $.mockjax.mockedAjaxCalls = function() {
+ return mockedAjaxCalls;
+ };
+})(jQuery);
diff --git a/sonar-server/src/main/webapp/javascripts/translate.js b/sonar-server/src/main/webapp/javascripts/translate.js
index 3803a031c41..9795da08b27 100644
--- a/sonar-server/src/main/webapp/javascripts/translate.js
+++ b/sonar-server/src/main/webapp/javascripts/translate.js
@@ -25,16 +25,20 @@
return prev.concat(current.split('.'));
}, []),
key = tokens.join('.'),
- start = window.SS.phrases,
- found = true;
+ start = window.SS && window.SS.phrases,
+ found = !!start;
- var result = tokens.reduce(function(prev, current) {
- if (!current || !prev[current]) {
- warn('No translation for "' + key + '"');
- found = false;
- }
- return current ? prev[current] : prev;
- }, start);
+ if (found) {
+ var result = tokens.reduce(function(prev, current) {
+ if (!current || !prev[current]) {
+ warn('No translation for "' + key + '"');
+ found = false;
+ }
+ return current ? prev[current] : prev;
+ }, start);
+ } else {
+ warn('No translation for "' + key + '"');
+ }
return found ? result : key;
};
diff --git a/sonar-server/src/main/webapp/stylesheets/coding-rules.css b/sonar-server/src/main/webapp/stylesheets/coding-rules.css
new file mode 100644
index 00000000000..ec1de36b2cf
--- /dev/null
+++ b/sonar-server/src/main/webapp/stylesheets/coding-rules.css
@@ -0,0 +1,67 @@
+/*
+ * Fonts
+ */
+/*
+ * Colors
+ */
+/*
+ * Icons
+ */
+/*
+ * Transitions
+ */
+.coding-rules-page .navigator-results .spinner {
+ margin: 10px;
+}
+/*
+ * Detail
+ */
+.coding-rules-detail-header {
+ margin-bottom: 10px;
+ font-weight: bold;
+ text-transform: uppercase;
+}
+.coding-rules-detail-language {
+ margin-bottom: 10px;
+}
+.coding-rules-detail-description {
+ padding: 10px;
+ background-color: #efefef;
+}
+.coding-rules-detail-description *:first-child {
+ margin-top: 0;
+ padding-top: 0;
+}
+.coding-rules-detail-description *:last-child {
+ margin-bottom: 0;
+ padding-bottom: 0;
+}
+.coding-rules-detail-quality-profiles-header {
+ margin-top: 20px;
+}
+.coding-rules-detail-quality-profile + .coding-rules-detail-quality-profile {
+ margin-top: 10px;
+}
+.coding-rules-detail-quality-profile-severity,
+.coding-rules-detail-quality-profile-name,
+.coding-rules-detail-quality-profile-actions {
+ display: inline-block;
+ vertical-align: middle;
+}
+.coding-rules-detail-quality-profile-parameters {
+ padding-left: 30px;
+}
+.coding-rules-detail-quality-profile-parameter {
+ margin: 5px;
+}
+.coding-rules-detail-quality-profile-parameter-key,
+.coding-rules-detail-quality-profile-parameter-value,
+.coding-rules-detail-quality-profile-parameter-actions {
+ vertical-align: middle;
+}
+.coding-rules-detail-quality-profile-parameter-key:after {
+ content: ":";
+}
+.coding-rules-detail-quality-profiles-activation {
+ margin-top: 10px;
+}
diff --git a/sonar-server/src/main/webapp/stylesheets/coding-rules.less b/sonar-server/src/main/webapp/stylesheets/coding-rules.less
new file mode 100644
index 00000000000..7f17fed1fed
--- /dev/null
+++ b/sonar-server/src/main/webapp/stylesheets/coding-rules.less
@@ -0,0 +1,82 @@
+@import 'mixins';
+@import 'variables';
+@import 'navigator/config';
+
+
+.coding-rules-page {
+
+ .navigator-results .spinner {
+ margin: @navigatorPadding;
+ }
+
+}
+
+
+
+/*
+ * Detail
+ */
+
+.coding-rules-detail-header {
+ margin-bottom: @navigatorPadding;
+ font-weight: bold;
+ text-transform: uppercase;
+}
+
+.coding-rules-detail-language {
+ margin-bottom: @navigatorPadding;
+}
+
+.coding-rules-detail-description {
+ padding: @navigatorPadding;
+ background-color: @navigatorBarBackground;
+
+ *:first-child {
+ margin-top: 0;
+ padding-top: 0;
+ }
+
+ *:last-child {
+ margin-bottom: 0;
+ padding-bottom: 0;
+ }
+}
+
+.coding-rules-detail-quality-profiles-header {
+ margin-top: 2 * @navigatorPadding;
+}
+
+.coding-rules-detail-quality-profile + .coding-rules-detail-quality-profile {
+ margin-top: @navigatorPadding;
+}
+
+.coding-rules-detail-quality-profile-severity,
+.coding-rules-detail-quality-profile-name,
+.coding-rules-detail-quality-profile-actions {
+ display: inline-block;
+ vertical-align: middle;
+}
+
+.coding-rules-detail-quality-profile-parameters {
+ padding-left: 3 * @navigatorPadding;
+}
+
+.coding-rules-detail-quality-profile-parameter {
+ margin: @navigatorPadding / 2;
+}
+
+.coding-rules-detail-quality-profile-parameter-key,
+.coding-rules-detail-quality-profile-parameter-value,
+.coding-rules-detail-quality-profile-parameter-actions {
+ vertical-align: middle;
+}
+
+.coding-rules-detail-quality-profile-parameter-key {
+ &:after {
+ content: ":";
+ }
+}
+
+.coding-rules-detail-quality-profiles-activation {
+ margin-top: @navigatorPadding;
+}
diff --git a/sonar-server/src/main/webapp/stylesheets/navigator.css b/sonar-server/src/main/webapp/stylesheets/navigator.css
index 8d05fbe50dc..5f6f6d6ee4c 100644
--- a/sonar-server/src/main/webapp/stylesheets/navigator.css
+++ b/sonar-server/src/main/webapp/stylesheets/navigator.css
@@ -115,6 +115,9 @@
z-index: 3;
background-color: #E4ECF3;
}
+.navigator-page-loader {
+ padding: 10px 0 0 10px;
+}
.navigator-header {
padding: 0 10px;
border-bottom: 1px solid #cdcdcd;
@@ -221,16 +224,22 @@
left: 0;
width: 319px;
}
-.navigator-results-no-issues {
- padding-top: 20%;
+.navigator-results-no-results {
+ padding-top: 20% !important;
+ background: #fff !important;
color: #999;
+ cursor: default !important;
text-align: center;
}
.navigator-details {
- padding: 62px 0 10px 10px;
+ padding: 10px;
background-color: #ffffff;
overflow: auto;
}
+.issues-page .navigator-details {
+ padding-top: 62px;
+ padding-right: 0;
+}
.navigator-details.loading {
background: #ffffff url("../images/loading.gif") no-repeat 4px 2px;
}
diff --git a/sonar-server/src/main/webapp/stylesheets/navigator/base.css b/sonar-server/src/main/webapp/stylesheets/navigator/base.css
index 54905a0c2b7..e3624fbb247 100644
--- a/sonar-server/src/main/webapp/stylesheets/navigator/base.css
+++ b/sonar-server/src/main/webapp/stylesheets/navigator/base.css
@@ -115,6 +115,9 @@
z-index: 3;
background-color: #E4ECF3;
}
+.navigator-page-loader {
+ padding: 10px 0 0 10px;
+}
.navigator-header {
padding: 0 10px;
border-bottom: 1px solid #cdcdcd;
@@ -221,16 +224,22 @@
left: 0;
width: 319px;
}
-.navigator-results-no-issues {
- padding-top: 20%;
+.navigator-results-no-results {
+ padding-top: 20% !important;
+ background: #fff !important;
color: #999;
+ cursor: default !important;
text-align: center;
}
.navigator-details {
- padding: 62px 0 10px 10px;
+ padding: 10px;
background-color: #ffffff;
overflow: auto;
}
+.issues-page .navigator-details {
+ padding-top: 62px;
+ padding-right: 0;
+}
.navigator-details.loading {
background: #ffffff url("../images/loading.gif") no-repeat 4px 2px;
}
diff --git a/sonar-server/src/main/webapp/stylesheets/navigator/base.less b/sonar-server/src/main/webapp/stylesheets/navigator/base.less
index 0688cb68c9a..63cf9f8267f 100644
--- a/sonar-server/src/main/webapp/stylesheets/navigator/base.less
+++ b/sonar-server/src/main/webapp/stylesheets/navigator/base.less
@@ -120,6 +120,11 @@
}
+.navigator-page-loader {
+ padding: @navigatorPadding 0 0 @navigatorPadding;
+}
+
+
// Header
.navigator-header {
@@ -263,9 +268,11 @@
}
}
-.navigator-results-no-issues {
- padding-top: 20%;
+.navigator-results-no-results {
+ padding-top: 20% !important;
+ background: #fff !important;
color: #999;
+ cursor: default !important;
text-align: center;
}
@@ -273,10 +280,15 @@
// Details
.navigator-details {
- padding: 62px 0 @navigatorPadding @navigatorPadding;
+ padding: @navigatorPadding;
background-color: @white;
overflow: auto;
+ .issues-page & {
+ padding-top: 62px;
+ padding-right: 0;
+ }
+
&.loading {
background: @white url("../images/loading.gif") no-repeat 4px 2px;
}
diff --git a/sonar-server/src/main/webapp/stylesheets/quality-gates.css b/sonar-server/src/main/webapp/stylesheets/quality-gates.css
index a201ca52428..dc1db977142 100644
--- a/sonar-server/src/main/webapp/stylesheets/quality-gates.css
+++ b/sonar-server/src/main/webapp/stylesheets/quality-gates.css
@@ -10,335 +10,6 @@
/*
* Transitions
*/
-.navigator-header {
- position: fixed;
- z-index: 2;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- top: 30px;
- left: 0;
- width: 100%;
- height: 37px;
-}
-.navigator-filters {
- position: fixed;
- z-index: 2;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- top: 67px;
- left: 0;
- width: 100%;
- height: 37px;
-}
-.navigator-results {
- position: fixed;
- z-index: 2;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- -moz-box-sizing: content-box;
- box-sizing: content-box;
- top: 134px;
- bottom: 0;
- left: 0;
- width: 319px;
-}
-.navigator-details {
- position: fixed;
- z-index: 2;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- top: 104px;
- bottom: 35px;
- left: 320px;
- right: 0;
-}
-.navigator-actions {
- position: fixed;
- z-index: 2;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- top: 104px;
- left: 0;
- width: 320px;
- height: 30px;
-}
-.navigator-notes {
- position: fixed;
- z-index: 2;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- top: 104px;
- left: 0;
- width: 100%;
- height: 20px;
- display: none;
-}
-.measures-page .navigator-results {
- top: 104px;
- left: 0;
- width: 100%;
-}
-.navigator-with-notes .navigator-actions,
-.navigator-with-notes .navigator-details {
- top: 124px;
-}
-.navigator-with-notes .navigator-results {
- top: 154px;
-}
-.navigator-with-notes .navigator-notes {
- display: block;
-}
-.navigator-with-notes .navigator-details .source_title {
- top: 124px;
-}
-.navigator-fetching:before {
- content: " ";
- position: absolute;
- z-index: 3;
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
- background: #ffffff url(../images/loading.gif) no-repeat 4px 4px;
-}
-.navigator-fetching#tab-issue-rule {
- position: relative;
-}
-.navigator-fetching#tab-issue-rule:before {
- z-index: 3;
- background-color: #EFEFEF;
-}
-.navigator-fetching.code-issue-actions {
- position: relative;
-}
-.navigator-fetching.code-issue-actions:before {
- z-index: 3;
- background-color: #E4ECF3;
-}
-.navigator-header {
- padding: 0 10px;
- border-bottom: 1px solid #cdcdcd;
- background-color: #efefef;
- font-size: 0;
-}
-.navigator-header-favorite {
- padding-left: 46px;
-}
-.navigator-header-title {
- display: inline-block;
- vertical-align: middle;
- font-size: 20px;
- line-height: 37px;
-}
-.navigator-header-description {
- display: inline-block;
- vertical-align: middle;
- margin-left: 16px;
- font-size: 11px;
- font-style: italic;
-}
-.navigator-header-actions {
- margin-left: 16px;
-}
-.navigator-header-actions > a {
- vertical-align: middle;
- margin: 0 8px;
- font-size: 11px;
-}
-.navigator-notes {
- padding: 0 10px;
- border-bottom: 1px solid #cdcdcd;
- background-color: #efefef;
- color: #777;
- font-size: 11px;
- line-height: 20px;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-.navigator-results {
- border-right: 1px solid #e1e1e1;
- background-color: #ffffff;
- overflow-x: hidden;
- overflow-y: auto;
-}
-.navigator-results-list > li {
- padding: 5px 0;
- cursor: pointer;
- transition: all 0.3s ease;
-}
-.navigator-results-list > li:first-child {
- border-top: 1px solid transparent;
-}
-.navigator-results-list > li:first-child.active {
- border-top-color: #4B9FD5;
-}
-.navigator-results-list > li:last-child {
- border-bottom: 1px solid transparent;
-}
-.navigator-results-list > li:last-child.active {
- border-bottom-color: #4B9FD5;
-}
-.navigator-results-list > li .line {
- padding: 5px 10px;
- line-height: 1.2;
-}
-.navigator-results-list > li .line-small {
- font-size: 11px;
- line-height: 14px;
-}
-.navigator-results-list > li .line-right {
- float: right;
-}
-.navigator-results-list > li .line-nowrap {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-.navigator-results-list > li:hover {
- background-color: #efefef;
-}
-.navigator-results-list > li.active {
- background-color: #CAE3F2;
- border-color: #4B9FD5;
-}
-.navigator-results-list > li + li {
- border-top: 1px solid #e1e1e1;
-}
-.navigator-results-list > li.active + li {
- border-top-color: #4B9FD5;
-}
-.navigator-results-list.navigator-fetching > li .line-nowrap {
- text-overflow: clip;
- /* thanks to FF */
-
-}
-.navigator-results-list.navigator-fetching:before {
- position: fixed;
- z-index: 3;
- top: 134px;
- bottom: 0;
- left: 0;
- width: 319px;
-}
-.navigator-results-no-issues {
- padding-top: 20%;
- color: #999;
- text-align: center;
-}
-.navigator-details {
- padding: 62px 0 10px 10px;
- background-color: #ffffff;
- overflow: auto;
-}
-.navigator-details.loading {
- background: #ffffff url("../images/loading.gif") no-repeat 4px 2px;
-}
-.navigator-details .code-issue-name {
- border-bottom: none;
-}
-.navigator-details .code-issue-actions {
- background-color: #E4ECF3;
-}
-.navigator-details .source_title {
- position: fixed;
- z-index: 3;
- top: 104px;
- left: 320px;
- right: 0;
- padding: 10px;
- border-bottom: 1px solid #e1e1e1;
- background-color: #fff;
-}
-.navigator-details .source {
- padding-right: 10px;
-}
-.navigator-details .source > table {
- border: 1px solid #DDD;
-}
-.navigator-details .scm .author {
- display: inline-block;
- vertical-align: middle;
- max-width: 100px;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-.navigator-actions {
- padding: 0 10px 0 0;
- border-right: 1px solid #e1e1e1;
- border-bottom: 1px solid #e1e1e1;
- background-color: #efefef;
- font-size: 11px;
-}
-.navigator-actions strong {
- font-weight: bold;
-}
-.navigator-actions-order {
- float: left;
- padding: 0 10px;
- line-height: 30px;
- cursor: pointer;
- transition: all 0.3s ease;
-}
-.navigator-actions-order:hover {
- background-color: #efefef;
-}
-.navigator-actions-order-choices {
- position: fixed;
- z-index: 2;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- top: 134px;
- left: 0;
- min-width: 160px;
- background-color: #fff;
- border-bottom: 1px solid #e1e1e1;
- border-right: 1px solid #e1e1e1;
- overflow: hidden;
- display: none;
-}
-.navigator-actions-order-choices > li {
- height: 30px;
- line-height: 30px;
- padding: 0 10px;
- cursor: pointer;
- transition: all 0.3s ease;
-}
-.navigator-actions-order-choices > li:hover {
- background-color: #efefef;
-}
-.navigator-actions-order-choices.open {
- display: block;
-}
-.navigator-actions-total {
- float: right;
- line-height: 26px;
-}
-.navigator-actions-bulk {
- position: relative;
- top: -1px;
- margin-left: 8px;
- font-size: 16px;
- text-decoration: none;
-}
-.navigator-page #footer {
- position: fixed;
- z-index: 2;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- bottom: 0;
- left: 320px;
- right: 0;
- margin: 0;
- border-top: 1px solid #e1e1e1;
-}
-.navigator-page #ftlinks {
- margin-top: 0;
-}
-.quality-gate-page-loader {
- padding: 10px 0 0 10px;
-}
.quality-gates-navigator .navigator-header {
left: 230px;
border-color: #cdcdcd;
diff --git a/sonar-server/src/main/webapp/stylesheets/quality-gates.less b/sonar-server/src/main/webapp/stylesheets/quality-gates.less
index da953c02e60..a0293d5e1b3 100644
--- a/sonar-server/src/main/webapp/stylesheets/quality-gates.less
+++ b/sonar-server/src/main/webapp/stylesheets/quality-gates.less
@@ -1,13 +1,9 @@
@import "variables";
@import "mixins";
-@import "navigator/base";
+@import "navigator/config";
@qualityGateSidebarWidth: 230px;
-.quality-gate-page-loader {
- padding: @navigatorPadding 0 0 @navigatorPadding;
-}
-
.quality-gates-navigator {
.navigator-header {
diff --git a/sonar-server/src/main/webapp/stylesheets/variables.less b/sonar-server/src/main/webapp/stylesheets/variables.less
index 95cedc2ef2b..2f40167a92c 100644
--- a/sonar-server/src/main/webapp/stylesheets/variables.less
+++ b/sonar-server/src/main/webapp/stylesheets/variables.less
@@ -5,6 +5,7 @@
@baseFontSize: 13px;
@baseFontColor: #444;
@smallFontSize: 11px;
+@headerFontSize: 16px;