]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5007 Add first POC
authorStas Vilchik <vilchiks@gmail.com>
Thu, 6 Mar 2014 16:36:10 +0000 (17:36 +0100)
committerStas Vilchik <vilchiks@gmail.com>
Thu, 6 Mar 2014 16:36:17 +0000 (17:36 +0100)
65 files changed:
plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties
sonar-server/src/main/webapp/WEB-INF/app/controllers/coding_rules_controller.rb [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/app/models/navigation.rb
sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/index.html.erb [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_actions_template.hbs.erb [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_detail_template.hbs.erb [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_filter_bar_template.hbs.erb [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_header_template.hbs.erb [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_layout.hbs.erb [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_list_empty_template.hbs.erb [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/app/views/coding_rules/templates/_coding_rules_list_item_template.hbs.erb [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/app/views/issues/templates/_no_issues.hbs.erb
sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_head.html.erb
sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb
sonar-server/src/main/webapp/WEB-INF/app/views/navigator/templates/_more_criteria_filter_template.hbs.erb
sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/index.html.erb
sonar-server/src/main/webapp/javascripts/coding-rules/app.coffee [new file with mode: 0644]
sonar-server/src/main/webapp/javascripts/coding-rules/app.js [new file with mode: 0644]
sonar-server/src/main/webapp/javascripts/coding-rules/collections/coding-rules.coffee [new file with mode: 0644]
sonar-server/src/main/webapp/javascripts/coding-rules/collections/coding-rules.js [new file with mode: 0644]
sonar-server/src/main/webapp/javascripts/coding-rules/layout.coffee [new file with mode: 0644]
sonar-server/src/main/webapp/javascripts/coding-rules/layout.js [new file with mode: 0644]
sonar-server/src/main/webapp/javascripts/coding-rules/mockjax.coffee [new file with mode: 0644]
sonar-server/src/main/webapp/javascripts/coding-rules/mockjax.js [new file with mode: 0644]
sonar-server/src/main/webapp/javascripts/coding-rules/models/coding-rule.coffee [new file with mode: 0644]
sonar-server/src/main/webapp/javascripts/coding-rules/models/coding-rule.js [new file with mode: 0644]
sonar-server/src/main/webapp/javascripts/coding-rules/router.coffee [new file with mode: 0644]
sonar-server/src/main/webapp/javascripts/coding-rules/router.js [new file with mode: 0644]
sonar-server/src/main/webapp/javascripts/coding-rules/views/actions-view.coffee [new file with mode: 0644]
sonar-server/src/main/webapp/javascripts/coding-rules/views/actions-view.js [new file with mode: 0644]
sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-detail-view.coffee [new file with mode: 0644]
sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-detail-view.js [new file with mode: 0644]
sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-list-empty-view.coffee [new file with mode: 0644]
sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-list-empty-view.js [new file with mode: 0644]
sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-list-item-view.coffee [new file with mode: 0644]
sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-list-item-view.js [new file with mode: 0644]
sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-list-view.coffee [new file with mode: 0644]
sonar-server/src/main/webapp/javascripts/coding-rules/views/coding-rules-list-view.js [new file with mode: 0644]
sonar-server/src/main/webapp/javascripts/coding-rules/views/filter-bar-view.coffee [new file with mode: 0644]
sonar-server/src/main/webapp/javascripts/coding-rules/views/filter-bar-view.js [new file with mode: 0644]
sonar-server/src/main/webapp/javascripts/coding-rules/views/filters/quality-profile-filter-view.coffee [new file with mode: 0644]
sonar-server/src/main/webapp/javascripts/coding-rules/views/filters/quality-profile-filter-view.js [new file with mode: 0644]
sonar-server/src/main/webapp/javascripts/coding-rules/views/header-view.coffee [new file with mode: 0644]
sonar-server/src/main/webapp/javascripts/coding-rules/views/header-view.js [new file with mode: 0644]
sonar-server/src/main/webapp/javascripts/issues/extra.js
sonar-server/src/main/webapp/javascripts/navigator/filters/ajax-select-filters.js
sonar-server/src/main/webapp/javascripts/navigator/filters/choice-filters.js
sonar-server/src/main/webapp/javascripts/navigator/filters/filter-bar.js
sonar-server/src/main/webapp/javascripts/quality-gate/app.coffee
sonar-server/src/main/webapp/javascripts/quality-gate/app.js
sonar-server/src/main/webapp/javascripts/quality-gate/layout.coffee
sonar-server/src/main/webapp/javascripts/quality-gate/layout.js
sonar-server/src/main/webapp/javascripts/tests/translateSpec.coffee
sonar-server/src/main/webapp/javascripts/tests/translateSpec.js
sonar-server/src/main/webapp/javascripts/third-party/jquery.mockjax.js [new file with mode: 0644]
sonar-server/src/main/webapp/javascripts/translate.js
sonar-server/src/main/webapp/stylesheets/coding-rules.css [new file with mode: 0644]
sonar-server/src/main/webapp/stylesheets/coding-rules.less [new file with mode: 0644]
sonar-server/src/main/webapp/stylesheets/navigator.css
sonar-server/src/main/webapp/stylesheets/navigator/base.css
sonar-server/src/main/webapp/stylesheets/navigator/base.less
sonar-server/src/main/webapp/stylesheets/quality-gates.css
sonar-server/src/main/webapp/stylesheets/quality-gates.less
sonar-server/src/main/webapp/stylesheets/variables.less
sonar-server/wro.xml

index a03ed679bf6d4c591c68e1ad0f14eac3ea99beae..15d05d37653a9dd2b9f5100e77892a36bd72393d 100644 (file)
@@ -363,6 +363,7 @@ sidebar.tools=Tools
 
 action_plans.page=Action Plans
 action_plans.page.description=Create and administer Action Plans for this project. Action Plans allow you to prioritize and group issues, and to monitor progress on those groups.
+coding_rules.page=Coding Rules
 global_permissions.page=Global Permissions
 global_permissions.page.description=Grant and revoke permissions to make changes at the global level. These permissions include editing quality profiles, sharing dashboards, and performing global system administration.
 manual_metrics.page=Manual Metrics
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 (file)
index 0000000..c06947b
--- /dev/null
@@ -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
index 5dc495bdc2906214831eb790c2ea4d9d4c7002bf..22c1ae1e64ab30fad599bfbbf074f6823ee95e4c 100644 (file)
@@ -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 (file)
index 0000000..e5bb24f
--- /dev/null
@@ -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 (file)
index 0000000..3cea3eb
--- /dev/null
@@ -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 (file)
index 0000000..18aad2a
--- /dev/null
@@ -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 (file)
index 0000000..9ca665e
--- /dev/null
@@ -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 (file)
index 0000000..bfee909
--- /dev/null
@@ -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 (file)
index 0000000..debdccc
--- /dev/null
@@ -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 (file)
index 0000000..011edf1
--- /dev/null
@@ -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 (file)
index 0000000..82f1214
--- /dev/null
@@ -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>
index 34ac7da045700ff1b2e29ff17efafcfd82568559..fe956141c567f5774a05447525a564246a29c3a9 100644 (file)
@@ -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>
index f1dc7f7d8bec8946a13a7da12a693fb95e010227..92221785ae68d2480198453573db49c1b05d0610 100644 (file)
@@ -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' %>
index 48e9b19095efe1c44ba5af31640d628328f3af41..ecec918cc28ad1395aa1e669e261e3974835bad3 100644 (file)
@@ -24,6 +24,9 @@
         <li>
           <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>
index b2f7e3ffae16a0eeb5f620706d47f86046886ad9..c1159abf4645bc4d90781129c783b497eec49011 100644 (file)
@@ -1,3 +1,3 @@
 <script id="more-criteria-filter-template" type="text/x-handlebars-template">
-  {{translate "moreCriteria"}}
+  {{t "moreCriteria"}}
 </script>
index 5402dcae379e4701a3e8b75605e3477459f46477..37251d2951d6b22b8f5d45a660ccc655b537a856 100644 (file)
@@ -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 (file)
index 0000000..81c81b6
--- /dev/null
@@ -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 (file)
index 0000000..4736322
--- /dev/null
@@ -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 (file)
index 0000000..b24c751
--- /dev/null
@@ -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 (file)
index 0000000..14264ad
--- /dev/null
@@ -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 (file)
index 0000000..0e3abd4
--- /dev/null
@@ -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 (file)
index 0000000..91d7c10
--- /dev/null
@@ -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 (file)
index 0000000..efaaa42
--- /dev/null
@@ -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 (file)
index 0000000..26c8b1b
--- /dev/null
@@ -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 (file)
index 0000000..7561848
--- /dev/null
@@ -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 (file)
index 0000000..accd6f9
--- /dev/null
@@ -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 (file)
index 0000000..7d55132
--- /dev/null
@@ -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 (file)
index 0000000..2fa7aac
--- /dev/null
@@ -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 (file)
index 0000000..8220be5
--- /dev/null
@@ -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 (file)
index 0000000..d2cefc3
--- /dev/null
@@ -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 (file)
index 0000000..0f5c741
--- /dev/null
@@ -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 (file)
index 0000000..06fd652
--- /dev/null
@@ -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 (file)
index 0000000..203fcad
--- /dev/null
@@ -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 (file)
index 0000000..828d78f
--- /dev/null
@@ -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 (file)
index 0000000..844a446
--- /dev/null
@@ -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 (file)
index 0000000..1d9895a
--- /dev/null
@@ -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 (file)
index 0000000..93db305
--- /dev/null
@@ -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 (file)
index 0000000..b8a8243
--- /dev/null
@@ -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 (file)
index 0000000..f6b7cf4
--- /dev/null
@@ -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 (file)
index 0000000..475ac88
--- /dev/null
@@ -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 (file)
index 0000000..3561ff9
--- /dev/null
@@ -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 (file)
index 0000000..a8ce1a5
--- /dev/null
@@ -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 (file)
index 0000000..b14bb29
--- /dev/null
@@ -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 (file)
index 0000000..21891da
--- /dev/null
@@ -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);
index 2c5bdbd7e0c1d1e74291550432af5425ddd0f05d..89b29704a67e9f9900455eb582d3776e2d1f3db7 100644 (file)
@@ -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() || '')
       });
 
index 070164abf0f46a580329f061e80306096a7b61cd..dd2e246d217986f99bfc5f24f7745083b4614452 100644 (file)
@@ -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;
     },
index a01b65f175f2dbe84317070b640bef4aaf027f79..cf74a21562e5b8979863917a00e7d51c6b7e8868 100644 (file)
@@ -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(', ');
     },
index 35e182d923c0229e4bfbd9f41f06332ff14f523d..a859c721382c80b61c98118da99a3311b2413267 100644 (file)
@@ -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);
+          }
         },
 
 
index 49f9bdb693bed7799416a3cf3816022f60ea5d18..ca7e143da8807794609c0a911ed4260439012ee4 100644 (file)
@@ -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()
index dd1301494f56a4e1ca9e0c7b4ecf438cf5059a63..0ffb6472aa9ee8ef143dc9a45cf094f842b78612 100644 (file)
       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({
     });
     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();
     });
   });
index bb3abdb19c10c83477e8a94b84b21c24ee22e0c3..e9805d059537a95712e6152d02468ccd017d07c9 100644 (file)
@@ -13,7 +13,7 @@ define [
     regions:
       headerRegion: '.navigator-header'
       actionsRegion: '.navigator-actions'
-      listRegion: '.navigator-results'
+      resultsRegion: '.navigator-results'
       detailsRegion: '.navigator-details'
 
 
index b18e10cdccd3e96a6fb52e5820a6ac7d095cda3e..0ffc92a02f0d6e02f3ca305818c1e824abf7aff6 100644 (file)
@@ -20,7 +20,7 @@
       AppLayout.prototype.regions = {
         headerRegion: '.navigator-header',
         actionsRegion: '.navigator-actions',
-        listRegion: '.navigator-results',
+        resultsRegion: '.navigator-results',
         detailsRegion: '.navigator-details'
       };
 
index 24185180c2306671b254d441e5d8df00db37a964..7b4576bcffff53c187c41e97dc98cdafd818ad48 100644 (file)
@@ -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'
+
index b634742ec8d7cbfa91429025b851c877cbd63665..2f3aafe26528779ac1afb12f9cd17f7e4b327a3b 100644 (file)
     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 (file)
index 0000000..b8e1314
--- /dev/null
@@ -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);
index 3803a031c4146012f2128ada7c0ddf19a217f708..9795da08b2782d68283a0cce534d4dcf72eefe83 100644 (file)
           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 (file)
index 0000000..ec1de36
--- /dev/null
@@ -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 (file)
index 0000000..7f17fed
--- /dev/null
@@ -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;
+}
index 8d05fbe50dca733774d80d9e28e5a0cab736a051..5f6f6d6ee4cab904740e442e53a3af3cec91d4c6 100644 (file)
   z-index: 3;
   background-color: #E4ECF3;
 }
+.navigator-page-loader {
+  padding: 10px 0 0 10px;
+}
 .navigator-header {
   padding: 0 10px;
   border-bottom: 1px solid #cdcdcd;
   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;
 }
index 54905a0c2b75abe165d358d78d8f267befbbf760..e3624fbb24777e6b6bdc31216794775b1e445a2f 100644 (file)
   z-index: 3;
   background-color: #E4ECF3;
 }
+.navigator-page-loader {
+  padding: 10px 0 0 10px;
+}
 .navigator-header {
   padding: 0 10px;
   border-bottom: 1px solid #cdcdcd;
   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;
 }
index 0688cb68c9a27029451d6fd857bd985b04284224..63cf9f8267f6b8964fe5c6725331c4b1f45e90ce 100644 (file)
 }
 
 
+.navigator-page-loader {
+  padding: @navigatorPadding 0 0 @navigatorPadding;
+}
+
+
 
 // Header
 .navigator-header {
   }
 }
 
-.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;
 }
 
 
 // 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;
   }
index a201ca5242856cc404583f112f958c164b599925..dc1db977142c96ced98f3dd365a08acb9f369b14 100644 (file)
 /*
  * 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;
index da953c02e60bbb3ca54d4da9936f237705327222..a0293d5e1b3273a2ff06e1a13b9fb4eb74f53681 100644 (file)
@@ -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 {
index 95cedc2ef2bcccde77be57392742e3a6a0d7e5c0..2f40167a92c172f707f6b012e339614c0a20b3a8 100644 (file)
@@ -5,6 +5,7 @@
 @baseFontSize: 13px;
 @baseFontColor: #444;
 @smallFontSize: 11px;
+@headerFontSize: 16px;
 
 
 
index 649e4569f879f5c45b3e982e4c9306d41e1a31b8..ab9a38e5cd866695f5051427b19df29538177cd6 100644 (file)
@@ -16,6 +16,7 @@
     <css>/stylesheets/select-list.css</css>
     <css>/stylesheets/navigator.css</css>
     <css>/stylesheets/quality-gates.css</css>
+    <css>/stylesheets/coding-rules.css</css>
 
     <js>/javascripts/third-party/jquery.js</js>
     <js>/javascripts/third-party/jquery-ui.js</js>