]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5820 Create a new coding rules page
authorStas Vilchik <vilchiks@gmail.com>
Thu, 18 Dec 2014 14:17:57 +0000 (15:17 +0100)
committerStas Vilchik <vilchiks@gmail.com>
Mon, 22 Dec 2014 09:46:42 +0000 (10:46 +0100)
197 files changed:
server/sonar-web/Gruntfile.coffee
server/sonar-web/src/main/coffee/coding-rules-old/app.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/layout.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/mockjax.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/router.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/views/actions-view.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-bulk-change-dropdown-view.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-bulk-change-view.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-custom-rule-creation-view.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-debt-popup-view.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-detail-custom-rule-view.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-detail-custom-rules-view.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-detail-quality-profile-view.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-detail-quality-profiles-view.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-detail-view.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-facets-view.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-list-empty-view.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-list-item-view.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-list-view.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-manual-rule-creation-view.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-parameter-popup-view.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-quality-profile-activation-view.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/views/filter-bar-view.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/views/filters/activation-filter-view.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/views/filters/active-severities-filter-view.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/views/filters/characteristic-filter-view.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/views/filters/inheritance-filter-view.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/views/filters/language-filter-view.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/views/filters/profile-dependent-filter-view.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/views/filters/quality-profile-filter-view.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/views/filters/query-filter-view.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/views/filters/repository-filter-view.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/views/filters/tag-filter-view.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules-old/views/header-view.coffee [new file with mode: 0644]
server/sonar-web/src/main/coffee/coding-rules/app.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/layout.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/mockjax.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/router.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/views/actions-view.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-bulk-change-dropdown-view.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-bulk-change-view.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-custom-rule-creation-view.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-debt-popup-view.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-detail-custom-rule-view.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-detail-custom-rules-view.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-detail-quality-profile-view.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-detail-quality-profiles-view.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-detail-view.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-facets-view.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-list-empty-view.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-list-item-view.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-list-view.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-manual-rule-creation-view.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-parameter-popup-view.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-quality-profile-activation-view.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/views/filter-bar-view.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/views/filters/activation-filter-view.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/views/filters/active-severities-filter-view.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/views/filters/characteristic-filter-view.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/views/filters/inheritance-filter-view.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/views/filters/language-filter-view.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/views/filters/profile-dependent-filter-view.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/views/filters/quality-profile-filter-view.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/views/filters/query-filter-view.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/views/filters/repository-filter-view.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/views/filters/tag-filter-view.coffee [deleted file]
server/sonar-web/src/main/coffee/coding-rules/views/header-view.coffee [deleted file]
server/sonar-web/src/main/coffee/issues/app.coffee
server/sonar-web/src/main/coffee/issues/component-viewer/main.coffee
server/sonar-web/src/main/coffee/issues/controller.coffee
server/sonar-web/src/main/coffee/issues/facets-view.coffee
server/sonar-web/src/main/coffee/issues/facets/action-plan-facet.coffee
server/sonar-web/src/main/coffee/issues/facets/assignee-facet.coffee
server/sonar-web/src/main/coffee/issues/facets/base-facet.coffee
server/sonar-web/src/main/coffee/issues/facets/creation-date-facet.coffee
server/sonar-web/src/main/coffee/issues/facets/custom-values-facet.coffee
server/sonar-web/src/main/coffee/issues/facets/resolution-facet.coffee
server/sonar-web/src/main/coffee/issues/facets/rule-facet.coffee
server/sonar-web/src/main/coffee/issues/facets/tag-facet.coffee
server/sonar-web/src/main/coffee/issues/filters-view.coffee
server/sonar-web/src/main/coffee/issues/layout.coffee
server/sonar-web/src/main/coffee/issues/models/state.coffee
server/sonar-web/src/main/coffee/issues/router.coffee
server/sonar-web/src/main/coffee/issues/workspace-header-view.coffee
server/sonar-web/src/main/coffee/issues/workspace-list-empty-view.coffee
server/sonar-web/src/main/coffee/issues/workspace-list-item-view.coffee
server/sonar-web/src/main/coffee/issues/workspace-list-view.coffee
server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-actions.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-bulk-change-dropdown.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-bulk-change.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-custom-rule-creation.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-custom-rule-reactivation.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-debt-popup.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-detail-custom-rule.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-detail-quality-profile.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-detail.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-facets.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-filter-bar.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-header.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-layout.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-list-empty.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-list-item.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-manual-rule-creation.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-manual-rule-reactivation.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-parameter-popup.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-profile-filter-detail.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-quality-profile-activation.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-query-filter.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-repository-detail.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules/coding-rules-actions.hbs [deleted file]
server/sonar-web/src/main/hbs/coding-rules/coding-rules-bulk-change-dropdown.hbs [deleted file]
server/sonar-web/src/main/hbs/coding-rules/coding-rules-bulk-change.hbs [deleted file]
server/sonar-web/src/main/hbs/coding-rules/coding-rules-custom-rule-creation.hbs [deleted file]
server/sonar-web/src/main/hbs/coding-rules/coding-rules-custom-rule-reactivation.hbs [deleted file]
server/sonar-web/src/main/hbs/coding-rules/coding-rules-debt-popup.hbs [deleted file]
server/sonar-web/src/main/hbs/coding-rules/coding-rules-detail-custom-rule.hbs [deleted file]
server/sonar-web/src/main/hbs/coding-rules/coding-rules-detail-quality-profile.hbs [deleted file]
server/sonar-web/src/main/hbs/coding-rules/coding-rules-detail.hbs [deleted file]
server/sonar-web/src/main/hbs/coding-rules/coding-rules-facets.hbs [deleted file]
server/sonar-web/src/main/hbs/coding-rules/coding-rules-filter-bar.hbs [deleted file]
server/sonar-web/src/main/hbs/coding-rules/coding-rules-filters.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules/coding-rules-header.hbs [deleted file]
server/sonar-web/src/main/hbs/coding-rules/coding-rules-layout.hbs
server/sonar-web/src/main/hbs/coding-rules/coding-rules-list-empty.hbs [deleted file]
server/sonar-web/src/main/hbs/coding-rules/coding-rules-list-item.hbs [deleted file]
server/sonar-web/src/main/hbs/coding-rules/coding-rules-manual-rule-creation.hbs [deleted file]
server/sonar-web/src/main/hbs/coding-rules/coding-rules-manual-rule-reactivation.hbs [deleted file]
server/sonar-web/src/main/hbs/coding-rules/coding-rules-parameter-popup.hbs [deleted file]
server/sonar-web/src/main/hbs/coding-rules/coding-rules-profile-filter-detail.hbs [deleted file]
server/sonar-web/src/main/hbs/coding-rules/coding-rules-quality-profile-activation.hbs [deleted file]
server/sonar-web/src/main/hbs/coding-rules/coding-rules-query-filter.hbs [deleted file]
server/sonar-web/src/main/hbs/coding-rules/coding-rules-repository-detail.hbs [deleted file]
server/sonar-web/src/main/hbs/coding-rules/coding-rules-rule-details.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules/coding-rules-workspace-header.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules/coding-rules-workspace-list-item.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules/coding-rules-workspace-list.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules/facets/_coding-rules-facet-header.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules/facets/coding-rules-base-facet.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules/facets/coding-rules-severity-facet.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/issues/facets/_issues-facet-header.hbs
server/sonar-web/src/main/hbs/issues/facets/issues-action-plan-facet.hbs
server/sonar-web/src/main/hbs/issues/facets/issues-assignee-facet.hbs
server/sonar-web/src/main/hbs/issues/facets/issues-base-facet.hbs
server/sonar-web/src/main/hbs/issues/facets/issues-component-facet.hbs
server/sonar-web/src/main/hbs/issues/facets/issues-creation-date-facet.hbs
server/sonar-web/src/main/hbs/issues/facets/issues-custom-values-facet.hbs
server/sonar-web/src/main/hbs/issues/facets/issues-issue-key-facet.hbs
server/sonar-web/src/main/hbs/issues/facets/issues-resolution-facet.hbs
server/sonar-web/src/main/hbs/issues/facets/issues-severity-facet.hbs
server/sonar-web/src/main/hbs/issues/facets/issues-status-facet.hbs
server/sonar-web/src/main/hbs/issues/issues-filters.hbs
server/sonar-web/src/main/hbs/issues/issues-layout.hbs
server/sonar-web/src/main/hbs/issues/issues-workspace-header.hbs
server/sonar-web/src/main/hbs/issues/issues-workspace-list.hbs
server/sonar-web/src/main/js/coding-rules/app.js [new file with mode: 0644]
server/sonar-web/src/main/js/coding-rules/controller.js [new file with mode: 0644]
server/sonar-web/src/main/js/coding-rules/facets-view.js [new file with mode: 0644]
server/sonar-web/src/main/js/coding-rules/facets/base-facet.js [new file with mode: 0644]
server/sonar-web/src/main/js/coding-rules/facets/characteristic-facet.js [new file with mode: 0644]
server/sonar-web/src/main/js/coding-rules/facets/custom-labels-facet.js [new file with mode: 0644]
server/sonar-web/src/main/js/coding-rules/facets/language-facet.js [new file with mode: 0644]
server/sonar-web/src/main/js/coding-rules/facets/quality-profile-facet.js [new file with mode: 0644]
server/sonar-web/src/main/js/coding-rules/facets/repository-facet.js [new file with mode: 0644]
server/sonar-web/src/main/js/coding-rules/facets/severity-facet.js [new file with mode: 0644]
server/sonar-web/src/main/js/coding-rules/facets/status-facet.js [new file with mode: 0644]
server/sonar-web/src/main/js/coding-rules/filters-view.js [new file with mode: 0644]
server/sonar-web/src/main/js/coding-rules/layout.js [new file with mode: 0644]
server/sonar-web/src/main/js/coding-rules/models/rule.js [new file with mode: 0644]
server/sonar-web/src/main/js/coding-rules/models/rules.js [new file with mode: 0644]
server/sonar-web/src/main/js/coding-rules/models/state.js [new file with mode: 0644]
server/sonar-web/src/main/js/coding-rules/rule-details-view.js [new file with mode: 0644]
server/sonar-web/src/main/js/coding-rules/workspace-header-view.js [new file with mode: 0644]
server/sonar-web/src/main/js/coding-rules/workspace-list-item-view.js [new file with mode: 0644]
server/sonar-web/src/main/js/coding-rules/workspace-list-view.js [new file with mode: 0644]
server/sonar-web/src/main/js/components/navigator/controller.js [new file with mode: 0644]
server/sonar-web/src/main/js/components/navigator/facets-view.js [new file with mode: 0644]
server/sonar-web/src/main/js/components/navigator/facets/base-facet.js [new file with mode: 0644]
server/sonar-web/src/main/js/components/navigator/models/facet.js [new file with mode: 0644]
server/sonar-web/src/main/js/components/navigator/models/facets.js [new file with mode: 0644]
server/sonar-web/src/main/js/components/navigator/models/state.js [new file with mode: 0644]
server/sonar-web/src/main/js/components/navigator/router.js [new file with mode: 0644]
server/sonar-web/src/main/js/components/navigator/workspace-header-view.js [new file with mode: 0644]
server/sonar-web/src/main/js/components/navigator/workspace-list-item-view.js [new file with mode: 0644]
server/sonar-web/src/main/js/components/navigator/workspace-list-view.js [new file with mode: 0644]
server/sonar-web/src/main/js/tests/e2e/tests/issues-page-spec.js
server/sonar-web/src/main/js/tests/e2e/views/coding-rules.jade
server/sonar-web/src/main/less/components.less
server/sonar-web/src/main/less/components/rules.less [new file with mode: 0644]
server/sonar-web/src/main/less/components/search-navigator.less [new file with mode: 0644]
server/sonar-web/src/main/less/issues.less
server/sonar-web/src/main/webapp/WEB-INF/app/controllers/coding_rules_old_controller.rb [new file with mode: 0644]
server/sonar-web/src/main/webapp/WEB-INF/app/models/navigation.rb
server/sonar-web/src/main/webapp/WEB-INF/app/views/coding_rules/index.html.erb
server/sonar-web/src/main/webapp/WEB-INF/app/views/coding_rules_old/index.html.erb [new file with mode: 0644]
server/sonar-web/src/main/webapp/WEB-INF/app/views/issues/search.html.erb
server/sonar-web/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index 1af2390f85c3a68f3c12f43980da14357c7be16b..45c4af59a1f2837434d961c876565f7aa1f5542b 100644 (file)
@@ -174,6 +174,10 @@ module.exports = (grunt) ->
         name: 'coding-rules/app'
         out: '<%= pkg.assets %>build/js/coding-rules/app.js'
 
+      codingRulesOld: options:
+        name: 'coding-rules-old/app'
+        out: '<%= pkg.assets %>build/js/coding-rules-old/app.js'
+
       issues: options:
         name: 'issues/app'
         out: '<%= pkg.assets %>build/js/issues/app.js'
@@ -237,6 +241,10 @@ module.exports = (grunt) ->
             '<%= pkg.sources %>hbs/common/**/*.hbs'
             '<%= pkg.sources %>hbs/coding-rules/**/*.hbs'
           ]
+          '<%= pkg.assets %>js/templates/coding-rules-old.js': [
+            '<%= pkg.sources %>hbs/common/**/*.hbs'
+            '<%= pkg.sources %>hbs/coding-rules-old/**/*.hbs'
+          ]
           '<%= pkg.assets %>js/templates/quality-gates.js': [
             '<%= pkg.sources %>hbs/quality-gates/**/*.hbs'
           ]
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/app.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/app.coffee
new file mode 100644 (file)
index 0000000..2687800
--- /dev/null
@@ -0,0 +1,521 @@
+requirejs.config
+  baseUrl: "#{baseUrl}/js"
+
+  paths:
+    'backbone': 'third-party/backbone'
+    'backbone.marionette': 'third-party/backbone.marionette'
+    'handlebars': 'third-party/handlebars'
+
+  shim:
+    'backbone.marionette':
+      deps: ['backbone']
+      exports: 'Marionette'
+    'backbone':
+      exports: 'Backbone'
+    'handlebars':
+      exports: 'Handlebars'
+
+
+requirejs [
+  'backbone', 'backbone.marionette',
+
+  'coding-rules-old/layout',
+  'coding-rules-old/router',
+
+  # views
+  'coding-rules-old/views/header-view',
+  'coding-rules-old/views/actions-view',
+  'coding-rules-old/views/filter-bar-view',
+  'coding-rules-old/views/coding-rules-list-view',
+  'coding-rules-old/views/coding-rules-detail-view',
+  'coding-rules-old/views/coding-rules-bulk-change-view',
+  'coding-rules-old/views/coding-rules-quality-profile-activation-view',
+  'coding-rules-old/views/coding-rules-bulk-change-dropdown-view',
+  'coding-rules-old/views/coding-rules-facets-view',
+  'coding-rules-old/views/coding-rules-custom-rule-creation-view',
+  'coding-rules-old/views/coding-rules-manual-rule-creation-view',
+
+  # filters
+  'navigator/filters/base-filters',
+  'navigator/filters/choice-filters',
+  'navigator/filters/string-filters',
+  'navigator/filters/date-filter-view',
+  'navigator/filters/read-only-filters',
+  'coding-rules-old/views/filters/query-filter-view',
+  'coding-rules-old/views/filters/quality-profile-filter-view',
+  'coding-rules-old/views/filters/inheritance-filter-view',
+  'coding-rules-old/views/filters/active-severities-filter-view',
+  'coding-rules-old/views/filters/activation-filter-view',
+  'coding-rules-old/views/filters/characteristic-filter-view',
+  'coding-rules-old/views/filters/repository-filter-view',
+  'coding-rules-old/views/filters/tag-filter-view',
+  'coding-rules-old/views/filters/language-filter-view',
+
+  'common/handlebars-extensions'
+], (
+  Backbone, Marionette,
+
+  CodingRulesLayout,
+  CodingRulesRouter,
+
+  # views
+  CodingRulesHeaderView,
+  CodingRulesActionsView,
+  CodingRulesFilterBarView,
+  CodingRulesListView,
+  CodingRulesDetailView,
+  CodingRulesBulkChangeView,
+  CodingRulesQualityProfileActivationView,
+  CodingRulesBulkChangeDropdownView,
+  CodingRulesFacetsView,
+  CodingRulesCustomRuleCreationView,
+  CodingRulesManualRuleCreationView,
+
+  # filters
+  BaseFilters,
+  ChoiceFilters,
+  StringFilterView,
+  DateFilterView,
+  ReadOnlyFilterView,
+  QueryFilterView,
+  QualityProfileFilterView,
+  InheritanceFilterView,
+  ActiveSeveritiesFilterView,
+  ActivationFilterView,
+  CharacteristicFilterView,
+  RepositoryFilterView,
+  TagFilterView,
+  LanguageFilterView
+) ->
+
+  # 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 '. '
+      else
+        text = t 'default_error_message'
+      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 = (params) ->
+    sort = _.findWhere(params, key: 'sort')
+    asc = _.findWhere(params, key: 'asc')
+
+    if (sort && asc)
+      @codingRules.sorting =
+        sort: sort.value
+        asc: asc.value =='true'
+
+
+  App.restoreDefaultSorting = ->
+    params = []
+    params.push(key: 'sort', value: 'createdAt')
+    params.push(key: 'asc', value: false)
+    @restoreSorting params
+
+
+  App.storeQuery = (query, sorting) ->
+    if sorting && sorting.sort
+      _.extend query,
+        s: 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 { p: @pageIndex, ps: 25, facets: firstPage }, query
+
+    if @codingRules.sorting && @codingRules.sorting.sort
+      _.extend fetchQuery,
+          s: @codingRules.sorting.sort,
+          asc: @codingRules.sorting.asc
+
+    @storeQuery query, @codingRules.sorting
+
+    # Optimize requested fields
+    _.extend fetchQuery, f: 'name,lang,status,tags,sysTags'
+
+    if @codingRulesListView
+      scrollOffset = jQuery('.navigator-results')[0].scrollTop
+    else
+      scrollOffset = 0
+
+    @layout.showSpinner 'resultsRegion'
+    @layout.showSpinner 'facetsRegion' if firstPage
+
+
+    jQuery.ajax
+      url: "#{baseUrl}/api/rules/search"
+      data: fetchQuery
+    .done (r) =>
+      _.map(r.rules, (rule) ->
+        rule.language = App.languages[rule.lang]
+      )
+
+      @codingRules.paging =
+        total: r.total
+        pageIndex: r.p
+        pageSize: r.ps
+        pages: 1 + (r.total / r.ps)
+
+      if @codingRulesListView
+        @codingRulesListView.close()
+
+      if firstPage
+        @codingRules.reset r.rules
+        @codingRulesListView = new CodingRulesListView
+          app: @
+          collection: @codingRules
+      else
+        @codingRulesListView.unbindEvents()
+        @codingRules.add r.rules
+
+      @layout.resultsRegion.show @codingRulesListView
+
+
+      if @codingRules.isEmpty()
+        @layout.detailsRegion.reset()
+      else if firstPage
+        @codingRulesListView.selectFirst()
+      else
+        @codingRulesListView.selectCurrent()
+
+      if firstPage
+        @codingRulesFacetsView = new CodingRulesFacetsView
+          app: @
+          collection: new Backbone.Collection r.facets, comparator: 'property'
+        @layout.facetsRegion.show @codingRulesFacetsView
+        @filterBarView.restoreFromWsQuery query
+        @codingRulesFacetsView.restoreFromQuery query
+      else
+        jQuery('.navigator-results')[0].scrollTop = scrollOffset
+
+      @layout.onResize()
+
+
+
+  App.facetLabel = (property, value) ->
+    return value unless App.facetPropertyToLabels[property]
+    App.facetPropertyToLabels[property](value)
+
+
+  App.fetchFirstPage = ->
+    @pageIndex = 1
+    App.fetchList true
+
+
+  App.fetchNextPage = ->
+    if @pageIndex < @codingRules.paging.pages
+      @pageIndex++
+      App.fetchList false
+
+
+  App.getQualityProfile = ->
+    value = @qualityProfileFilter.get('value')
+    if value? && value.length == 1 then value[0] else null
+
+
+  App.getQualityProfilesForLanguage = (language_key) ->
+    _.filter App.qualityProfiles, (p) => p.lang == language_key
+
+  App.getQualityProfileByKey = (profile_key) ->
+    _.findWhere App.qualityProfiles, key: profile_key
+
+
+  App.getSubcharacteristicName = (name) ->
+    (App.characteristics[name] || '').replace ': ', ' > '
+
+
+  App.showRule = (ruleKey) ->
+    App.layout.showSpinner 'detailsRegion'
+    jQuery.ajax
+      url: "#{baseUrl}/api/rules/show"
+      data:
+        key: ruleKey
+        actives: true
+    .done (r) =>
+      rule = new Backbone.Model(r.rule)
+      App.codingRulesQualityProfileActivationView.rule = rule
+      App.detailView = new CodingRulesDetailView
+        app: App
+        model: rule
+        actives: r.actives
+      App.layout.detailsRegion.show App.detailView
+
+
+  App.manualRepository = ->
+    key: 'manual'
+    name: 'Manual Rules'
+    language: 'none'
+
+
+  App.createManualRule = ->
+    App.codingRulesManualRuleCreationView.model = new Backbone.Model()
+    App.codingRulesManualRuleCreationView.show()
+
+
+  # Construct layout
+  App.addInitializer ->
+    @layout = new CodingRulesLayout app: @
+    jQuery('#content').append @layout.render().el
+    @layout.onResize()
+
+
+  # Construct header
+  App.addInitializer ->
+    @codingRulesHeaderView = new CodingRulesHeaderView app: @
+    @layout.headerRegion.show @codingRulesHeaderView
+
+
+  # Define coding rules
+  App.addInitializer ->
+    @codingRules = new Backbone.Collection
+    @restoreDefaultSorting()
+
+
+  # Construct status bar
+  App.addInitializer ->
+    @codingRulesActionsView = new CodingRulesActionsView
+      app: @
+      collection: @codingRules
+    @layout.actionsRegion.show @codingRulesActionsView
+
+
+  # Construct bulk change views
+  App.addInitializer ->
+    @codingRulesBulkChangeView = new CodingRulesBulkChangeView app: @
+    @codingRulesBulkChangeDropdownView = new CodingRulesBulkChangeDropdownView app: @
+
+
+  # Construct quality profile activation view
+  App.addInitializer ->
+    @codingRulesQualityProfileActivationView = new CodingRulesQualityProfileActivationView app: @
+
+
+  # Construct custom rule creation view
+  App.addInitializer ->
+    @codingRulesCustomRuleCreationView = new CodingRulesCustomRuleCreationView app: @
+
+
+  # Construct custom rule creation view
+  App.addInitializer ->
+    @codingRulesManualRuleCreationView = new CodingRulesManualRuleCreationView app: @
+
+  # Define filters
+  App.addInitializer ->
+    @filters = new BaseFilters.Filters
+
+    @queryFilter = new BaseFilters.Filter
+      property: 'q'
+      type: QueryFilterView
+      size: 50
+    @filters.add @queryFilter
+
+    @filters.add new BaseFilters.Filter
+      name: t 'coding_rules.filters.severity'
+      property: 'severities'
+      type: ChoiceFilters.ChoiceFilterView
+      optional: true
+      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.tag'
+      property: 'tags'
+      type: TagFilterView
+      optional: true
+
+    @filters.add new BaseFilters.Filter
+      name: t 'coding_rules.filters.characteristic'
+      property: 'debt_characteristics'
+      type: CharacteristicFilterView
+      choices: @characteristics
+      multiple: false
+      optional: true
+
+    @qualityProfileFilter = new BaseFilters.Filter
+      name: t 'coding_rules.filters.quality_profile'
+      property: 'qprofile'
+      type: QualityProfileFilterView
+      app: @
+      choices: @qualityProfiles
+      multiple: false
+    @filters.add @qualityProfileFilter
+
+    @activationFilter = new BaseFilters.Filter
+      name: t 'coding_rules.filters.activation'
+      property: 'activation'
+      type: ActivationFilterView
+      enabled: false
+      optional: true
+      multiple: false
+      qualityProfileFilter: @qualityProfileFilter
+      choices:
+        true: t 'coding_rules.filters.activation.active'
+        false: t 'coding_rules.filters.activation.inactive'
+    @filters.add @activationFilter
+
+    @filters.add new BaseFilters.Filter
+      name: t 'coding_rules.filters.active_severity'
+      property: 'active_severities'
+      type: ActiveSeveritiesFilterView
+      enabled: false
+      optional: true
+      qualityProfileFilter: @qualityProfileFilter
+      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'
+
+    @languageFilter =  new BaseFilters.Filter
+      name: t 'coding_rules.filters.language'
+      property: 'languages'
+      type: LanguageFilterView
+      app: @
+      choices: @languages
+      optional: true
+    @filters.add @languageFilter
+
+    @filters.add new BaseFilters.Filter
+      name: t 'coding_rules.filters.availableSince'
+      property: 'available_since'
+      type: DateFilterView
+      enabled: false
+      optional: true
+
+    @filters.add new BaseFilters.Filter
+      name: t 'coding_rules.filters.inheritance'
+      property: 'inheritance'
+      type: InheritanceFilterView
+      enabled: false
+      optional: true
+      multiple: false
+      qualityProfileFilter: @qualityProfileFilter
+      choices:
+        'NONE': t 'coding_rules.filters.inheritance.not_inherited'
+        'INHERITED': t 'coding_rules.filters.inheritance.inherited'
+        'OVERRIDES': t 'coding_rules.filters.inheritance.overriden'
+
+    @filters.add new BaseFilters.Filter
+      name: t 'coding_rules.filters.repository'
+      property: 'repositories'
+      type: RepositoryFilterView
+      enabled: false
+      optional: true
+      app: @
+      choices: @repositories
+
+    @filters.add new BaseFilters.Filter
+      name: t 'coding_rules.filters.status'
+      property: 'statuses'
+      type: ChoiceFilters.ChoiceFilterView
+      enabled: false
+      optional: true
+      choices: @statuses
+
+    @filters.add new BaseFilters.Filter
+      name: t 'coding_rules.filters.template'
+      property: 'is_template'
+      type: ChoiceFilters.ChoiceFilterView
+      optional: true
+      multiple: false
+      choices:
+        'true': t 'coding_rules.filters.template.is_template'
+        'false': t 'coding_rules.filters.template.is_not_template'
+
+    @filters.add new BaseFilters.Filter
+      name: t 'coding_rules.filters.key'
+      property: 'rule_key'
+      type: ReadOnlyFilterView
+      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/rules/app"
+  .done (r) ->
+    App.appState = new Backbone.Model
+    App.state = new Backbone.Model
+    App.canWrite = r.canWrite
+    App.qualityProfiles = _.sortBy r.qualityprofiles, ['name', 'lang']
+    App.languages = _.extend r.languages, none: 'None'
+    _.map App.qualityProfiles, (profile) ->
+      profile.language = App.languages[profile.lang]
+    App.repositories = r.repositories
+    App.repositories.push App.manualRepository()
+    App.statuses = r.statuses
+    App.characteristics = r.characteristics
+
+    App.facetPropertyToLabels =
+      'languages': (value) -> App.languages[value]
+      'repositories': (value) ->
+        repo = _.findWhere(App.repositories, key: value)
+        other_repo_with_same_name = _.find(App.repositories, (repos) -> repos.name == repo.name && repos.key != repo.key)
+        if other_repo_with_same_name
+          App.languages[repo.language] + ' ' + repo.name
+        else
+          repo.name
+
+  # Message bundles
+  l10nXHR = window.requestMessages()
+
+  jQuery.when(l10nXHR, appXHR).done ->
+      # Remove the initial spinner
+      jQuery('#coding-rules-page-loader').remove()
+
+      # Start the application
+      App.start()
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/layout.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/layout.coffee
new file mode 100644 (file)
index 0000000..459c11d
--- /dev/null
@@ -0,0 +1,90 @@
+define [
+  'backbone.marionette',
+  'templates/coding-rules-old'
+], (
+  Marionette,
+  Templates
+) ->
+
+  class AppLayout extends Marionette.Layout
+    className: 'navigator coding-rules-navigator'
+    template: Templates['coding-rules-layout']
+    storageKey: 'codingRulesResultsWidth'
+
+
+    regions:
+      headerRegion: '.navigator-header'
+      actionsRegion: '.navigator-actions'
+      resultsRegion: '.navigator-results'
+      detailsRegion: '.navigator-details'
+      filtersRegion: '.navigator-filters'
+      facetsRegion: '.navigator-facets'
+
+
+    ui:
+      side: '.navigator-side'
+      results: '.navigator-results'
+      details: '.navigator-details'
+      resizer: '.navigator-resizer'
+
+
+    initialize: ->
+      jQuery(window).on 'resize', => @onResize()
+
+      @isResize = false
+      jQuery('body').on 'mousemove', (e) => @processResize(e)
+      jQuery('body').on 'mouseup', => @stopResize()
+
+
+    onRender: ->
+      @ui.resizer.on 'mousedown', (e) => @startResize(e)
+
+      resultsWidth = localStorage.getItem @storageKey
+      if resultsWidth
+        @$(@resultsRegion.el).width +resultsWidth
+        @ui.side.width +resultsWidth + 20
+
+
+    onResize: ->
+      footerEl = jQuery('#footer')
+      footerHeight = footerEl.outerHeight true
+
+      resultsEl = @ui.results
+      resultsHeight = jQuery(window).height() - resultsEl.offset().top -
+        parseInt(resultsEl.css('margin-bottom'), 10) - footerHeight
+      resultsEl.height resultsHeight
+
+      detailsEl = @ui.details
+      detailsWidth = jQuery(window).width() - detailsEl.offset().left -
+        parseInt(detailsEl.css('margin-right'), 10)
+      detailsHeight = jQuery(window).height() - detailsEl.offset().top -
+        parseInt(detailsEl.css('margin-bottom'), 10) - footerHeight
+      detailsEl.width(detailsWidth).height detailsHeight
+
+
+    showSpinner: (region) ->
+      @[region].show new Marionette.ItemView
+        template: _.template('<i class="spinner"></i>')
+
+
+    startResize: (e) ->
+      @isResize = true
+      @originalWidth = @ui.results.width()
+      @x = e.clientX
+      jQuery('html').attr('unselectable', 'on').css('user-select', 'none').on('selectstart', false)
+
+
+    processResize: (e) ->
+      if @isResize
+        delta = e.clientX - @x
+        @$(@resultsRegion.el).width @originalWidth + delta
+        @ui.side.width @originalWidth + 20 + delta
+        localStorage.setItem @storageKey, @ui.results.width()
+        @onResize()
+
+
+    stopResize: ->
+      if @isResize
+        jQuery('html').attr('unselectable', 'off').css('user-select', 'text').off('selectstart')
+      @isResize = false
+      true
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/mockjax.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/mockjax.coffee
new file mode 100644 (file)
index 0000000..30f37ba
--- /dev/null
@@ -0,0 +1,364 @@
+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
+      qualityprofiles: [
+        { key: 'sonarway', name: 'Sonar Way', lang: 'Java', parent: null },
+        { key: 'qualityprofile1', name: 'Quality Profile 1', lang: 'Java', parent: 'sonarway' },
+        { key: 'qualityprofile2', name: 'Quality Profile 2', lang: 'JavaScript', parent: 'sonarway' },
+        { key: 'qualityprofile3', name: 'Quality Profile 3', lang: 'Java', parent: null },
+      ]
+      languages:
+        java: 'Java'
+        javascript: 'JavaScript'
+      repositories:
+        'checkstyle': 'Checkstyle'
+        'common-java': 'Common SonarQube'
+        'findbugs': 'FindBugs'
+        'pmd': 'PMD'
+        'pmd-unit-tests': 'PMD Unit Tests'
+        'squid': 'SonarQube'
+      statuses:
+        'BETA': 'Beta'
+        'DEPRECATED': 'Deprecated'
+        'READY': 'Ready'
+      tags:
+        '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'
+      characteristics:
+        '1469': 'Changeability'
+        '1441': 'Changeability: Architecture related changeability'
+        '1470': 'Changeability: Data related changeability'
+        '1475': 'Changeability: Logic related changeability'
+        '1392': 'Efficiency'
+        '1377': 'Efficiency: Memory use'
+        '2965': 'Efficiency: Network use'
+        '1393': 'Efficiency: Processor use'
+        '1154': 'Maintainability'
+        '1022': 'Maintainability: Readability'
+        '1155': 'Maintainability: Understandability'
+        '988': 'Portability'
+        '977': 'Portability: Compiler related portability'
+        '989': 'Portability: Hardware related portability'
+        '994': 'Portability: Language related portability'
+        '1000': 'Portability: OS related portability'
+        '1006': 'Portability: Software related portability'
+        '1021': 'Portability: Time zone related portability'
+        '1551': 'Reliability'
+        '1496': 'Reliability: Architecture related reliability'
+        '1552': 'Reliability: Data related reliability'
+        '1596': 'Reliability: Exception handling'
+        '1622': 'Reliability: Fault tolerance'
+        '1629': 'Reliability: Instruction related reliability'
+        '1759': 'Reliability: Logic related reliability'
+        '2948': 'Reliability: Resource'
+        '1874': 'Reliability: Synchronization related reliability'
+        '1925': 'Reliability: Unit tests'
+        '975': 'Reusability'
+        '974': 'Reusability: Modularity'
+        '976': 'Reusability: Transportability'
+        '1345': 'Security'
+        '1335': 'Security: API abuse'
+        '1346': 'Security: Errors'
+        '1349': 'Security: Input validation and representation'
+        '1364': 'Security: Security features'
+        '1933': 'Testability'
+        '1932': 'Testability: Integration level testability'
+        '1934': 'Testability: Unit level testability'
+      messages:
+        'all': 'All'
+        'any': 'Any'
+        'apply': 'Apply'
+        'are_you_sure': 'Are you sure?'
+        'bold': 'Bold'
+        'bulk_change': 'Bulk Change'
+        'bulleted_point': 'Bulleted point'
+        'cancel': 'Cancel'
+        'change': 'Change'
+        'code': 'Code'
+        'delete': 'Delete'
+        'done': 'Done'
+        'edit': 'Edit'
+        'markdown.helplink': 'Markdown Help'
+        'moreCriteria': '+ More Criteria'
+        'save': 'Save'
+        'search_verb': 'Search'
+        'severity': 'Severity'
+        'update': 'Update'
+
+        'severity.BLOCKER': 'Blocker'
+        'severity.CRITICAL': 'Critical'
+        'severity.MAJOR': 'Major'
+        'severity.MINOR': 'Minor'
+        'severity.INFO': 'Info'
+
+        'coding_rules.activate': 'Activate'
+        'coding_rules.activate_in': 'Activate In'
+        'coding_rules.activate_in_quality_profile': 'Activate In Quality Profile'
+        'coding_rules.activate_in_all_quality_profiles': 'Activate In All {0} Profiles'
+        'coding_rules.add_note': 'Add Note'
+        'coding_rules.available_since': 'Available Since'
+        'coding_rules.bulk_change': 'Bulk Change'
+        'coding_rules.change_severity': 'Change Severity'
+        'coding_rules.change_severity_in': 'Change Severity In'
+        'coding_rules.change_details': 'Change Details of Quality Profile'
+        'coding_rules.extend_description': 'Extend Description'
+        'coding_rules.deactivate_in': 'Deactivate In'
+        'coding_rules.deactivate': 'Deactivate'
+        'coding_rules.deactivate_in_quality_profile': 'Deactivate In Quality Profile'
+        'coding_rules.deactivate_in_all_quality_profiles': 'Deactivate In All {0} Profiles'
+        'coding_rules.found': 'Found'
+        'coding_rules.inherits': '"{0}" inherits "{1}"'
+        'coding_rules.key': 'Key:'
+        'coding_rules.new_search': 'New Search'
+        'coding_rules.no_results': 'No Coding Rules'
+        'coding_rules.no_tags': 'No tags'
+        'coding_rules.order': 'Order'
+        'coding_rules.ordered_by': 'Ordered By'
+        'coding_rules.original': 'Original:'
+        'coding_rules.page': 'Coding Rules'
+        'coding_rules.parameters': 'Parameters'
+        'coding_rules.parameters.default_value': 'Default Value:'
+        'coding_rules.permalink': 'Permalink'
+        'coding_rules.quality_profiles': 'Quality Profiles'
+        'coding_rules.quality_profile': 'Quality Profile'
+        'coding_rules.repository': 'Repository:'
+        'coding_rules.revert_to_parent_definition': 'Revert to Parent Definition'
+        'coding_rules._rules': 'rules'
+        'coding_rules.select_tag': 'Select Tag'
+
+        'coding_rules.filters.activation': 'Activation'
+        'coding_rules.filters.activation.active': 'Active'
+        'coding_rules.filters.activation.inactive': 'Inactive'
+        'coding_rules.filters.activation.help': 'Activation criterion is available when a quality profile is selected'
+        'coding_rules.filters.availableSince': 'Available Since'
+        'coding_rules.filters.characteristic': 'Characteristic'
+        'coding_rules.filters.description': 'Description'
+        'coding_rules.filters.quality_profile': 'Quality Profile'
+        'coding_rules.filters.inheritance': 'Inheritance'
+        'coding_rules.filters.inheritance.inactive': 'Inheritance criterion is available when an inherited quality profile is selected'
+        'coding_rules.filters.inheritance.not_inherited': 'Not Inherited'
+        'coding_rules.filters.inheritance.inherited': 'Inherited'
+        'coding_rules.filters.inheritance.overriden': 'Overriden'
+        'coding_rules.filters.key': 'Key'
+        'coding_rules.filters.language': 'Language'
+        'coding_rules.filters.name': 'Name'
+        'coding_rules.filters.repository': 'Repository'
+        'coding_rules.filters.severity': 'Severity'
+        'coding_rules.filters.status': 'Status'
+        'coding_rules.filters.tag': 'Tag'
+
+        'coding_rules.sort.creation_date': 'Creation Date'
+        'coding_rules.sort.name': 'Name'
+
+
+  # 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'
+          severity: 'MAJOR'
+          status: 'DEPRECATED'
+        },
+        {
+          name: 'Avoid Array Loops'
+          language: 'Java'
+          severity: 'CRITICAL'
+          status: 'READY'
+        },
+        {
+          name: 'Bad practice - Abstract class defines covariant compareTo() method'
+          language: 'Java'
+          severity: 'MAJOR'
+          status: 'READY'
+        },
+        {
+          name: 'Correctness - Use of class without a hashCode() method in a hashed data structure'
+          language: 'Java'
+          severity: 'MINOR'
+          status: 'BETA'
+        },
+        {
+          name: 'Useless Operation On Immutable'
+          language: 'Java'
+          severity: 'MAJOR'
+          status: 'READY'
+        }
+      ]
+      paging:
+        total: 5
+        fTotal: '5'
+      facets: [
+        {
+          name: 'Languages'
+          property: 'languages'
+          values: [
+            { key: 'java', text: 'Java', stat: 45 }
+            { key: 'javascript', text: 'JavaScript', stat: 21 }
+          ]
+        }
+        {
+          name: 'Tags'
+          property: 'tags'
+          values: [
+            { key: 'brain-overload', text: 'brain-overload', stat: 8 }
+            { key: 'bug', text: 'bug', stat: 7 }
+            { key: 'comment', text: 'comment', stat: 7 }
+            { key: 'convention', text: 'convention', stat: 6 }
+            { key: 'error-handling', text: 'error-handling', stat: 5 }
+          ]
+        }
+        {
+          name: 'Repositories'
+          property: 'repositories'
+          values: [
+            { key: 'squid', text: 'SonarQube', stat: 57 }
+            { key: 'pmd', text: 'PMD', stat: 17 }
+          ]
+        }
+      ]
+
+
+
+
+  # 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'
+        creationDate: '2013-10-15'
+        fCreationDate: 'Oct 15, 2013'
+        status: 'DEPRECATED'
+        repositoryName: 'SonarQube'
+        repositoryKey: 'squid'
+        characteristic: 'Reliability'
+        subcharacteristic: 'Data related reliability'
+        key: 'S1190'
+        parameters: [
+          { key: 'someParameter', type: 'INT', default: 4, description: 'Some parameter description' }
+          { key: 'xpath', type: 'TEXT', description: 'XPath, the XML Path Language, is a query language for selecting nodes from an XML document. In addition, XPath may be used to compute values (e.g., strings, numbers, or Boolean values) from the content of an XML document. XPath was defined by the World Wide Web Consortium (W3C).' }
+        ]
+        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>'''
+        extra: '''This note is here <b>only for test purposes</b>.'''
+        extraRaw: '''This note is here *only for test purposes*.'''
+
+        qualityProfiles: [
+          {
+            name: 'SonarWay'
+            key: 'sonarway'
+            severity: 'MINOR'
+            parameters: [
+              { key: 'someParameter', value: 8 }
+              { key: 'xpath', value: '/child::html/child::body/child::*/child::span[attribute::class]' }
+            ]
+          },
+          {
+            name: 'Quality Profile 1'
+            key: 'qualityprofile1'
+            severity: 'MAJOR'
+            parameters: [
+              { key: 'someParameter', value: 6 }
+              { key: 'xpath', value: '/html/body/*/span[@class]' }
+            ]
+            inherits: 'sonarway'
+          }
+        ]
+
+
+
+  # POST /api/codingrules/extend_description
+  jQuery.mockjax
+    url: "#{baseUrl}/api/codingrules/extend_description"
+    responseText: JSON.stringify
+      extra: '''This note is here <i>only for test purposes</i>.'''
+      extraRaw: '''This note is here *only for test purposes*.'''
+
+
+  # POST /api/codingrules/bulk_change
+  jQuery.mockjax
+    url: "#{baseUrl}/api/codingrules/bulk_change"
+
+
+  # POST /api/codingrules/set_tags
+  jQuery.mockjax
+    url: "#{baseUrl}/api/codingrules/set_tags"
+
+
+  # POST /api/codingrules/activate
+  jQuery.mockjax
+    url: "#{baseUrl}/api/codingrules/activate"
+
+
+  # POST /api/codingrules/note
+  jQuery.mockjax
+    url: "#{baseUrl}/api/codingrules/note"
+    responseText: JSON.stringify
+      note:
+        username: 'Admin Admin'
+        html: '''<p>This note is here <b>only for test purposes</b>.</p>'''
+        raw: '''This note is here *only for test purposes*.'''
+        fCreationDate: 'less than a minute'
+
+
+  # GET /api/qualityprofiles/list
+  jQuery.mockjax
+    url: "#{baseUrl}/api/qualityprofiles/list"
+    responseText: JSON.stringify
+      more: false
+      results: [
+        { id: 'sonarway', text: 'Sonar Way', category: 'Java', parent: null },
+        { id: 'qp1', text: 'Quality Profile 1', category: 'Java', parent: 'sonarway' },
+        { id: 'qp2', text: 'Quality Profile 2', category: 'JavaScript', parent: 'sonarway' },
+        { id: 'qp3', text: 'Quality Profile 3', category: 'Java', parent: null },
+      ]
+
+
+  # GET /api/qualityprofiles/show
+  jQuery.mockjax
+    url: "#{baseUrl}/api/qualityprofiles/show"
+    responseText: JSON.stringify
+      qualityprofile:
+        id: 'sonarway', text: 'Sonar Way', category: 'Java', parent: null
+
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/router.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/router.coffee
new file mode 100644 (file)
index 0000000..fe49b73
--- /dev/null
@@ -0,0 +1,39 @@
+define [
+  'backbone',
+], (
+  Backbone,
+) ->
+
+  class AppRouter extends Backbone.Router
+
+    routes:
+      '': 'emptyQuery'
+      ':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: ->
+      @app.restoreDefaultSorting()
+      @index('')
+
+
+    index: (query) ->
+      params = this.parseQuery(query)
+      @loadResults(params)
+
+
+    loadResults: (params) ->
+      @app.filterBarView.restoreFromQuery(params)
+      if @app.codingRulesFacetsView
+        @app.codingRulesFacetsView.restoreFromQuery(params)
+      @app.restoreSorting(params)
+      @app.fetchFirstPage()
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/actions-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/actions-view.coffee
new file mode 100644 (file)
index 0000000..b8559cb
--- /dev/null
@@ -0,0 +1,64 @@
+define [
+  'backbone.marionette'
+  'templates/coding-rules-old'
+], (
+  Marionette
+  Templates
+) ->
+
+  class CodingRulesStatusView extends Marionette.ItemView
+    template: Templates['coding-rules-actions']
+
+
+    collectionEvents:
+      'all': 'render'
+
+
+    ui:
+      orderChoices: '.navigator-actions-order-choices'
+      bulkChange: '.navigator-actions-bulk'
+
+
+    events:
+      'click .navigator-actions-order': 'toggleOrderChoices'
+      'click @ui.orderChoices': 'sort'
+      'click @ui.bulkChange': 'bulkChange'
+
+
+    onRender: ->
+      unless @collection.sorting.sortText
+        while not @collection.sorting.sortText
+          @collection.sorting.sortText = @$('[data-sort=' + @collection.sorting.sort + ']:first').text()
+        @render()
+
+
+    toggleOrderChoices: (e) ->
+      e.stopPropagation()
+      @ui.orderChoices.toggleClass 'open'
+      if @ui.orderChoices.is '.open'
+        jQuery('body').on 'click.coding_rules_actions', =>
+          @ui.orderChoices.removeClass 'open'
+
+
+    sort: (e) ->
+      e.stopPropagation()
+      @ui.orderChoices.removeClass 'open'
+      jQuery('body').off 'click.coding_rules_actions'
+      el = jQuery(e.target)
+      sort = el.data 'sort'
+      asc = el.data 'asc'
+      if sort != null && asc != null
+        @collection.sorting = sort: sort, sortText: el.text(), asc: asc
+        @options.app.fetchFirstPage()
+
+
+    bulkChange: (e) ->
+      e.stopPropagation()
+      @options.app.codingRulesBulkChangeDropdownView.toggle()
+
+
+    serializeData: ->
+      _.extend super,
+        canWrite: @options.app.canWrite
+        paging: @collection.paging
+        sorting: @collection.sorting
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-bulk-change-dropdown-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-bulk-change-dropdown-view.coffee
new file mode 100644 (file)
index 0000000..0a1ee73
--- /dev/null
@@ -0,0 +1,55 @@
+define [
+  'backbone.marionette',
+  'templates/coding-rules-old'
+], (
+  Marionette,
+  Templates
+) ->
+
+  class CodingRulesBulkChangeDropdownView extends Marionette.ItemView
+    className: 'coding-rules-bulk-change-dropdown'
+    template: Templates['coding-rules-bulk-change-dropdown']
+
+
+    events:
+      'click .coding-rules-bulk-change-dropdown-link': 'doAction'
+
+
+    doAction: (e) ->
+      action = jQuery(e.currentTarget).data 'action'
+      param = jQuery(e.currentTarget).data 'param'
+      @options.app.codingRulesBulkChangeView.show action, param
+
+
+    onRender: ->
+      jQuery('body').append @el
+      jQuery('body').off('click.bulk-change').on 'click.bulk-change', => @hide()
+      @$el.css
+        top: jQuery('.navigator-actions').offset().top + jQuery('.navigator-actions').height() + 1
+        left: jQuery('.navigator-actions').offset().left + jQuery('.navigator-actions').outerWidth() - @$el.outerWidth()
+
+
+    toggle: ->
+      if @$el.is(':visible') then @hide() else @show()
+
+
+    show: ->
+      @render()
+      @$el.show()
+
+
+    hide: ->
+      @$el.hide()
+
+
+    serializeData: ->
+      languages = @options.app.languageFilter.get('value')
+      activationValues = @options.app.activationFilter.get('value') or []
+      qualityProfile = @options.app.getQualityProfile()
+
+      qualityProfile: qualityProfile
+      qualityProfileName: @options.app.qualityProfileFilter.view.renderValue()
+      singleLanguage: _.isArray(languages) and languages.length == 1
+      language: @options.app.languageFilter.view.renderValue()
+      allowActivateOnProfile: qualityProfile and (activationValues.length == 0 or activationValues[0] == 'false')
+      allowDeactivateOnProfile: qualityProfile and (activationValues.length == 0 or activationValues[0] == 'true')
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-bulk-change-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-bulk-change-view.coffee
new file mode 100644 (file)
index 0000000..16b2689
--- /dev/null
@@ -0,0 +1,123 @@
+define [
+  'backbone.marionette',
+  'templates/coding-rules-old'
+], (
+  Marionette,
+  Templates
+) ->
+
+  class CodingRulesBulkChangeView extends Marionette.ItemView
+    template: Templates['coding-rules-bulk-change']
+
+    ui:
+      modalFooter: '.modal-foot'
+      modalError: '.modal-error'
+      modalWarning: '.modal-warning'
+      modalNotice: '.modal-notice'
+      modalField: '.modal-field'
+      codingRulesSubmitBulkChange: '#coding-rules-submit-bulk-change'
+      codingRulesCancelBulkChange: '#coding-rules-cancel-bulk-change'
+      codingRulesCloseBulkChange: '#coding-rules-close-bulk-change'
+
+    events:
+      'submit form': 'onSubmit'
+      'click @ui.codingRulesCancelBulkChange': 'hide'
+      'click @ui.codingRulesCloseBulkChange': 'close'
+      'change select': 'enableAction'
+
+
+    onRender: ->
+      @$el.dialog
+        dialogClass: 'no-close',
+        width: '600px',
+        draggable: false,
+        autoOpen: false,
+        modal: true,
+        minHeight: 50,
+        resizable: false,
+        title: null
+
+      @$('#coding-rules-bulk-change-profile').select2
+        width: '250px'
+        minimumResultsForSearch: 1
+
+    show: (action, param = null) ->
+      @action = action
+      @profile = param
+      @render()
+      @$el.dialog 'open'
+
+
+    hide: ->
+      @$el.dialog 'close'
+
+
+    close: ->
+      @options.app.fetchFirstPage()
+      @hide()
+      false
+
+
+    prepareQuery: ->
+      _.extend @options.app.getQuery(),
+        wsAction: @action
+        profile_key: @$('#coding-rules-bulk-change-profile').val() or @profile
+
+
+    bulkChange: (query) ->
+      wsAction = query.wsAction
+      query = _.omit(query, 'wsAction')
+
+      @ui.modalError.hide()
+      @ui.modalWarning.hide()
+      @ui.modalNotice.hide()
+
+      origFooter = @ui.modalFooter.html()
+      @ui.modalFooter.html '<i class="spinner"></i>'
+
+      jQuery.ajax
+        type: 'POST'
+        url: "#{baseUrl}/api/qualityprofiles/#{wsAction}_rules"
+        data: query
+      .done (r) =>
+        @ui.modalField.hide()
+        if (r.failed)
+          @ui.modalWarning.show()
+          @ui.modalWarning.html tp('coding_rules.bulk_change.warning', r.succeeded, r.failed)
+        else
+          @ui.modalNotice.show()
+          @ui.modalNotice.html tp('coding_rules.bulk_change.success', r.succeeded)
+
+        @ui.modalFooter.html origFooter
+        @$(@ui.codingRulesSubmitBulkChange.selector).hide()
+        @$(@ui.codingRulesCancelBulkChange.selector).hide()
+        @$(@ui.codingRulesCloseBulkChange.selector).show()
+        @$(@ui.codingRulesCloseBulkChange.selector).focus()
+      .fail =>
+        @ui.modalFooter.html origFooter
+
+
+    onSubmit: (e) ->
+      e.preventDefault()
+      @bulkChange(@prepareQuery())
+
+
+    getAvailableQualityProfiles: ->
+      languages = @options.app.languageFilter.get('value')
+      singleLanguage = _.isArray(languages) && languages.length == 1
+
+      if singleLanguage
+        @options.app.getQualityProfilesForLanguage(languages[0])
+      else
+        @options.app.qualityProfiles
+
+    serializeData: ->
+      action: @action
+
+      paging: @options.app.codingRules.paging
+      qualityProfiles: @options.app.qualityProfiles
+
+      qualityProfile: @profile
+      qualityProfileName: @options.app.qualityProfileFilter.view.renderValue()
+
+      availableQualityProfiles: @getAvailableQualityProfiles()
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-custom-rule-creation-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-custom-rule-creation-view.coffee
new file mode 100644 (file)
index 0000000..0efc2a0
--- /dev/null
@@ -0,0 +1,179 @@
+define [
+  'backbone.marionette',
+  'templates/coding-rules-old'
+], (
+  Marionette,
+  Templates
+) ->
+
+  class CodingRulesCustomRuleCreationView extends Marionette.ItemView
+    className: 'coding-rules-modal'
+    template: Templates['coding-rules-custom-rule-creation']
+
+
+    ui:
+      customRuleCreationKey: '#coding-rules-custom-rule-creation-key'
+      customRuleCreationName: '#coding-rules-custom-rule-creation-name'
+      customRuleCreationHtmlDescription: '#coding-rules-custom-rule-creation-html-description'
+      customRuleCreationSeverity: '#coding-rules-custom-rule-creation-severity'
+      customRuleCreationStatus: '#coding-rules-custom-rule-creation-status'
+      customRuleCreationParameters: '[name]'
+      customRuleCreationCreate: '#coding-rules-custom-rule-creation-create'
+      customRuleCreationReactivate: '#coding-rules-custom-rule-creation-reactivate'
+      modalFoot: '.modal-foot'
+
+
+    events:
+      'input @ui.customRuleCreationName': 'generateKey'
+      'keydown @ui.customRuleCreationName': 'generateKey'
+      'keyup @ui.customRuleCreationName': 'generateKey'
+
+      'input @ui.customRuleCreationKey': 'flagKey'
+      'keydown @ui.customRuleCreationKey': 'flagKey'
+      'keyup @ui.customRuleCreationKey': 'flagKey'
+
+      'click #coding-rules-custom-rule-creation-cancel': 'hide'
+      'click @ui.customRuleCreationCreate': 'create'
+      'click @ui.customRuleCreationReactivate': 'reactivate'
+
+
+    generateKey: ->
+      unless @keyModifiedByUser
+        if @ui.customRuleCreationKey
+          generatedKey = @ui.customRuleCreationName.val().latinize().replace(/[^A-Za-z0-9]/g, '_')
+          @ui.customRuleCreationKey.val generatedKey
+
+    flagKey: ->
+      @keyModifiedByUser = true
+      # Cannot use @ui.customRuleCreationReactivate.hide() directly since it was not there at initial render
+      jQuery(@ui.customRuleCreationReactivate.selector).hide()
+
+
+    create: ->
+      action = 'create'
+      if @model and @model.has 'key'
+        action = 'update'
+
+      postData =
+        name: @ui.customRuleCreationName.val()
+        markdown_description: @ui.customRuleCreationHtmlDescription.val()
+        severity: @ui.customRuleCreationSeverity.val()
+        status: @ui.customRuleCreationStatus.val()
+
+      if @model && @model.has 'key'
+        postData.key = @model.get 'key'
+      else
+        postData.template_key = @templateRule.get 'key'
+        postData.custom_key = @ui.customRuleCreationKey.val()
+        postData.prevent_reactivation = true
+
+      params = @ui.customRuleCreationParameters.map(->
+        node = jQuery(@)
+        value = node.val()
+        if !value and action == 'create'
+          value = node.prop('placeholder') || ''
+        key: node.prop('name'), value: value).get()
+
+      postData.params = (params.map (param) -> param.key + '=' + window.csvEscape(param.value)).join(';')
+      @sendRequest(action, postData)
+
+
+    reactivate: ->
+      postData =
+        name: @existingRule.name
+        markdown_description: @existingRule.mdDesc
+        severity: @existingRule.severity
+        status: @existingRule.status
+        template_key: @existingRule.templateKey
+        custom_key: @ui.customRuleCreationKey.val()
+        prevent_reactivation: false
+
+      params = @existingRule.params
+      postData.params = (params.map (param) -> param.key + '=' + param.defaultValue).join(';')
+
+      @sendRequest('create', postData)
+
+
+    sendRequest: (action, postData) ->
+      @$('.modal-error').hide()
+      @$('.modal-warning').hide()
+
+      origFooter = @ui.modalFoot.html()
+      @ui.modalFoot.html '<i class="spinner"></i>'
+
+      jQuery.ajax
+        type: 'POST'
+        url: "#{baseUrl}/api/rules/" + action
+        data: postData
+        error: () ->
+      .done (r) =>
+          delete @templateRule
+          @options.app.showRule r.rule.key
+          @hide()
+      .fail (jqXHR, textStatus, errorThrown) =>
+          if jqXHR.status == 409
+            @existingRule = jqXHR.responseJSON.rule
+            @$('.modal-warning').show()
+            @ui.modalFoot.html Templates['coding-rules-custom-rule-reactivation'](@)
+          else
+            jQuery.ajaxSettings.error(jqXHR, textStatus, errorThrown)
+            @ui.modalFoot.html origFooter
+
+
+    onRender: ->
+      @$el.dialog
+        dialogClass: 'no-close',
+        width: '600px',
+        draggable: false,
+        autoOpen: false,
+        modal: true,
+        minHeight: 50,
+        resizable: false,
+        title: null
+
+      @keyModifiedByUser = false
+
+      format = (state) ->
+        return state.text unless state.id
+        "<i class='icon-severity-#{state.id.toLowerCase()}'></i> #{state.text}"
+
+      severity = (@model && @model.get 'severity') || @templateRule.get 'severity'
+      @ui.customRuleCreationSeverity.val severity
+      @ui.customRuleCreationSeverity.select2
+        width: '250px'
+        minimumResultsForSearch: 999
+        formatResult: format
+        formatSelection: format
+
+      status = (@model && @model.get 'status') || @templateRule.get 'status'
+      @ui.customRuleCreationStatus.val status
+      @ui.customRuleCreationStatus.select2
+        width: '250px'
+        minimumResultsForSearch: 999
+
+
+    show: ->
+      @render()
+      @$el.dialog 'open'
+
+
+    hide: ->
+      @$el.dialog 'close'
+
+
+    serializeData: ->
+      params = {}
+      if @templateRule
+        params = @templateRule.get 'params'
+      else if @model and @model.has 'params'
+        params = @model.get('params').map (p) ->
+          _.extend p,
+            value: p.defaultValue
+
+      _.extend super,
+        change: @model && @model.has 'key'
+        params: params
+        severities: ['BLOCKER', 'CRITICAL', 'MAJOR', 'MINOR', 'INFO']
+        statuses: _.map @options.app.statuses, (value, key) ->
+          id: key
+          text: value
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-debt-popup-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-debt-popup-view.coffee
new file mode 100644 (file)
index 0000000..3331b7d
--- /dev/null
@@ -0,0 +1,16 @@
+define [
+  'backbone.marionette'
+  'templates/coding-rules-old'
+  'common/popup'
+], (
+  Marionette
+  Templates
+  Popup
+) ->
+
+  class CodingRulesDebtPopupView extends Popup
+    template: Templates['coding-rules-debt-popup']
+
+    serializeData: ->
+      _.extend super,
+        subcharacteristic: @options.app.getSubcharacteristicName(@model.get 'debtSubChar')
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-detail-custom-rule-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-detail-custom-rule-view.coffee
new file mode 100644 (file)
index 0000000..84c1f33
--- /dev/null
@@ -0,0 +1,42 @@
+define [
+  'backbone.marionette'
+  'templates/coding-rules-old'
+], (
+  Marionette
+  Templates
+) ->
+
+  class CodingRulesDetailCustomRuleView extends Marionette.ItemView
+    tagName: 'tr'
+    className: 'coding-rules-detail-custom-rule'
+    template: Templates['coding-rules-detail-custom-rule']
+
+    ui:
+      delete: '.coding-rules-detail-custom-rule-delete'
+
+    events:
+      'click @ui.delete': 'delete'
+
+    delete: ->
+      confirmDialog
+        title: t 'delete'
+        html: t 'are_you_sure'
+        yesHandler: =>
+          origEl = @$el.html()
+          @$el.html '<i class="spinner"></i>'
+
+          jQuery.ajax
+            type: 'POST'
+            url: "#{baseUrl}/api/rules/delete"
+            data:
+              key: @model.get 'key'
+          .done =>
+            templateKey = @options.templateKey or @options.templateRule.get 'key'
+            @options.app.showRule templateKey
+          .fail =>
+            @$el.html origEl
+
+    serializeData: ->
+      _.extend super,
+        templateRule: @options.templateRule
+        canWrite: @options.app.canWrite
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-detail-custom-rules-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-detail-custom-rules-view.coffee
new file mode 100644 (file)
index 0000000..b5df8e7
--- /dev/null
@@ -0,0 +1,16 @@
+define [
+  'backbone.marionette'
+  'coding-rules-old/views/coding-rules-detail-custom-rule-view'
+], (
+  Marionette
+  CodingRulesDetailCustomRuleView
+) ->
+
+  class CodingRulesDetailCustomRulesView extends Marionette.CollectionView
+    tagName: 'table'
+    className: 'width100'
+    itemView: CodingRulesDetailCustomRuleView
+
+    itemViewOptions: ->
+      app: @options.app
+      templateRule: @options.templateRule
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-detail-quality-profile-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-detail-quality-profile-view.coffee
new file mode 100644 (file)
index 0000000..ef8a98d
--- /dev/null
@@ -0,0 +1,101 @@
+define [
+  'backbone.marionette',
+  'templates/coding-rules-old'
+], (
+  Marionette,
+  Templates
+) ->
+
+  class CodingRulesDetailQualityProfileView extends Marionette.ItemView
+    className: 'coding-rules-detail-quality-profile'
+    template: Templates['coding-rules-detail-quality-profile']
+
+
+    modelEvents:
+      'change': 'render'
+
+
+    ui:
+      change: '.coding-rules-detail-quality-profile-change'
+      revert: '.coding-rules-detail-quality-profile-revert'
+      deactivate: '.coding-rules-detail-quality-profile-deactivate'
+
+
+    events:
+      'click @ui.change': 'change'
+      'click @ui.revert': 'revert'
+      'click @ui.deactivate': 'deactivate'
+
+
+    change: ->
+      @options.app.codingRulesQualityProfileActivationView.model = @model
+      @options.app.codingRulesQualityProfileActivationView.show()
+
+
+    revert: ->
+      ruleKey = @options.rule.get('key')
+      confirmDialog
+        title: t 'coding_rules.revert_to_parent_definition'
+        html: tp 'coding_rules.revert_to_parent_definition.confirm', @getParent().name
+        yesHandler: =>
+          jQuery.ajax
+            type: 'POST'
+            url: "#{baseUrl}/api/qualityprofiles/activate_rule"
+            data:
+              profile_key: @model.get('qProfile')
+              rule_key: ruleKey
+              reset: true
+          .done =>
+            @options.app.showRule ruleKey
+
+
+    deactivate: ->
+      ruleKey = @options.rule.get('key')
+      myProfile = _.findWhere(@options.app.qualityProfiles, key: @model.get('qProfile'))
+      confirmDialog
+        title: t 'coding_rules.deactivate'
+        html: tp 'coding_rules.deactivate.confirm', myProfile.name
+        yesHandler: =>
+          jQuery.ajax
+            type: 'POST'
+            url: "#{baseUrl}/api/qualityprofiles/deactivate_rule"
+            data:
+              profile_key: @model.get('qProfile')
+              rule_key: ruleKey
+          .done =>
+            @options.app.showRule ruleKey
+
+
+    enableUpdate: ->
+      @ui.update.prop 'disabled', false
+
+
+    getParent: ->
+      return null unless @model.get('inherit') && @model.get('inherit') != 'NONE'
+      myProfile = _.findWhere(@options.app.qualityProfiles, key: @model.get('qProfile'))
+      parentKey = myProfile.parentKey
+      parent = _.extend {}, _.findWhere(@options.app.qualityProfiles, key: parentKey)
+      parentActiveInfo = @model.collection.findWhere(qProfile: parentKey) or new Backbone.Model()
+      _.extend parent, parentActiveInfo.toJSON()
+      parent
+
+
+    enhanceParameters: ->
+      parent = @getParent()
+      params = _.sortBy(@model.get('params'), 'key')
+      return params unless parent
+      params.map (p) ->
+        parentParam = _.findWhere(parent.params, key: p.key)
+        if parentParam
+          _.extend p, original: _.findWhere(parent.params, key: p.key).value
+        else
+          p
+
+
+    serializeData: ->
+      hash = _.extend super,
+        parent: @getParent()
+        parameters: @enhanceParameters()
+        canWrite: @options.app.canWrite
+        templateKey: @options.rule.get 'templateKey'
+        isTemplate: @options.rule.get 'isTemplate'
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-detail-quality-profiles-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-detail-quality-profiles-view.coffee
new file mode 100644 (file)
index 0000000..b26bbee
--- /dev/null
@@ -0,0 +1,15 @@
+define [
+  'backbone.marionette'
+  'coding-rules-old/views/coding-rules-detail-quality-profile-view'
+], (
+  Marionette,
+  CodingRulesDetailQualityProfileView
+) ->
+
+  class CodingRulesDetailQualityProfilesView extends Marionette.CollectionView
+    itemView: CodingRulesDetailQualityProfileView
+
+    itemViewOptions: ->
+      app: @options.app
+      rule: @options.rule
+      qualityProfiles: @collection
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-detail-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-detail-view.coffee
new file mode 100644 (file)
index 0000000..20bf8c7
--- /dev/null
@@ -0,0 +1,344 @@
+define [
+  'backbone'
+  'backbone.marionette'
+  'coding-rules-old/views/coding-rules-detail-quality-profiles-view'
+  'coding-rules-old/views/coding-rules-detail-quality-profile-view'
+  'coding-rules-old/views/coding-rules-detail-custom-rules-view'
+  'coding-rules-old/views/coding-rules-detail-custom-rule-view'
+  'coding-rules-old/views/coding-rules-parameter-popup-view'
+  'coding-rules-old/views/coding-rules-debt-popup-view'
+  'templates/coding-rules-old'
+], (
+  Backbone
+  Marionette
+  CodingRulesDetailQualityProfilesView
+  CodingRulesDetailQualityProfileView
+  CodingRulesDetailCustomRulesView
+  CodingRulesDetailCustomRuleView
+  CodingRulesParameterPopupView
+  CodingRulesDebtPopupView
+  Templates
+) ->
+
+  class CodingRulesDetailView extends Marionette.Layout
+    template: Templates['coding-rules-detail']
+
+
+    regions:
+      qualityProfilesRegion: '#coding-rules-detail-quality-profiles'
+      customRulesRegion: '.coding-rules-detail-custom-rules-section'
+      customRulesListRegion: '#coding-rules-detail-custom-rules'
+      contextRegion: '.coding-rules-detail-context'
+
+
+    ui:
+      tagsChange: '.coding-rules-detail-tags-change'
+      tagInput: '.coding-rules-detail-tag-input'
+      tagsEdit: '.coding-rules-detail-tag-edit'
+      tagsEditDone: '.coding-rules-detail-tag-edit-done'
+      tagsEditCancel: '.coding-rules-details-tag-edit-cancel'
+      tagsList: '.coding-rules-detail-tag-list'
+
+      subcharacteristic: '.coding-rules-subcharacteristic'
+
+      descriptionExtra: '#coding-rules-detail-description-extra'
+      extendDescriptionLink: '#coding-rules-detail-extend-description'
+      extendDescriptionForm: '.coding-rules-detail-extend-description-form'
+      extendDescriptionSubmit: '#coding-rules-detail-extend-description-submit'
+      extendDescriptionRemove: '#coding-rules-detail-extend-description-remove'
+      extendDescriptionText: '#coding-rules-detail-extend-description-text'
+      extendDescriptionSpinner: '#coding-rules-detail-extend-description-spinner'
+      cancelExtendDescription: '#coding-rules-detail-extend-description-cancel'
+
+      activateQualityProfile: '#coding-rules-quality-profile-activate'
+      activateContextQualityProfile: '.coding-rules-detail-quality-profile-activate'
+      changeQualityProfile: '.coding-rules-detail-quality-profile-update'
+      createCustomRule: '#coding-rules-custom-rules-create'
+      changeCustomRule: '#coding-rules-detail-custom-rule-change'
+      changeManualRule: '#coding-rules-detail-manual-rule-change'
+      deleteCustomRule: '#coding-rules-detail-rule-delete'
+
+
+    events:
+      'click @ui.tagsChange': 'changeTags'
+      'click @ui.tagsEditDone': 'editDone'
+      'click @ui.tagsEditCancel': 'cancelEdit'
+
+      'click @ui.extendDescriptionLink': 'showExtendDescriptionForm'
+      'click @ui.cancelExtendDescription': 'hideExtendDescriptionForm'
+      'click @ui.extendDescriptionSubmit': 'submitExtendDescription'
+      'click @ui.extendDescriptionRemove': 'removeExtendedDescription'
+
+      'click @ui.activateQualityProfile': 'activateQualityProfile'
+      'click @ui.activateContextQualityProfile': 'activateContextQualityProfile'
+      'click @ui.changeQualityProfile': 'changeQualityProfile'
+      'click @ui.createCustomRule': 'createCustomRule'
+      'click @ui.changeCustomRule': 'changeCustomRule'
+      'click @ui.changeManualRule': 'changeManualRule'
+      'click @ui.deleteCustomRule': 'deleteRule'
+
+      'click .coding-rules-detail-parameter-name': 'toggleParameterDescription'
+      'click .coding-rules-subcharacteristic': 'showDebtPopup'
+
+    initialize: (options) ->
+      super options
+
+      if @model.get 'params'
+        origParams = @model.get('params')
+        @model.set 'params', _.sortBy(origParams, 'key')
+
+      _.map options.actives, (active) =>
+        _.extend active, options.app.getQualityProfileByKey active.qProfile
+      qualityProfiles = new Backbone.Collection options.actives,
+        comparator: 'name'
+      @qualityProfilesView = new CodingRulesDetailQualityProfilesView
+        app: @options.app
+        collection: qualityProfiles
+        rule: @model
+
+      unless @model.get 'isTemplate'
+        qualityProfileKey = @options.app.getQualityProfile()
+
+        if qualityProfileKey
+          @contextProfile = qualityProfiles.findWhere qProfile: qualityProfileKey
+          unless @contextProfile
+            @contextProfile = new Backbone.Model
+              key: qualityProfileKey, name: @options.app.qualityProfileFilter.view.renderValue()
+          @contextQualityProfileView = new CodingRulesDetailQualityProfileView
+            app: @options.app
+            model: @contextProfile
+            rule: @model
+            qualityProfiles: qualityProfiles
+
+          @listenTo @contextProfile, 'destroy', @hideContext
+
+    onRender: ->
+      @$el.find('.open-modal').modal()
+
+      if @model.get 'isTemplate'
+        @$(@contextRegion.el).hide()
+
+        if _.isEmpty(@options.actives)
+          @$(@qualityProfilesRegion.el).hide()
+        else
+          @qualityProfilesRegion.show @qualityProfilesView
+
+        @$(@customRulesRegion.el).show()
+        customRulesOriginal = @$(@customRulesRegion.el).html()
+
+        @$(@customRulesRegion.el).html '<i class="spinner"></i>'
+
+        customRules = new Backbone.Collection()
+        jQuery.ajax
+          url: "#{baseUrl}/api/rules/search"
+          data:
+            template_key: @model.get 'key'
+            f: 'name,severity,params'
+        .done (r) =>
+          customRules.add r.rules
+
+          # Protect against element disappearing due to navigation
+          if @customRulesRegion
+            if customRules.isEmpty() and not @options.app.canWrite
+              @$(@customRulesRegion.el).hide()
+            else
+              @customRulesView = new CodingRulesDetailCustomRulesView
+                app: @options.app
+                collection: customRules
+                templateRule: @model
+              @$(@customRulesRegion.el).html customRulesOriginal
+              @customRulesListRegion.show @customRulesView
+
+      else
+        @$(@customRulesRegion.el).hide()
+        @$(@qualityProfilesRegion.el).show()
+        @qualityProfilesRegion.show @qualityProfilesView
+
+        if @options.app.getQualityProfile() and (@options.app.canWrite or @contextProfile.has('severity'))
+          @$(@contextRegion.el).show()
+          @contextRegion.show @contextQualityProfileView
+        else
+          @$(@contextRegion.el).hide()
+
+      that = @
+      jQuery.ajax
+        url: "#{baseUrl}/api/rules/tags"
+      .done (r) =>
+        if @ui.tagInput.select2
+          # Prevent synchronization issue with navigation
+          @ui.tagInput.select2
+            tags: _.difference (_.difference r.tags, that.model.get 'tags'), that.model.get 'sysTags'
+            width: '300px'
+
+      @ui.tagsEdit.hide()
+
+      @ui.extendDescriptionForm.hide()
+      @ui.extendDescriptionSpinner.hide()
+
+
+    toggleParameterDescription: (e) ->
+      jQuery(e.currentTarget).next('.coding-rules-detail-parameter-description').toggle();
+
+
+    showDebtPopup: (e) ->
+      e.stopPropagation()
+      jQuery('body').click()
+      popup = new CodingRulesDebtPopupView
+        model: @model
+        app: @options.app
+        triggerEl: jQuery(e.currentTarget)
+      popup.render()
+      false
+
+
+    hideContext: ->
+      @contextRegion.reset()
+      @$(@contextRegion.el).hide()
+
+
+    changeTags: ->
+      if @ui.tagsEdit.show
+        @ui.tagsEdit.show()
+      if @ui.tagsList.hide
+        @ui.tagsList.hide()
+      @tagsBuffer = @ui.tagInput.select2 'val'
+      key.setScope 'tags'
+      key 'escape', 'tags', => @cancelEdit()
+
+
+    cancelEdit: ->
+      key.unbind 'escape', 'tags'
+      if @ui.tagsList.show
+        @ui.tagsList.show()
+      if @ui.tagInput.select2
+        console.log @tagsBuffer
+        @ui.tagInput.select2 'val', @tagsBuffer
+        @ui.tagInput.select2 'close'
+      if @ui.tagsEdit.hide
+        @ui.tagsEdit.hide()
+
+
+    editDone: ->
+      @ui.tagsEdit.html '<i class="spinner"></i>'
+      tags = @ui.tagInput.val()
+      jQuery.ajax
+        type: 'POST'
+        url: "#{baseUrl}/api/rules/update"
+        data:
+          key: @model.get 'key'
+          tags: tags
+      .done (r) =>
+          @model.set 'tags', r.rule.tags
+          @cancelEdit()
+      .always =>
+        @render()
+
+
+    showExtendDescriptionForm: ->
+      @ui.descriptionExtra.hide()
+      @ui.extendDescriptionForm.show()
+      key.setScope 'extraDesc'
+      key 'escape', 'extraDesc', => @hideExtendDescriptionForm()
+      @ui.extendDescriptionText.focus()
+
+
+    hideExtendDescriptionForm: ->
+      key.unbind 'escape', 'extraDesc'
+      @ui.descriptionExtra.show()
+      @ui.extendDescriptionForm.hide()
+
+
+    submitExtendDescription: ->
+      @ui.extendDescriptionForm.hide()
+      @ui.extendDescriptionSpinner.show()
+      jQuery.ajax
+        type: 'POST'
+        url: "#{baseUrl}/api/rules/update"
+        dataType: 'json'
+        data:
+          key: @model.get 'key'
+          markdown_note: @ui.extendDescriptionText.val()
+      .done (r) =>
+        @model.set
+          htmlNote: r.rule.htmlNote
+          mdNote: r.rule.mdNote
+        @render()
+
+
+    removeExtendedDescription: ->
+      confirmDialog
+        html: t 'coding_rules.remove_extended_description.confirm'
+        yesHandler: =>
+          @ui.extendDescriptionText.val ''
+          @submitExtendDescription()
+
+
+    activateQualityProfile: ->
+      @options.app.codingRulesQualityProfileActivationView.model = null
+      @options.app.codingRulesQualityProfileActivationView.show()
+
+
+    activateContextQualityProfile: ->
+      @options.app.codingRulesQualityProfileActivationView.model = @contextProfile
+      @options.app.codingRulesQualityProfileActivationView.show()
+
+    createCustomRule: ->
+      @options.app.codingRulesCustomRuleCreationView.templateRule = @model
+      @options.app.codingRulesCustomRuleCreationView.model = new Backbone.Model()
+      @options.app.codingRulesCustomRuleCreationView.show()
+
+
+    changeCustomRule: ->
+      @options.app.codingRulesCustomRuleCreationView.model = @model
+      @options.app.codingRulesCustomRuleCreationView.show()
+
+
+    changeManualRule: ->
+      @options.app.codingRulesManualRuleCreationView.model = @model
+      @options.app.codingRulesManualRuleCreationView.show()
+
+
+    deleteRule: ->
+      ruleType = if @model.has('templateKey') then 'custom' else 'manual'
+      confirmDialog
+        title: t 'delete'
+        html: tp "coding_rules.delete.#{ruleType}.confirm", @model.get('name')
+        yesHandler: =>
+          jQuery.ajax
+            type: 'POST'
+            url: "#{baseUrl}/api/rules/delete"
+            data:
+              key: @model.get 'key'
+          .done =>
+            @options.app.fetchFirstPage()
+          .fail =>
+            @options.app.showRule @model.get('key')
+
+
+    serializeData: ->
+      contextQualityProfile = @options.app.getQualityProfile()
+      repoKey = @model.get 'repo'
+      isManual = (@options.app.manualRepository().key == repoKey)
+      isCustom = (@model.has 'templateKey')
+
+      qualityProfilesVisible = not isManual
+      if qualityProfilesVisible
+        if @model.get 'isTemplate'
+          qualityProfilesVisible = (not _.isEmpty(@options.actives))
+        else
+          qualityProfilesVisible = (@options.app.canWrite or not _.isEmpty(@options.actives))
+
+
+      _.extend super,
+        contextQualityProfile: contextQualityProfile
+        contextQualityProfileName: @options.app.qualityProfileFilter.view.renderValue()
+        qualityProfile: @contextProfile
+        language: @options.app.languages[@model.get 'lang']
+        repository: _.find(@options.app.repositories, (repo) -> repo.key == repoKey).name
+        isManual: isManual
+        canWrite: @options.app.canWrite
+        isEditable: (@options.app.canWrite and (isManual or isCustom))
+        qualityProfilesVisible: qualityProfilesVisible
+        subcharacteristic: @options.app.getSubcharacteristicName(@model.get 'debtSubChar')
+        createdAt: moment(@model.get 'createdAt').toDate()
+        allTags: _.union @model.get('sysTags'), @model.get('tags')
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-facets-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-facets-view.coffee
new file mode 100644 (file)
index 0000000..7a20939
--- /dev/null
@@ -0,0 +1,53 @@
+define [
+  'backbone.marionette'
+  'templates/coding-rules-old'
+], (
+  Marionette,
+  Templates
+) ->
+
+  class CodingRulesFacetsView extends Marionette.ItemView
+    template: Templates['coding-rules-facets']
+
+
+    ui:
+      facets: '.navigator-facets-list-item'
+      options: '.facet'
+
+
+    events:
+      'click @ui.options': 'selectOption'
+
+
+    initialize: ->
+      super()
+      that = @
+      @options.collection.each (facet) ->
+        property = facet.get 'property'
+        facet.set 'property_message', t 'coding_rules.facets.' + property
+        facet.set 'limitReached', facet.get('values').length >= 10
+        _.each(facet.get('values'), (value) ->
+          value.text = that.options.app.facetLabel(property, value.val)
+        )
+
+    selectOption: (e) ->
+      option = jQuery(e.currentTarget)
+      option.toggleClass 'active'
+      property = option.closest('.navigator-facets-list-item').data('property')
+      value = option.data('key')
+      @options.app.filterBarView.toggle(property, value)
+      @applyOptions()
+
+
+    applyOptions: ->
+      @options.app.fetchFirstPage()
+
+
+    restoreFromQuery: (params) ->
+      @ui.options.each ->
+        jQuery(@).removeClass('active')
+      @ui.facets.each ->
+        property = jQuery(@).data 'property'
+        if !!params[property]
+          _(params[property].split(',')).map (value) ->
+            jQuery('.navigator-facets-list-item[data-property="' + property + '"] .facet[data-key="' + value + '"]').addClass 'active'
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-list-empty-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-list-empty-view.coffee
new file mode 100644 (file)
index 0000000..a428e4c
--- /dev/null
@@ -0,0 +1,12 @@
+define [
+  'backbone.marionette',
+  'templates/coding-rules-old'
+], (
+  Marionette,
+  Templates
+) ->
+
+  class CodingRulesListEmptyView extends Marionette.ItemView
+    tagName: 'li'
+    className: 'navigator-results-no-results'
+    template: Templates['coding-rules-list-empty']
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-list-item-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-list-item-view.coffee
new file mode 100644 (file)
index 0000000..6b46aba
--- /dev/null
@@ -0,0 +1,31 @@
+define [
+  'backbone.marionette',
+  'coding-rules-old/views/coding-rules-detail-view',
+  'templates/coding-rules-old'
+], (
+  Marionette,
+  CodingRulesDetailView,
+  Templates
+) ->
+
+  class CodingRulesListItemView extends Marionette.ItemView
+    tagName: 'li'
+    template: Templates['coding-rules-list-item']
+    activeClass: 'active'
+
+
+    events: ->
+      'click': 'showDetail'
+
+
+    showDetail: ->
+      @options.listView.selectIssue @$el
+      @options.app.showRule @model.get('key')
+
+
+    serializeData: ->
+      tags = _.union @model.get('sysTags'), @model.get('tags')
+      _.extend super,
+        manualRuleLabel: t 'coding_rules.manual_rule'
+        allTags: tags
+        showDetails: (@model.get('status') != 'READY') || (_.isArray(tags) && tags.length > 0)
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-list-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-list-view.coffee
new file mode 100644 (file)
index 0000000..7669b57
--- /dev/null
@@ -0,0 +1,93 @@
+define [
+  'backbone.marionette',
+  'coding-rules-old/views/coding-rules-list-item-view',
+  'coding-rules-old/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
+
+
+    initialize: ->
+      openRule = (el) -> el.click()
+      @openRule = _.debounce openRule, 300
+      key.setScope 'list'
+
+
+    onRender: ->
+      key 'up', 'list', (e) =>
+        @selectPrev()
+        #e.stopPropagation()
+      key 'down', 'list', (e) =>
+        @selectNext()
+        #e.stopPropagation()
+
+      $scrollEl = jQuery('.navigator-results')
+      scrollEl = $scrollEl.get(0)
+      onScroll = =>
+        if scrollEl.offsetHeight + scrollEl.scrollTop >= scrollEl.scrollHeight
+          @options.app.fetchNextPage()
+      throttledScroll = _.throttle onScroll, 300
+      $scrollEl.off('scroll').on 'scroll', throttledScroll
+
+
+    onClose: ->
+      @unbindEvents()
+
+
+    unbindEvents: ->
+      key.unbind 'up', 'list'
+      key.unbind 'down', 'list'
+
+
+    selectIssue: (el, open) ->
+      @$('.active').removeClass 'active'
+      el.addClass 'active'
+      ruleKey = el.find('[name]').attr('name')
+      rule = @collection.findWhere key: ruleKey
+      @selected = @collection.indexOf(rule)
+      @openRule el if open
+
+
+    selectFirst: ->
+      @selected = -1
+      @selectNext()
+
+
+    selectCurrent: ->
+      @selected--
+      @selectNext()
+
+
+    selectNext: ->
+      if @selected + 1 < @collection.length
+        @selected += 1
+        child = @$el.children().eq(@selected)
+        container = jQuery('.navigator-results')
+        containerHeight = container.height()
+        bottom = child.position().top + child.outerHeight()
+        if bottom > containerHeight
+          container.scrollTop(container.scrollTop() - containerHeight + bottom)
+        @selectIssue child, true
+
+
+    selectPrev: ->
+      if @selected > 0
+        @selected -= 1
+        child = @$el.children().eq(@selected)
+        container = jQuery('.navigator-results')
+        top = child.position().top
+        if top < 0
+          container.scrollTop(container.scrollTop() + top)
+        @selectIssue child, true
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-manual-rule-creation-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-manual-rule-creation-view.coffee
new file mode 100644 (file)
index 0000000..5d48f9c
--- /dev/null
@@ -0,0 +1,133 @@
+define [
+  'backbone.marionette',
+  'templates/coding-rules-old'
+], (
+  Marionette,
+  Templates
+) ->
+
+  class CodingRulesManualRuleCreationView extends Marionette.ItemView
+    template: Templates['coding-rules-manual-rule-creation']
+
+
+    ui:
+      manualRuleCreationKey: '#coding-rules-manual-rule-creation-key'
+      manualRuleCreationName: '#coding-rules-manual-rule-creation-name'
+      manualRuleCreationHtmlDescription: '#coding-rules-manual-rule-creation-html-description'
+      manualRuleCreationSeverity: '#coding-rules-manual-rule-creation-severity'
+      manualRuleCreationStatus: '#coding-rules-manual-rule-creation-status'
+      manualRuleCreationParameters: '[name]'
+      manualRuleCreationCreate: '#coding-rules-manual-rule-creation-create'
+      manualRuleCreationReactivate: '#coding-rules-manual-rule-creation-reactivate'
+      modalFoot: '.modal-foot'
+
+
+    events:
+      'input @ui.manualRuleCreationName': 'generateKey'
+      'keydown @ui.manualRuleCreationName': 'generateKey'
+      'keyup @ui.manualRuleCreationName': 'generateKey'
+
+      'input @ui.manualRuleCreationKey': 'flagKey'
+      'keydown @ui.manualRuleCreationKey': 'flagKey'
+      'keyup @ui.manualRuleCreationKey': 'flagKey'
+
+      'click #coding-rules-manual-rule-creation-cancel': 'hide'
+      'click @ui.manualRuleCreationCreate': 'create'
+      'click @ui.manualRuleCreationReactivate': 'reactivate'
+
+
+    generateKey: ->
+      unless @keyModifiedByUser
+        if @ui.manualRuleCreationKey
+          generatedKey = @ui.manualRuleCreationName.val().latinize().replace(/[^A-Za-z0-9]/g, '_')
+          @ui.manualRuleCreationKey.val generatedKey
+
+    flagKey: ->
+      @keyModifiedByUser = true
+      # Cannot use @ui.manualRuleCreationReactivate.hide() directly since it was not there at initial render
+      jQuery(@ui.manualRuleCreationReactivate.selector).hide()
+
+
+    create: ->
+      action = 'create'
+      if @model and @model.has 'key'
+        action = 'update'
+
+      postData =
+        name: @ui.manualRuleCreationName.val()
+        markdown_description: @ui.manualRuleCreationHtmlDescription.val()
+
+      if @model && @model.has 'key'
+        postData.key = @model.get 'key'
+      else
+        postData.manual_key = @ui.manualRuleCreationKey.val()
+        postData.prevent_reactivation = true
+
+      @sendRequest(action, postData)
+
+
+    reactivate: ->
+      postData =
+        name: @existingRule.name
+        markdown_description: @existingRule.mdDesc
+        manual_key: @ui.manualRuleCreationKey.val()
+        prevent_reactivation: false
+
+      @sendRequest('create', postData)
+
+
+    sendRequest: (action, postData) ->
+      @$('.modal-error').hide()
+      @$('.modal-warning').hide()
+
+      origFooter = @ui.modalFoot.html()
+      @ui.modalFoot.html '<i class="spinner"></i>'
+
+      jQuery.ajax
+        type: 'POST'
+        url: "#{baseUrl}/api/rules/" + action
+        data: postData
+        error: () ->
+      .done (r) =>
+          @options.app.showRule r.rule.key
+          @hide()
+      .fail (jqXHR, textStatus, errorThrown) =>
+          if jqXHR.status == 409
+            @existingRule = jqXHR.responseJSON.rule
+            @$('.modal-warning').show()
+            @ui.modalFoot.html Templates['coding-rules-manual-rule-reactivation'](@)
+          else
+            jQuery.ajaxSettings.error(jqXHR, textStatus, errorThrown)
+            @ui.modalFoot.html origFooter
+
+
+    onRender: ->
+      @$el.dialog
+        dialogClass: 'no-close',
+        width: '600px',
+        draggable: false,
+        autoOpen: false,
+        modal: true,
+        minHeight: 50,
+        resizable: false,
+        title: null
+
+      @keyModifiedByUser = false
+
+      format = (state) ->
+        return state.text unless state.id
+        "<i class='icon-severity-#{state.id.toLowerCase()}'></i> #{state.text}"
+
+
+    show: ->
+      @render()
+      @$el.dialog 'open'
+
+
+    hide: ->
+      @$el.dialog 'close'
+
+
+    serializeData: ->
+      _.extend super,
+        change: @model && @model.has 'key'
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-parameter-popup-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-parameter-popup-view.coffee
new file mode 100644 (file)
index 0000000..cdee879
--- /dev/null
@@ -0,0 +1,15 @@
+define [
+  'backbone.marionette'
+  'templates/coding-rules-old'
+  'common/popup'
+], (
+  Marionette
+  Templates
+  Popup
+) ->
+
+  $ = jQuery
+
+
+  class CodingRulesParameterPopupView extends Popup
+    template: Templates['coding-rules-parameter-popup']
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-quality-profile-activation-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-quality-profile-activation-view.coffee
new file mode 100644 (file)
index 0000000..2d7f00a
--- /dev/null
@@ -0,0 +1,124 @@
+define [
+  'backbone.marionette',
+  'templates/coding-rules-old'
+], (
+  Marionette,
+  Templates
+) ->
+
+  class CodingRulesQualityProfileActivationView extends Marionette.ItemView
+    className: 'coding-rules-modal'
+    template: Templates['coding-rules-quality-profile-activation']
+
+
+    ui:
+      qualityProfileSelect: '#coding-rules-quality-profile-activation-select'
+      qualityProfileSeverity: '#coding-rules-quality-profile-activation-severity'
+      qualityProfileActivate: '#coding-rules-quality-profile-activation-activate'
+      qualityProfileParameters: '[name]'
+
+
+    events:
+      'click #coding-rules-quality-profile-activation-cancel': 'hide'
+      'click @ui.qualityProfileActivate': 'activate'
+
+
+    activate: ->
+      profileKey = @ui.qualityProfileSelect.val()
+      params = @ui.qualityProfileParameters.map(->
+        key: jQuery(@).prop('name'), value: jQuery(@).val() || jQuery(@).prop('placeholder') || '').get()
+
+      paramsHash = (params.map (param) -> param.key + '=' + window.csvEscape(param.value)).join(';')
+
+      if @model
+        profileKey = @model.get('qProfile')
+        unless profileKey
+          profileKey = @model.get('key')
+      severity = @ui.qualityProfileSeverity.val()
+
+      origFooter = @$('.modal-foot').html()
+      @$('.modal-foot').html '<i class="spinner"></i>'
+
+      ruleKey = @rule.get('key')
+      jQuery.ajax
+        type: 'POST'
+        url: "#{baseUrl}/api/qualityprofiles/activate_rule"
+        data:
+          profile_key: profileKey
+          rule_key: ruleKey
+          severity: severity
+          params: paramsHash
+      .done =>
+          @options.app.showRule ruleKey
+          @hide()
+      .fail =>
+          @$('.modal-foot').html origFooter
+
+
+    onRender: ->
+      @$el.dialog
+        dialogClass: 'no-close',
+        width: '600px',
+        draggable: false,
+        autoOpen: false,
+        modal: true,
+        minHeight: 50,
+        resizable: false,
+        title: null
+
+      @ui.qualityProfileSelect.select2
+        width: '250px'
+        minimumResultsForSearch: 5
+
+      format = (state) ->
+        return state.text unless state.id
+        "<i class='icon-severity-#{state.id.toLowerCase()}'></i> #{state.text}"
+
+      severity = (@model && @model.get 'severity') || @rule.get 'severity'
+      @ui.qualityProfileSeverity.val severity
+      @ui.qualityProfileSeverity.select2
+        width: '250px'
+        minimumResultsForSearch: 999
+        formatResult: format
+        formatSelection: format
+
+
+    show: ->
+      @render()
+      @$el.dialog 'open'
+
+
+    hide: ->
+      @$el.dialog 'close'
+
+
+    getAvailableQualityProfiles: (lang) ->
+      activeQualityProfiles =  @options.app.detailView.qualityProfilesView.collection
+      inactiveProfiles = _.reject @options.app.qualityProfiles, (profile) =>
+        activeQualityProfiles.findWhere key: profile.key
+      _.filter inactiveProfiles, (profile) =>
+        profile.lang == lang
+
+
+    serializeData: ->
+      params = @rule.get 'params'
+      if @model
+        modelParams = @model.get 'params'
+        if modelParams
+          params = params.map (p) ->
+            parentParam = _.findWhere(modelParams, key: p.key)
+            if parentParam
+              _.extend p, value: _.findWhere(modelParams, key: p.key).value
+            else
+              p
+
+      availableProfiles = @getAvailableQualityProfiles(@rule.get 'lang')
+
+      _.extend super,
+        rule: @rule.toJSON()
+        change: @model && @model.has 'severity'
+        params: params
+        qualityProfiles: availableProfiles
+        severities: ['BLOCKER', 'CRITICAL', 'MAJOR', 'MINOR', 'INFO']
+        saveEnabled: not _.isEmpty(availableProfiles) or (@model and @model.get('qProfile'))
+        isCustomRule: (@model and @model.has('templateKey')) or @rule.has 'templateKey'
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/filter-bar-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/filter-bar-view.coffee
new file mode 100644 (file)
index 0000000..edd69fb
--- /dev/null
@@ -0,0 +1,97 @@
+define [
+  'navigator/filters/filter-bar',
+  'navigator/filters/base-filters',
+  'navigator/filters/favorite-filters',
+  'navigator/filters/more-criteria-filters',
+  'navigator/filters/read-only-filters',
+  'templates/coding-rules-old'
+], (
+  FilterBarView,
+  BaseFilters,
+  FavoriteFiltersModule,
+  MoreCriteriaFilters,
+  ReadOnlyFilterView,
+  Templates
+) ->
+
+  class CodingRulesFilterBarView extends FilterBarView
+    template: Templates['coding-rules-filter-bar']
+
+    collectionEvents:
+      'change:enabled': 'changeEnabled'
+
+
+    events:
+      'click .navigator-filter-submit': 'search'
+
+
+    onRender: ->
+      @selectFirst()
+
+
+    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: ->
+      readOnlyFilters = @collection.where(type: ReadOnlyFilterView)
+      disabledFilters = _.difference(@collection.where(enabled: false), readOnlyFilters)
+      if disabledFilters.length > 0
+        @moreCriteriaFilter = new BaseFilters.Filter
+          type: MoreCriteriaFilters.MoreCriteriaFilterView,
+          enabled: true,
+          optional: false,
+          filters: disabledFilters
+        @collection.add @moreCriteriaFilter
+
+
+    changeEnabled: ->
+      if @moreCriteriaFilter?
+        disabledFilters = _.reject @collection.where(enabled: false), (filter) ->
+          filter.get('type') in [MoreCriteriaFilters.MoreCriteriaFilterView, ReadOnlyFilterView]
+
+        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: ->
+      @$('.navigator-filter-submit').blur()
+      @options.app.state.set
+        query: this.options.app.getQuery(),
+        search: true
+      @options.app.fetchFirstPage()
+
+
+    fetchNextPage: ->
+      @options.app.fetchNextPage()
+
+
+    restoreFromWsQuery: (query) ->
+      params = _.map(query, (value, key) ->
+        'key': key
+        'value': value
+      )
+      @restoreFromQuery params
+
+
+    toggle: (property, value) ->
+      filter = @collection.findWhere(property: property)
+      unless filter.view.isActive()
+        @moreCriteriaFilter.view.detailsView.enableByProperty(property)
+      choice = filter.view.choices.get(value)
+      choice.set 'checked', !choice.get('checked')
+      filter.view.detailsView.updateValue()
+      filter.view.detailsView.updateLists()
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/activation-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/activation-filter-view.coffee
new file mode 100644 (file)
index 0000000..e6d3399
--- /dev/null
@@ -0,0 +1,32 @@
+define [
+  'coding-rules-old/views/filters/profile-dependent-filter-view'
+], (
+  ProfileDependentFilterView
+) ->
+
+  class ActivationFilterView extends ProfileDependentFilterView
+    tooltip: 'coding_rules.filters.activation.help'
+
+
+    makeActive: ->
+      super
+      filterValue = @model.get 'value'
+      if !filterValue or filterValue.length == 0
+        @choices.each (model) -> model.set 'checked', model.id == 'true'
+        @model.set 'value', ['true']
+        @detailsView.updateLists()
+
+
+
+    showDetails: ->
+      super unless @$el.is '.navigator-filter-inactive'
+
+
+    restore: (value) ->
+      value = value.split(',') if _.isString(value)
+      if @choices && value.length > 0
+        @choices.each (model) -> model.set 'checked', value.indexOf(model.id) >= 0
+        @model.set value: value, enabled: true
+        @onChangeQualityProfile()
+      else
+        @clear()
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/active-severities-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/active-severities-filter-view.coffee
new file mode 100644 (file)
index 0000000..5c07e23
--- /dev/null
@@ -0,0 +1,9 @@
+
+define [
+  'coding-rules-old/views/filters/profile-dependent-filter-view'
+], (
+  ProfileDependentFilterView
+) ->
+
+  class ActiveSeveritiesFilterView extends ProfileDependentFilterView
+    tooltip: 'coding_rules.filters.active_severity.inactive'
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/characteristic-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/characteristic-filter-view.coffee
new file mode 100644 (file)
index 0000000..efa29a7
--- /dev/null
@@ -0,0 +1,12 @@
+define [
+  'navigator/filters/choice-filters'
+], (
+  ChoiceFilters
+) ->
+
+  class CharacteriticFilterView extends ChoiceFilters.ChoiceFilterView
+
+    initialize: ->
+      super
+      @choices.comparator = 'text'
+      @choices.sort()
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/inheritance-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/inheritance-filter-view.coffee
new file mode 100644 (file)
index 0000000..0a20137
--- /dev/null
@@ -0,0 +1,23 @@
+define [
+  'coding-rules-old/views/filters/profile-dependent-filter-view'
+], (
+  ProfileDependentFilterView
+) ->
+
+  class InheritanceFilterView extends ProfileDependentFilterView
+    tooltip: 'coding_rules.filters.inheritance.inactive'
+
+    onChangeQualityProfile: ->
+      qualityProfileKey = @qualityProfileFilter.get 'value'
+      if _.isArray(qualityProfileKey) && qualityProfileKey.length == 1
+        qualityProfile = @options.app.getQualityProfileByKey qualityProfileKey[0]
+        if qualityProfile.parentKey
+          parentQualityProfile = @options.app.getQualityProfile qualityProfile.parentKey
+          if parentQualityProfile
+            @makeActive()
+          else
+            @makeInactive()
+        else
+          @makeInactive()
+      else
+        @makeInactive()
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/language-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/language-filter-view.coffee
new file mode 100644 (file)
index 0000000..3e5ea0a
--- /dev/null
@@ -0,0 +1,45 @@
+define [
+  'navigator/filters/choice-filters',
+  'templates/coding-rules-old'
+], (
+  ChoiceFilters,
+  Templates
+) ->
+
+  class LanguageFilterView extends ChoiceFilters.ChoiceFilterView
+
+    modelEvents:
+      'change:value': 'onChangeValue'
+      'change:enabled': 'focus',
+
+
+    initialize: ->
+      super
+      @choices.comparator = 'text'
+      @choices.sort()
+      @app = @model.get 'app'
+      @listenTo @app.qualityProfileFilter, 'change:value', @onChangeProfile
+      @selectedFromProfile = false
+
+    onChangeProfile: ->
+      profiles = @app.qualityProfileFilter.get 'value'
+      if _.isArray(profiles) && profiles.length > 0
+        profile = _.findWhere @app.qualityProfiles, key: profiles[0]
+        @options.filterBarView.moreCriteriaFilter.view.detailsView.enableByProperty(@detailsView.model.get 'property')
+        @choices.each (item) -> item.set 'checked', item.id == profile.lang
+        @refreshValues()
+        @selectedFromProfile = true
+      else if @selectedFromProfile
+        @choices.each (item) -> item.set 'checked', false
+        @refreshValues()
+
+    onChangeValue: ->
+      @selectedFromProfile = false
+      @renderBase()
+
+
+    refreshValues: ->
+      @detailsView.updateValue()
+      @detailsView.updateLists()
+      @render()
+      @hideDetails()
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/profile-dependent-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/profile-dependent-filter-view.coffee
new file mode 100644 (file)
index 0000000..5afad40
--- /dev/null
@@ -0,0 +1,57 @@
+define [
+  'navigator/filters/choice-filters'
+], (
+  ChoiceFilters
+) ->
+
+  class ProfileDependentFilterView extends ChoiceFilters.ChoiceFilterView
+    tooltip: 'coding_rules.filters.activation.help'
+
+    initialize: ->
+      super
+      @qualityProfileFilter = @model.get 'qualityProfileFilter'
+      @listenTo @qualityProfileFilter, 'change:value', @onChangeQualityProfile
+      @onChangeQualityProfile()
+
+
+    onChangeQualityProfile: ->
+      qualityProfileKey = @qualityProfileFilter.get 'value'
+      if _.isArray(qualityProfileKey) && qualityProfileKey.length == 1
+        @makeActive()
+      else
+        @makeInactive()
+
+
+    makeActive: ->
+      @model.set inactive: false, title: ''
+      @model.trigger 'change:enabled'
+      @$el.removeClass('navigator-filter-inactive').prop 'title', ''
+      @options.filterBarView.moreCriteriaFilter.view.detailsView.enableByProperty(@detailsView.model.get 'property')
+      @hideDetails()
+
+
+    makeInactive: ->
+      @model.set inactive: true, title: t @tooltip
+      @model.trigger 'change:enabled'
+      @choices.each (model) -> model.set 'checked', false
+      @detailsView.updateLists()
+      @detailsView.updateValue()
+      @$el.addClass('navigator-filter-inactive').prop 'title', t @tooltip
+
+
+    showDetails: ->
+      super unless @$el.is '.navigator-filter-inactive'
+
+
+    restore: (value) ->
+      value = value.split(',') if _.isString(value)
+      if @choices && value.length > 0
+        @model.set value: value, enabled: true
+        @choices.each (item) ->
+          item.set 'checked', false
+        _.each value, (v) =>
+          cModel = @choices.findWhere id: v
+          cModel.set 'checked', true
+        @onChangeQualityProfile()
+      else
+        @clear()
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/quality-profile-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/quality-profile-filter-view.coffee
new file mode 100644 (file)
index 0000000..3dde4d0
--- /dev/null
@@ -0,0 +1,61 @@
+define [
+  'navigator/filters/choice-filters',
+  'templates/coding-rules-old'
+], (
+  ChoiceFilters,
+  Templates
+) ->
+
+  class QualityProfileDetailFilterView extends ChoiceFilters.DetailsChoiceFilterView
+    itemTemplate: Templates['coding-rules-profile-filter-detail']
+
+
+  class QualityProfileFilterView extends ChoiceFilters.ChoiceFilterView
+
+    initialize: ->
+      super
+        detailsView: QualityProfileDetailFilterView
+
+      @app = @model.get 'app'
+
+      @allProfiles = @model.get 'choices'
+      @updateChoices @allProfiles
+
+      @listenTo @app.languageFilter, 'change:value', @onChangeLanguage
+      @onChangeLanguage()
+
+
+    onChangeLanguage: ->
+      languages = @app.languageFilter.get 'value'
+      if _.isArray(languages) && languages.length > 0
+        @filterLanguages(languages)
+      else
+        @updateChoices(@allProfiles)
+
+    filterLanguages: (languages) ->
+      languageProfiles = _.filter( @allProfiles, (prof) -> languages.indexOf(prof.lang) >= 0 )
+      @updateChoices(languageProfiles)
+
+
+    updateChoices: (collection) ->
+      languages = @app.languages
+      currentValue = @model.get('value')
+      @choices = new Backbone.Collection( _.map collection, (item, index) ->
+          new Backbone.Model
+            id: item.key
+            text: item.name
+            checked: false
+            index: index
+            language: languages[item.lang]
+        comparator: 'index'
+      )
+      if currentValue
+        @restore(currentValue)
+      @render()
+
+    render: ->
+      super
+      if @model.get 'value'
+        @$el.addClass('navigator-filter-context')
+      else
+        @$el.removeClass('navigator-filter-context')
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/query-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/query-filter-view.coffee
new file mode 100644 (file)
index 0000000..fa57264
--- /dev/null
@@ -0,0 +1,81 @@
+define [
+  'backbone',
+  'backbone.marionette',
+  'navigator/filters/base-filters',
+  'navigator/filters/string-filters',
+  'navigator/filters/choice-filters',
+  'templates/coding-rules-old',
+  'common/handlebars-extensions'
+], (
+  Backbone,
+  Marionette,
+  BaseFilters,
+  StringFilterView,
+  ChoiceFilters,
+  Templates
+) ->
+
+  class QueryFilterView extends StringFilterView
+    template: Templates['coding-rules-query-filter']
+    className: 'navigator-filter navigator-filter-query'
+
+    events:
+      'keypress input': 'checkSubmit'
+      'change input': 'change'
+      'click': 'focus'
+      'blur': 'blur'
+
+
+    change: (e) ->
+      @model.set 'value', $j(e.target).val()
+      @options.app.codingRules.sorting = sort: '', asc: ''
+
+
+    clear: ->
+      super
+      @focus()
+
+
+    focus: ->
+      @$(':input').focus();
+
+
+    blur: ->
+      @$(':input').blur();
+
+
+    serializeData: ->
+      return _.extend({}, @model.toJSON(),
+        value: this.model.get('value') || ''
+      )
+
+
+    initialize: ->
+      super detailsView: null
+      @model.set('size', 25) unless @model.get 'size'
+
+
+    checkSubmit: (e) ->
+      if (e.which == 13)
+        e.preventDefault()
+        @change(e)
+        @blur()
+        @options.app.filterBarView.$('.navigator-filter-submit').focus()
+        @options.app.filterBarView.$('.navigator-filter-submit').click()
+
+
+    renderInput: ->
+      # Done in template
+
+
+    toggleDetails: ->
+      # NOP
+
+
+    isDefaultValue: ->
+      true
+
+
+    renderBase: ->
+      super
+      @$el.prop('title', '');
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/repository-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/repository-filter-view.coffee
new file mode 100644 (file)
index 0000000..82dc8e6
--- /dev/null
@@ -0,0 +1,55 @@
+define [
+  'navigator/filters/choice-filters',
+  'templates/coding-rules-old'
+], (
+  ChoiceFilters,
+  Templates
+) ->
+
+  class RepositoryDetailFilterView extends ChoiceFilters.DetailsChoiceFilterView
+    itemTemplate: Templates['coding-rules-repository-detail']
+
+
+  class RepositoryFilterView extends ChoiceFilters.ChoiceFilterView
+
+    initialize: ->
+      super
+        detailsView: RepositoryDetailFilterView
+
+      @app = @model.get 'app'
+
+      @allRepositories = @model.get 'choices'
+      @updateChoices @allRepositories
+
+      @listenTo @app.languageFilter, 'change:value', @onChangeLanguage
+      @onChangeLanguage()
+
+
+    onChangeLanguage: ->
+      languages = @app.languageFilter.get 'value'
+      if _.isArray(languages) && languages.length > 0
+        @filterLanguages(languages)
+      else
+        @updateChoices(@allRepositories)
+
+    filterLanguages: (languages) ->
+      languageRepositories = _.filter( @allRepositories, (repo) -> languages.indexOf(repo.language) >= 0 )
+      @updateChoices(languageRepositories)
+
+
+    updateChoices: (collection) ->
+      languages = @app.languages
+      currentValue = @model.get('value')
+      @choices = new Backbone.Collection( _.map collection, (item, index) ->
+          new Backbone.Model
+            id: item.key
+            text: item.name
+            checked: false
+            index: index
+            language: languages[item.language]
+        comparator: (item) ->
+          [item.get('text'), item.get('language')]
+      )
+      if currentValue
+        @restore(currentValue)
+      @render()
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/tag-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/tag-filter-view.coffee
new file mode 100644 (file)
index 0000000..01366e7
--- /dev/null
@@ -0,0 +1,38 @@
+define [
+  'navigator/filters/choice-filters'
+], (
+  ChoiceFilters
+) ->
+
+  class TagFilterView extends ChoiceFilters.ChoiceFilterView
+
+    initialize: ->
+      super()
+      @loadTags()
+      # TODO Register an event handler to reload tags when they are modified on a rule
+
+
+    loadTags: ->
+      tagsXHR = jQuery.ajax
+        url: "#{baseUrl}/api/rules/tags"
+        async: false
+
+      jQuery.when(tagsXHR).done (r) =>
+        @choices = new Backbone.Collection(
+          _.map(r.tags, (tag) ->
+            new Backbone.Model
+              id: tag
+              text: tag
+          ),
+          comparator: 'text')
+
+        if @tagToRestore
+          @restore(@tagToRestore)
+          @tagToRestore = null
+        @render()
+
+    restore: (value) ->
+      unless @choices.isEmpty()
+        super(value)
+      else
+        @tagToRestore = value
diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/header-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/header-view.coffee
new file mode 100644 (file)
index 0000000..13a71b5
--- /dev/null
@@ -0,0 +1,28 @@
+define [
+  'backbone.marionette',
+  'templates/coding-rules-old'
+], (
+  Marionette,
+  Templates
+) ->
+
+  class CodingRulesHeaderView extends Marionette.ItemView
+    template: Templates['coding-rules-header']
+
+
+    events:
+      'click #coding-rules-new-search': 'newSearch'
+      'click #coding-rules-create-rule': 'createRule'
+
+
+    newSearch: ->
+      @options.app.router.emptyQuery()
+
+
+    createRule: ->
+      @options.app.createManualRule()
+
+
+    serializeData: ->
+      _.extend super,
+        'canWrite': @options.app.canWrite
diff --git a/server/sonar-web/src/main/coffee/coding-rules/app.coffee b/server/sonar-web/src/main/coffee/coding-rules/app.coffee
deleted file mode 100644 (file)
index 953c009..0000000
+++ /dev/null
@@ -1,521 +0,0 @@
-requirejs.config
-  baseUrl: "#{baseUrl}/js"
-
-  paths:
-    'backbone': 'third-party/backbone'
-    'backbone.marionette': 'third-party/backbone.marionette'
-    'handlebars': 'third-party/handlebars'
-
-  shim:
-    'backbone.marionette':
-      deps: ['backbone']
-      exports: 'Marionette'
-    'backbone':
-      exports: 'Backbone'
-    'handlebars':
-      exports: 'Handlebars'
-
-
-requirejs [
-  'backbone', 'backbone.marionette',
-
-  'coding-rules/layout',
-  'coding-rules/router',
-
-  # views
-  'coding-rules/views/header-view',
-  'coding-rules/views/actions-view',
-  'coding-rules/views/filter-bar-view',
-  'coding-rules/views/coding-rules-list-view',
-  'coding-rules/views/coding-rules-detail-view',
-  'coding-rules/views/coding-rules-bulk-change-view',
-  'coding-rules/views/coding-rules-quality-profile-activation-view',
-  'coding-rules/views/coding-rules-bulk-change-dropdown-view',
-  'coding-rules/views/coding-rules-facets-view',
-  'coding-rules/views/coding-rules-custom-rule-creation-view',
-  'coding-rules/views/coding-rules-manual-rule-creation-view',
-
-  # filters
-  'navigator/filters/base-filters',
-  'navigator/filters/choice-filters',
-  'navigator/filters/string-filters',
-  'navigator/filters/date-filter-view',
-  'navigator/filters/read-only-filters',
-  'coding-rules/views/filters/query-filter-view',
-  'coding-rules/views/filters/quality-profile-filter-view',
-  'coding-rules/views/filters/inheritance-filter-view',
-  'coding-rules/views/filters/active-severities-filter-view',
-  'coding-rules/views/filters/activation-filter-view',
-  'coding-rules/views/filters/characteristic-filter-view',
-  'coding-rules/views/filters/repository-filter-view',
-  'coding-rules/views/filters/tag-filter-view',
-  'coding-rules/views/filters/language-filter-view',
-
-  'common/handlebars-extensions'
-], (
-  Backbone, Marionette,
-
-  CodingRulesLayout,
-  CodingRulesRouter,
-
-  # views
-  CodingRulesHeaderView,
-  CodingRulesActionsView,
-  CodingRulesFilterBarView,
-  CodingRulesListView,
-  CodingRulesDetailView,
-  CodingRulesBulkChangeView,
-  CodingRulesQualityProfileActivationView,
-  CodingRulesBulkChangeDropdownView,
-  CodingRulesFacetsView,
-  CodingRulesCustomRuleCreationView,
-  CodingRulesManualRuleCreationView,
-
-  # filters
-  BaseFilters,
-  ChoiceFilters,
-  StringFilterView,
-  DateFilterView,
-  ReadOnlyFilterView,
-  QueryFilterView,
-  QualityProfileFilterView,
-  InheritanceFilterView,
-  ActiveSeveritiesFilterView,
-  ActivationFilterView,
-  CharacteristicFilterView,
-  RepositoryFilterView,
-  TagFilterView,
-  LanguageFilterView
-) ->
-
-  # 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 '. '
-      else
-        text = t 'default_error_message'
-      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 = (params) ->
-    sort = _.findWhere(params, key: 'sort')
-    asc = _.findWhere(params, key: 'asc')
-
-    if (sort && asc)
-      @codingRules.sorting =
-        sort: sort.value
-        asc: asc.value =='true'
-
-
-  App.restoreDefaultSorting = ->
-    params = []
-    params.push(key: 'sort', value: 'createdAt')
-    params.push(key: 'asc', value: false)
-    @restoreSorting params
-
-
-  App.storeQuery = (query, sorting) ->
-    if sorting && sorting.sort
-      _.extend query,
-        s: 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 { p: @pageIndex, ps: 25, facets: firstPage }, query
-
-    if @codingRules.sorting && @codingRules.sorting.sort
-      _.extend fetchQuery,
-          s: @codingRules.sorting.sort,
-          asc: @codingRules.sorting.asc
-
-    @storeQuery query, @codingRules.sorting
-
-    # Optimize requested fields
-    _.extend fetchQuery, f: 'name,lang,status,tags,sysTags'
-
-    if @codingRulesListView
-      scrollOffset = jQuery('.navigator-results')[0].scrollTop
-    else
-      scrollOffset = 0
-
-    @layout.showSpinner 'resultsRegion'
-    @layout.showSpinner 'facetsRegion' if firstPage
-
-
-    jQuery.ajax
-      url: "#{baseUrl}/api/rules/search"
-      data: fetchQuery
-    .done (r) =>
-      _.map(r.rules, (rule) ->
-        rule.language = App.languages[rule.lang]
-      )
-
-      @codingRules.paging =
-        total: r.total
-        pageIndex: r.p
-        pageSize: r.ps
-        pages: 1 + (r.total / r.ps)
-
-      if @codingRulesListView
-        @codingRulesListView.close()
-
-      if firstPage
-        @codingRules.reset r.rules
-        @codingRulesListView = new CodingRulesListView
-          app: @
-          collection: @codingRules
-      else
-        @codingRulesListView.unbindEvents()
-        @codingRules.add r.rules
-
-      @layout.resultsRegion.show @codingRulesListView
-
-
-      if @codingRules.isEmpty()
-        @layout.detailsRegion.reset()
-      else if firstPage
-        @codingRulesListView.selectFirst()
-      else
-        @codingRulesListView.selectCurrent()
-
-      if firstPage
-        @codingRulesFacetsView = new CodingRulesFacetsView
-          app: @
-          collection: new Backbone.Collection r.facets, comparator: 'property'
-        @layout.facetsRegion.show @codingRulesFacetsView
-        @filterBarView.restoreFromWsQuery query
-        @codingRulesFacetsView.restoreFromQuery query
-      else
-        jQuery('.navigator-results')[0].scrollTop = scrollOffset
-
-      @layout.onResize()
-
-
-
-  App.facetLabel = (property, value) ->
-    return value unless App.facetPropertyToLabels[property]
-    App.facetPropertyToLabels[property](value)
-
-
-  App.fetchFirstPage = ->
-    @pageIndex = 1
-    App.fetchList true
-
-
-  App.fetchNextPage = ->
-    if @pageIndex < @codingRules.paging.pages
-      @pageIndex++
-      App.fetchList false
-
-
-  App.getQualityProfile = ->
-    value = @qualityProfileFilter.get('value')
-    if value? && value.length == 1 then value[0] else null
-
-
-  App.getQualityProfilesForLanguage = (language_key) ->
-    _.filter App.qualityProfiles, (p) => p.lang == language_key
-
-  App.getQualityProfileByKey = (profile_key) ->
-    _.findWhere App.qualityProfiles, key: profile_key
-
-
-  App.getSubcharacteristicName = (name) ->
-    (App.characteristics[name] || '').replace ': ', ' > '
-
-
-  App.showRule = (ruleKey) ->
-    App.layout.showSpinner 'detailsRegion'
-    jQuery.ajax
-      url: "#{baseUrl}/api/rules/show"
-      data:
-        key: ruleKey
-        actives: true
-    .done (r) =>
-      rule = new Backbone.Model(r.rule)
-      App.codingRulesQualityProfileActivationView.rule = rule
-      App.detailView = new CodingRulesDetailView
-        app: App
-        model: rule
-        actives: r.actives
-      App.layout.detailsRegion.show App.detailView
-
-
-  App.manualRepository = ->
-    key: 'manual'
-    name: 'Manual Rules'
-    language: 'none'
-
-
-  App.createManualRule = ->
-    App.codingRulesManualRuleCreationView.model = new Backbone.Model()
-    App.codingRulesManualRuleCreationView.show()
-
-
-  # Construct layout
-  App.addInitializer ->
-    @layout = new CodingRulesLayout app: @
-    jQuery('#content').append @layout.render().el
-    @layout.onResize()
-
-
-  # Construct header
-  App.addInitializer ->
-    @codingRulesHeaderView = new CodingRulesHeaderView app: @
-    @layout.headerRegion.show @codingRulesHeaderView
-
-
-  # Define coding rules
-  App.addInitializer ->
-    @codingRules = new Backbone.Collection
-    @restoreDefaultSorting()
-
-
-  # Construct status bar
-  App.addInitializer ->
-    @codingRulesActionsView = new CodingRulesActionsView
-      app: @
-      collection: @codingRules
-    @layout.actionsRegion.show @codingRulesActionsView
-
-
-  # Construct bulk change views
-  App.addInitializer ->
-    @codingRulesBulkChangeView = new CodingRulesBulkChangeView app: @
-    @codingRulesBulkChangeDropdownView = new CodingRulesBulkChangeDropdownView app: @
-
-
-  # Construct quality profile activation view
-  App.addInitializer ->
-    @codingRulesQualityProfileActivationView = new CodingRulesQualityProfileActivationView app: @
-
-
-  # Construct custom rule creation view
-  App.addInitializer ->
-    @codingRulesCustomRuleCreationView = new CodingRulesCustomRuleCreationView app: @
-
-
-  # Construct custom rule creation view
-  App.addInitializer ->
-    @codingRulesManualRuleCreationView = new CodingRulesManualRuleCreationView app: @
-
-  # Define filters
-  App.addInitializer ->
-    @filters = new BaseFilters.Filters
-
-    @queryFilter = new BaseFilters.Filter
-      property: 'q'
-      type: QueryFilterView
-      size: 50
-    @filters.add @queryFilter
-
-    @filters.add new BaseFilters.Filter
-      name: t 'coding_rules.filters.severity'
-      property: 'severities'
-      type: ChoiceFilters.ChoiceFilterView
-      optional: true
-      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.tag'
-      property: 'tags'
-      type: TagFilterView
-      optional: true
-
-    @filters.add new BaseFilters.Filter
-      name: t 'coding_rules.filters.characteristic'
-      property: 'debt_characteristics'
-      type: CharacteristicFilterView
-      choices: @characteristics
-      multiple: false
-      optional: true
-
-    @qualityProfileFilter = new BaseFilters.Filter
-      name: t 'coding_rules.filters.quality_profile'
-      property: 'qprofile'
-      type: QualityProfileFilterView
-      app: @
-      choices: @qualityProfiles
-      multiple: false
-    @filters.add @qualityProfileFilter
-
-    @activationFilter = new BaseFilters.Filter
-      name: t 'coding_rules.filters.activation'
-      property: 'activation'
-      type: ActivationFilterView
-      enabled: false
-      optional: true
-      multiple: false
-      qualityProfileFilter: @qualityProfileFilter
-      choices:
-        true: t 'coding_rules.filters.activation.active'
-        false: t 'coding_rules.filters.activation.inactive'
-    @filters.add @activationFilter
-
-    @filters.add new BaseFilters.Filter
-      name: t 'coding_rules.filters.active_severity'
-      property: 'active_severities'
-      type: ActiveSeveritiesFilterView
-      enabled: false
-      optional: true
-      qualityProfileFilter: @qualityProfileFilter
-      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'
-
-    @languageFilter =  new BaseFilters.Filter
-      name: t 'coding_rules.filters.language'
-      property: 'languages'
-      type: LanguageFilterView
-      app: @
-      choices: @languages
-      optional: true
-    @filters.add @languageFilter
-
-    @filters.add new BaseFilters.Filter
-      name: t 'coding_rules.filters.availableSince'
-      property: 'available_since'
-      type: DateFilterView
-      enabled: false
-      optional: true
-
-    @filters.add new BaseFilters.Filter
-      name: t 'coding_rules.filters.inheritance'
-      property: 'inheritance'
-      type: InheritanceFilterView
-      enabled: false
-      optional: true
-      multiple: false
-      qualityProfileFilter: @qualityProfileFilter
-      choices:
-        'NONE': t 'coding_rules.filters.inheritance.not_inherited'
-        'INHERITED': t 'coding_rules.filters.inheritance.inherited'
-        'OVERRIDES': t 'coding_rules.filters.inheritance.overriden'
-
-    @filters.add new BaseFilters.Filter
-      name: t 'coding_rules.filters.repository'
-      property: 'repositories'
-      type: RepositoryFilterView
-      enabled: false
-      optional: true
-      app: @
-      choices: @repositories
-
-    @filters.add new BaseFilters.Filter
-      name: t 'coding_rules.filters.status'
-      property: 'statuses'
-      type: ChoiceFilters.ChoiceFilterView
-      enabled: false
-      optional: true
-      choices: @statuses
-
-    @filters.add new BaseFilters.Filter
-      name: t 'coding_rules.filters.template'
-      property: 'is_template'
-      type: ChoiceFilters.ChoiceFilterView
-      optional: true
-      multiple: false
-      choices:
-        'true': t 'coding_rules.filters.template.is_template'
-        'false': t 'coding_rules.filters.template.is_not_template'
-
-    @filters.add new BaseFilters.Filter
-      name: t 'coding_rules.filters.key'
-      property: 'rule_key'
-      type: ReadOnlyFilterView
-      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/rules/app"
-  .done (r) ->
-    App.appState = new Backbone.Model
-    App.state = new Backbone.Model
-    App.canWrite = r.canWrite
-    App.qualityProfiles = _.sortBy r.qualityprofiles, ['name', 'lang']
-    App.languages = _.extend r.languages, none: 'None'
-    _.map App.qualityProfiles, (profile) ->
-      profile.language = App.languages[profile.lang]
-    App.repositories = r.repositories
-    App.repositories.push App.manualRepository()
-    App.statuses = r.statuses
-    App.characteristics = r.characteristics
-
-    App.facetPropertyToLabels =
-      'languages': (value) -> App.languages[value]
-      'repositories': (value) ->
-        repo = _.findWhere(App.repositories, key: value)
-        other_repo_with_same_name = _.find(App.repositories, (repos) -> repos.name == repo.name && repos.key != repo.key)
-        if other_repo_with_same_name
-          App.languages[repo.language] + ' ' + repo.name
-        else
-          repo.name
-
-  # Message bundles
-  l10nXHR = window.requestMessages()
-
-  jQuery.when(l10nXHR, appXHR).done ->
-      # Remove the initial spinner
-      jQuery('#coding-rules-page-loader').remove()
-
-      # Start the application
-      App.start()
diff --git a/server/sonar-web/src/main/coffee/coding-rules/layout.coffee b/server/sonar-web/src/main/coffee/coding-rules/layout.coffee
deleted file mode 100644 (file)
index 8008248..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-define [
-  'backbone.marionette',
-  'templates/coding-rules'
-], (
-  Marionette,
-  Templates
-) ->
-
-  class AppLayout extends Marionette.Layout
-    className: 'navigator coding-rules-navigator'
-    template: Templates['coding-rules-layout']
-    storageKey: 'codingRulesResultsWidth'
-
-
-    regions:
-      headerRegion: '.navigator-header'
-      actionsRegion: '.navigator-actions'
-      resultsRegion: '.navigator-results'
-      detailsRegion: '.navigator-details'
-      filtersRegion: '.navigator-filters'
-      facetsRegion: '.navigator-facets'
-
-
-    ui:
-      side: '.navigator-side'
-      results: '.navigator-results'
-      details: '.navigator-details'
-      resizer: '.navigator-resizer'
-
-
-    initialize: ->
-      jQuery(window).on 'resize', => @onResize()
-
-      @isResize = false
-      jQuery('body').on 'mousemove', (e) => @processResize(e)
-      jQuery('body').on 'mouseup', => @stopResize()
-
-
-    onRender: ->
-      @ui.resizer.on 'mousedown', (e) => @startResize(e)
-
-      resultsWidth = localStorage.getItem @storageKey
-      if resultsWidth
-        @$(@resultsRegion.el).width +resultsWidth
-        @ui.side.width +resultsWidth + 20
-
-
-    onResize: ->
-      footerEl = jQuery('#footer')
-      footerHeight = footerEl.outerHeight true
-
-      resultsEl = @ui.results
-      resultsHeight = jQuery(window).height() - resultsEl.offset().top -
-        parseInt(resultsEl.css('margin-bottom'), 10) - footerHeight
-      resultsEl.height resultsHeight
-
-      detailsEl = @ui.details
-      detailsWidth = jQuery(window).width() - detailsEl.offset().left -
-        parseInt(detailsEl.css('margin-right'), 10)
-      detailsHeight = jQuery(window).height() - detailsEl.offset().top -
-        parseInt(detailsEl.css('margin-bottom'), 10) - footerHeight
-      detailsEl.width(detailsWidth).height detailsHeight
-
-
-    showSpinner: (region) ->
-      @[region].show new Marionette.ItemView
-        template: _.template('<i class="spinner"></i>')
-
-
-    startResize: (e) ->
-      @isResize = true
-      @originalWidth = @ui.results.width()
-      @x = e.clientX
-      jQuery('html').attr('unselectable', 'on').css('user-select', 'none').on('selectstart', false)
-
-
-    processResize: (e) ->
-      if @isResize
-        delta = e.clientX - @x
-        @$(@resultsRegion.el).width @originalWidth + delta
-        @ui.side.width @originalWidth + 20 + delta
-        localStorage.setItem @storageKey, @ui.results.width()
-        @onResize()
-
-
-    stopResize: ->
-      if @isResize
-        jQuery('html').attr('unselectable', 'off').css('user-select', 'text').off('selectstart')
-      @isResize = false
-      true
diff --git a/server/sonar-web/src/main/coffee/coding-rules/mockjax.coffee b/server/sonar-web/src/main/coffee/coding-rules/mockjax.coffee
deleted file mode 100644 (file)
index 30f37ba..0000000
+++ /dev/null
@@ -1,364 +0,0 @@
-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
-      qualityprofiles: [
-        { key: 'sonarway', name: 'Sonar Way', lang: 'Java', parent: null },
-        { key: 'qualityprofile1', name: 'Quality Profile 1', lang: 'Java', parent: 'sonarway' },
-        { key: 'qualityprofile2', name: 'Quality Profile 2', lang: 'JavaScript', parent: 'sonarway' },
-        { key: 'qualityprofile3', name: 'Quality Profile 3', lang: 'Java', parent: null },
-      ]
-      languages:
-        java: 'Java'
-        javascript: 'JavaScript'
-      repositories:
-        'checkstyle': 'Checkstyle'
-        'common-java': 'Common SonarQube'
-        'findbugs': 'FindBugs'
-        'pmd': 'PMD'
-        'pmd-unit-tests': 'PMD Unit Tests'
-        'squid': 'SonarQube'
-      statuses:
-        'BETA': 'Beta'
-        'DEPRECATED': 'Deprecated'
-        'READY': 'Ready'
-      tags:
-        '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'
-      characteristics:
-        '1469': 'Changeability'
-        '1441': 'Changeability: Architecture related changeability'
-        '1470': 'Changeability: Data related changeability'
-        '1475': 'Changeability: Logic related changeability'
-        '1392': 'Efficiency'
-        '1377': 'Efficiency: Memory use'
-        '2965': 'Efficiency: Network use'
-        '1393': 'Efficiency: Processor use'
-        '1154': 'Maintainability'
-        '1022': 'Maintainability: Readability'
-        '1155': 'Maintainability: Understandability'
-        '988': 'Portability'
-        '977': 'Portability: Compiler related portability'
-        '989': 'Portability: Hardware related portability'
-        '994': 'Portability: Language related portability'
-        '1000': 'Portability: OS related portability'
-        '1006': 'Portability: Software related portability'
-        '1021': 'Portability: Time zone related portability'
-        '1551': 'Reliability'
-        '1496': 'Reliability: Architecture related reliability'
-        '1552': 'Reliability: Data related reliability'
-        '1596': 'Reliability: Exception handling'
-        '1622': 'Reliability: Fault tolerance'
-        '1629': 'Reliability: Instruction related reliability'
-        '1759': 'Reliability: Logic related reliability'
-        '2948': 'Reliability: Resource'
-        '1874': 'Reliability: Synchronization related reliability'
-        '1925': 'Reliability: Unit tests'
-        '975': 'Reusability'
-        '974': 'Reusability: Modularity'
-        '976': 'Reusability: Transportability'
-        '1345': 'Security'
-        '1335': 'Security: API abuse'
-        '1346': 'Security: Errors'
-        '1349': 'Security: Input validation and representation'
-        '1364': 'Security: Security features'
-        '1933': 'Testability'
-        '1932': 'Testability: Integration level testability'
-        '1934': 'Testability: Unit level testability'
-      messages:
-        'all': 'All'
-        'any': 'Any'
-        'apply': 'Apply'
-        'are_you_sure': 'Are you sure?'
-        'bold': 'Bold'
-        'bulk_change': 'Bulk Change'
-        'bulleted_point': 'Bulleted point'
-        'cancel': 'Cancel'
-        'change': 'Change'
-        'code': 'Code'
-        'delete': 'Delete'
-        'done': 'Done'
-        'edit': 'Edit'
-        'markdown.helplink': 'Markdown Help'
-        'moreCriteria': '+ More Criteria'
-        'save': 'Save'
-        'search_verb': 'Search'
-        'severity': 'Severity'
-        'update': 'Update'
-
-        'severity.BLOCKER': 'Blocker'
-        'severity.CRITICAL': 'Critical'
-        'severity.MAJOR': 'Major'
-        'severity.MINOR': 'Minor'
-        'severity.INFO': 'Info'
-
-        'coding_rules.activate': 'Activate'
-        'coding_rules.activate_in': 'Activate In'
-        'coding_rules.activate_in_quality_profile': 'Activate In Quality Profile'
-        'coding_rules.activate_in_all_quality_profiles': 'Activate In All {0} Profiles'
-        'coding_rules.add_note': 'Add Note'
-        'coding_rules.available_since': 'Available Since'
-        'coding_rules.bulk_change': 'Bulk Change'
-        'coding_rules.change_severity': 'Change Severity'
-        'coding_rules.change_severity_in': 'Change Severity In'
-        'coding_rules.change_details': 'Change Details of Quality Profile'
-        'coding_rules.extend_description': 'Extend Description'
-        'coding_rules.deactivate_in': 'Deactivate In'
-        'coding_rules.deactivate': 'Deactivate'
-        'coding_rules.deactivate_in_quality_profile': 'Deactivate In Quality Profile'
-        'coding_rules.deactivate_in_all_quality_profiles': 'Deactivate In All {0} Profiles'
-        'coding_rules.found': 'Found'
-        'coding_rules.inherits': '"{0}" inherits "{1}"'
-        'coding_rules.key': 'Key:'
-        'coding_rules.new_search': 'New Search'
-        'coding_rules.no_results': 'No Coding Rules'
-        'coding_rules.no_tags': 'No tags'
-        'coding_rules.order': 'Order'
-        'coding_rules.ordered_by': 'Ordered By'
-        'coding_rules.original': 'Original:'
-        'coding_rules.page': 'Coding Rules'
-        'coding_rules.parameters': 'Parameters'
-        'coding_rules.parameters.default_value': 'Default Value:'
-        'coding_rules.permalink': 'Permalink'
-        'coding_rules.quality_profiles': 'Quality Profiles'
-        'coding_rules.quality_profile': 'Quality Profile'
-        'coding_rules.repository': 'Repository:'
-        'coding_rules.revert_to_parent_definition': 'Revert to Parent Definition'
-        'coding_rules._rules': 'rules'
-        'coding_rules.select_tag': 'Select Tag'
-
-        'coding_rules.filters.activation': 'Activation'
-        'coding_rules.filters.activation.active': 'Active'
-        'coding_rules.filters.activation.inactive': 'Inactive'
-        'coding_rules.filters.activation.help': 'Activation criterion is available when a quality profile is selected'
-        'coding_rules.filters.availableSince': 'Available Since'
-        'coding_rules.filters.characteristic': 'Characteristic'
-        'coding_rules.filters.description': 'Description'
-        'coding_rules.filters.quality_profile': 'Quality Profile'
-        'coding_rules.filters.inheritance': 'Inheritance'
-        'coding_rules.filters.inheritance.inactive': 'Inheritance criterion is available when an inherited quality profile is selected'
-        'coding_rules.filters.inheritance.not_inherited': 'Not Inherited'
-        'coding_rules.filters.inheritance.inherited': 'Inherited'
-        'coding_rules.filters.inheritance.overriden': 'Overriden'
-        'coding_rules.filters.key': 'Key'
-        'coding_rules.filters.language': 'Language'
-        'coding_rules.filters.name': 'Name'
-        'coding_rules.filters.repository': 'Repository'
-        'coding_rules.filters.severity': 'Severity'
-        'coding_rules.filters.status': 'Status'
-        'coding_rules.filters.tag': 'Tag'
-
-        'coding_rules.sort.creation_date': 'Creation Date'
-        'coding_rules.sort.name': 'Name'
-
-
-  # 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'
-          severity: 'MAJOR'
-          status: 'DEPRECATED'
-        },
-        {
-          name: 'Avoid Array Loops'
-          language: 'Java'
-          severity: 'CRITICAL'
-          status: 'READY'
-        },
-        {
-          name: 'Bad practice - Abstract class defines covariant compareTo() method'
-          language: 'Java'
-          severity: 'MAJOR'
-          status: 'READY'
-        },
-        {
-          name: 'Correctness - Use of class without a hashCode() method in a hashed data structure'
-          language: 'Java'
-          severity: 'MINOR'
-          status: 'BETA'
-        },
-        {
-          name: 'Useless Operation On Immutable'
-          language: 'Java'
-          severity: 'MAJOR'
-          status: 'READY'
-        }
-      ]
-      paging:
-        total: 5
-        fTotal: '5'
-      facets: [
-        {
-          name: 'Languages'
-          property: 'languages'
-          values: [
-            { key: 'java', text: 'Java', stat: 45 }
-            { key: 'javascript', text: 'JavaScript', stat: 21 }
-          ]
-        }
-        {
-          name: 'Tags'
-          property: 'tags'
-          values: [
-            { key: 'brain-overload', text: 'brain-overload', stat: 8 }
-            { key: 'bug', text: 'bug', stat: 7 }
-            { key: 'comment', text: 'comment', stat: 7 }
-            { key: 'convention', text: 'convention', stat: 6 }
-            { key: 'error-handling', text: 'error-handling', stat: 5 }
-          ]
-        }
-        {
-          name: 'Repositories'
-          property: 'repositories'
-          values: [
-            { key: 'squid', text: 'SonarQube', stat: 57 }
-            { key: 'pmd', text: 'PMD', stat: 17 }
-          ]
-        }
-      ]
-
-
-
-
-  # 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'
-        creationDate: '2013-10-15'
-        fCreationDate: 'Oct 15, 2013'
-        status: 'DEPRECATED'
-        repositoryName: 'SonarQube'
-        repositoryKey: 'squid'
-        characteristic: 'Reliability'
-        subcharacteristic: 'Data related reliability'
-        key: 'S1190'
-        parameters: [
-          { key: 'someParameter', type: 'INT', default: 4, description: 'Some parameter description' }
-          { key: 'xpath', type: 'TEXT', description: 'XPath, the XML Path Language, is a query language for selecting nodes from an XML document. In addition, XPath may be used to compute values (e.g., strings, numbers, or Boolean values) from the content of an XML document. XPath was defined by the World Wide Web Consortium (W3C).' }
-        ]
-        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>'''
-        extra: '''This note is here <b>only for test purposes</b>.'''
-        extraRaw: '''This note is here *only for test purposes*.'''
-
-        qualityProfiles: [
-          {
-            name: 'SonarWay'
-            key: 'sonarway'
-            severity: 'MINOR'
-            parameters: [
-              { key: 'someParameter', value: 8 }
-              { key: 'xpath', value: '/child::html/child::body/child::*/child::span[attribute::class]' }
-            ]
-          },
-          {
-            name: 'Quality Profile 1'
-            key: 'qualityprofile1'
-            severity: 'MAJOR'
-            parameters: [
-              { key: 'someParameter', value: 6 }
-              { key: 'xpath', value: '/html/body/*/span[@class]' }
-            ]
-            inherits: 'sonarway'
-          }
-        ]
-
-
-
-  # POST /api/codingrules/extend_description
-  jQuery.mockjax
-    url: "#{baseUrl}/api/codingrules/extend_description"
-    responseText: JSON.stringify
-      extra: '''This note is here <i>only for test purposes</i>.'''
-      extraRaw: '''This note is here *only for test purposes*.'''
-
-
-  # POST /api/codingrules/bulk_change
-  jQuery.mockjax
-    url: "#{baseUrl}/api/codingrules/bulk_change"
-
-
-  # POST /api/codingrules/set_tags
-  jQuery.mockjax
-    url: "#{baseUrl}/api/codingrules/set_tags"
-
-
-  # POST /api/codingrules/activate
-  jQuery.mockjax
-    url: "#{baseUrl}/api/codingrules/activate"
-
-
-  # POST /api/codingrules/note
-  jQuery.mockjax
-    url: "#{baseUrl}/api/codingrules/note"
-    responseText: JSON.stringify
-      note:
-        username: 'Admin Admin'
-        html: '''<p>This note is here <b>only for test purposes</b>.</p>'''
-        raw: '''This note is here *only for test purposes*.'''
-        fCreationDate: 'less than a minute'
-
-
-  # GET /api/qualityprofiles/list
-  jQuery.mockjax
-    url: "#{baseUrl}/api/qualityprofiles/list"
-    responseText: JSON.stringify
-      more: false
-      results: [
-        { id: 'sonarway', text: 'Sonar Way', category: 'Java', parent: null },
-        { id: 'qp1', text: 'Quality Profile 1', category: 'Java', parent: 'sonarway' },
-        { id: 'qp2', text: 'Quality Profile 2', category: 'JavaScript', parent: 'sonarway' },
-        { id: 'qp3', text: 'Quality Profile 3', category: 'Java', parent: null },
-      ]
-
-
-  # GET /api/qualityprofiles/show
-  jQuery.mockjax
-    url: "#{baseUrl}/api/qualityprofiles/show"
-    responseText: JSON.stringify
-      qualityprofile:
-        id: 'sonarway', text: 'Sonar Way', category: 'Java', parent: null
-
diff --git a/server/sonar-web/src/main/coffee/coding-rules/router.coffee b/server/sonar-web/src/main/coffee/coding-rules/router.coffee
deleted file mode 100644 (file)
index fe49b73..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-define [
-  'backbone',
-], (
-  Backbone,
-) ->
-
-  class AppRouter extends Backbone.Router
-
-    routes:
-      '': 'emptyQuery'
-      ':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: ->
-      @app.restoreDefaultSorting()
-      @index('')
-
-
-    index: (query) ->
-      params = this.parseQuery(query)
-      @loadResults(params)
-
-
-    loadResults: (params) ->
-      @app.filterBarView.restoreFromQuery(params)
-      if @app.codingRulesFacetsView
-        @app.codingRulesFacetsView.restoreFromQuery(params)
-      @app.restoreSorting(params)
-      @app.fetchFirstPage()
diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/actions-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/actions-view.coffee
deleted file mode 100644 (file)
index b5f1355..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-define [
-  'backbone.marionette'
-  'templates/coding-rules'
-], (
-  Marionette
-  Templates
-) ->
-
-  class CodingRulesStatusView extends Marionette.ItemView
-    template: Templates['coding-rules-actions']
-
-
-    collectionEvents:
-      'all': 'render'
-
-
-    ui:
-      orderChoices: '.navigator-actions-order-choices'
-      bulkChange: '.navigator-actions-bulk'
-
-
-    events:
-      'click .navigator-actions-order': 'toggleOrderChoices'
-      'click @ui.orderChoices': 'sort'
-      'click @ui.bulkChange': 'bulkChange'
-
-
-    onRender: ->
-      unless @collection.sorting.sortText
-        while not @collection.sorting.sortText
-          @collection.sorting.sortText = @$('[data-sort=' + @collection.sorting.sort + ']:first').text()
-        @render()
-
-
-    toggleOrderChoices: (e) ->
-      e.stopPropagation()
-      @ui.orderChoices.toggleClass 'open'
-      if @ui.orderChoices.is '.open'
-        jQuery('body').on 'click.coding_rules_actions', =>
-          @ui.orderChoices.removeClass 'open'
-
-
-    sort: (e) ->
-      e.stopPropagation()
-      @ui.orderChoices.removeClass 'open'
-      jQuery('body').off 'click.coding_rules_actions'
-      el = jQuery(e.target)
-      sort = el.data 'sort'
-      asc = el.data 'asc'
-      if sort != null && asc != null
-        @collection.sorting = sort: sort, sortText: el.text(), asc: asc
-        @options.app.fetchFirstPage()
-
-
-    bulkChange: (e) ->
-      e.stopPropagation()
-      @options.app.codingRulesBulkChangeDropdownView.toggle()
-
-
-    serializeData: ->
-      _.extend super,
-        canWrite: @options.app.canWrite
-        paging: @collection.paging
-        sorting: @collection.sorting
diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-bulk-change-dropdown-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-bulk-change-dropdown-view.coffee
deleted file mode 100644 (file)
index 2755217..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-define [
-  'backbone.marionette',
-  'templates/coding-rules'
-], (
-  Marionette,
-  Templates
-) ->
-
-  class CodingRulesBulkChangeDropdownView extends Marionette.ItemView
-    className: 'coding-rules-bulk-change-dropdown'
-    template: Templates['coding-rules-bulk-change-dropdown']
-
-
-    events:
-      'click .coding-rules-bulk-change-dropdown-link': 'doAction'
-
-
-    doAction: (e) ->
-      action = jQuery(e.currentTarget).data 'action'
-      param = jQuery(e.currentTarget).data 'param'
-      @options.app.codingRulesBulkChangeView.show action, param
-
-
-    onRender: ->
-      jQuery('body').append @el
-      jQuery('body').off('click.bulk-change').on 'click.bulk-change', => @hide()
-      @$el.css
-        top: jQuery('.navigator-actions').offset().top + jQuery('.navigator-actions').height() + 1
-        left: jQuery('.navigator-actions').offset().left + jQuery('.navigator-actions').outerWidth() - @$el.outerWidth()
-
-
-    toggle: ->
-      if @$el.is(':visible') then @hide() else @show()
-
-
-    show: ->
-      @render()
-      @$el.show()
-
-
-    hide: ->
-      @$el.hide()
-
-
-    serializeData: ->
-      languages = @options.app.languageFilter.get('value')
-      activationValues = @options.app.activationFilter.get('value') or []
-      qualityProfile = @options.app.getQualityProfile()
-
-      qualityProfile: qualityProfile
-      qualityProfileName: @options.app.qualityProfileFilter.view.renderValue()
-      singleLanguage: _.isArray(languages) and languages.length == 1
-      language: @options.app.languageFilter.view.renderValue()
-      allowActivateOnProfile: qualityProfile and (activationValues.length == 0 or activationValues[0] == 'false')
-      allowDeactivateOnProfile: qualityProfile and (activationValues.length == 0 or activationValues[0] == 'true')
diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-bulk-change-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-bulk-change-view.coffee
deleted file mode 100644 (file)
index 299d802..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-define [
-  'backbone.marionette',
-  'templates/coding-rules'
-], (
-  Marionette,
-  Templates
-) ->
-
-  class CodingRulesBulkChangeView extends Marionette.ItemView
-    template: Templates['coding-rules-bulk-change']
-
-    ui:
-      modalFooter: '.modal-foot'
-      modalError: '.modal-error'
-      modalWarning: '.modal-warning'
-      modalNotice: '.modal-notice'
-      modalField: '.modal-field'
-      codingRulesSubmitBulkChange: '#coding-rules-submit-bulk-change'
-      codingRulesCancelBulkChange: '#coding-rules-cancel-bulk-change'
-      codingRulesCloseBulkChange: '#coding-rules-close-bulk-change'
-
-    events:
-      'submit form': 'onSubmit'
-      'click @ui.codingRulesCancelBulkChange': 'hide'
-      'click @ui.codingRulesCloseBulkChange': 'close'
-      'change select': 'enableAction'
-
-
-    onRender: ->
-      @$el.dialog
-        dialogClass: 'no-close',
-        width: '600px',
-        draggable: false,
-        autoOpen: false,
-        modal: true,
-        minHeight: 50,
-        resizable: false,
-        title: null
-
-      @$('#coding-rules-bulk-change-profile').select2
-        width: '250px'
-        minimumResultsForSearch: 1
-
-    show: (action, param = null) ->
-      @action = action
-      @profile = param
-      @render()
-      @$el.dialog 'open'
-
-
-    hide: ->
-      @$el.dialog 'close'
-
-
-    close: ->
-      @options.app.fetchFirstPage()
-      @hide()
-      false
-
-
-    prepareQuery: ->
-      _.extend @options.app.getQuery(),
-        wsAction: @action
-        profile_key: @$('#coding-rules-bulk-change-profile').val() or @profile
-
-
-    bulkChange: (query) ->
-      wsAction = query.wsAction
-      query = _.omit(query, 'wsAction')
-
-      @ui.modalError.hide()
-      @ui.modalWarning.hide()
-      @ui.modalNotice.hide()
-
-      origFooter = @ui.modalFooter.html()
-      @ui.modalFooter.html '<i class="spinner"></i>'
-
-      jQuery.ajax
-        type: 'POST'
-        url: "#{baseUrl}/api/qualityprofiles/#{wsAction}_rules"
-        data: query
-      .done (r) =>
-        @ui.modalField.hide()
-        if (r.failed)
-          @ui.modalWarning.show()
-          @ui.modalWarning.html tp('coding_rules.bulk_change.warning', r.succeeded, r.failed)
-        else
-          @ui.modalNotice.show()
-          @ui.modalNotice.html tp('coding_rules.bulk_change.success', r.succeeded)
-
-        @ui.modalFooter.html origFooter
-        @$(@ui.codingRulesSubmitBulkChange.selector).hide()
-        @$(@ui.codingRulesCancelBulkChange.selector).hide()
-        @$(@ui.codingRulesCloseBulkChange.selector).show()
-        @$(@ui.codingRulesCloseBulkChange.selector).focus()
-      .fail =>
-        @ui.modalFooter.html origFooter
-
-
-    onSubmit: (e) ->
-      e.preventDefault()
-      @bulkChange(@prepareQuery())
-
-
-    getAvailableQualityProfiles: ->
-      languages = @options.app.languageFilter.get('value')
-      singleLanguage = _.isArray(languages) && languages.length == 1
-
-      if singleLanguage
-        @options.app.getQualityProfilesForLanguage(languages[0])
-      else
-        @options.app.qualityProfiles
-
-    serializeData: ->
-      action: @action
-
-      paging: @options.app.codingRules.paging
-      qualityProfiles: @options.app.qualityProfiles
-
-      qualityProfile: @profile
-      qualityProfileName: @options.app.qualityProfileFilter.view.renderValue()
-
-      availableQualityProfiles: @getAvailableQualityProfiles()
diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-custom-rule-creation-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-custom-rule-creation-view.coffee
deleted file mode 100644 (file)
index 69df942..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-define [
-  'backbone.marionette',
-  'templates/coding-rules'
-], (
-  Marionette,
-  Templates
-) ->
-
-  class CodingRulesCustomRuleCreationView extends Marionette.ItemView
-    className: 'coding-rules-modal'
-    template: Templates['coding-rules-custom-rule-creation']
-
-
-    ui:
-      customRuleCreationKey: '#coding-rules-custom-rule-creation-key'
-      customRuleCreationName: '#coding-rules-custom-rule-creation-name'
-      customRuleCreationHtmlDescription: '#coding-rules-custom-rule-creation-html-description'
-      customRuleCreationSeverity: '#coding-rules-custom-rule-creation-severity'
-      customRuleCreationStatus: '#coding-rules-custom-rule-creation-status'
-      customRuleCreationParameters: '[name]'
-      customRuleCreationCreate: '#coding-rules-custom-rule-creation-create'
-      customRuleCreationReactivate: '#coding-rules-custom-rule-creation-reactivate'
-      modalFoot: '.modal-foot'
-
-
-    events:
-      'input @ui.customRuleCreationName': 'generateKey'
-      'keydown @ui.customRuleCreationName': 'generateKey'
-      'keyup @ui.customRuleCreationName': 'generateKey'
-
-      'input @ui.customRuleCreationKey': 'flagKey'
-      'keydown @ui.customRuleCreationKey': 'flagKey'
-      'keyup @ui.customRuleCreationKey': 'flagKey'
-
-      'click #coding-rules-custom-rule-creation-cancel': 'hide'
-      'click @ui.customRuleCreationCreate': 'create'
-      'click @ui.customRuleCreationReactivate': 'reactivate'
-
-
-    generateKey: ->
-      unless @keyModifiedByUser
-        if @ui.customRuleCreationKey
-          generatedKey = @ui.customRuleCreationName.val().latinize().replace(/[^A-Za-z0-9]/g, '_')
-          @ui.customRuleCreationKey.val generatedKey
-
-    flagKey: ->
-      @keyModifiedByUser = true
-      # Cannot use @ui.customRuleCreationReactivate.hide() directly since it was not there at initial render
-      jQuery(@ui.customRuleCreationReactivate.selector).hide()
-
-
-    create: ->
-      action = 'create'
-      if @model and @model.has 'key'
-        action = 'update'
-
-      postData =
-        name: @ui.customRuleCreationName.val()
-        markdown_description: @ui.customRuleCreationHtmlDescription.val()
-        severity: @ui.customRuleCreationSeverity.val()
-        status: @ui.customRuleCreationStatus.val()
-
-      if @model && @model.has 'key'
-        postData.key = @model.get 'key'
-      else
-        postData.template_key = @templateRule.get 'key'
-        postData.custom_key = @ui.customRuleCreationKey.val()
-        postData.prevent_reactivation = true
-
-      params = @ui.customRuleCreationParameters.map(->
-        node = jQuery(@)
-        value = node.val()
-        if !value and action == 'create'
-          value = node.prop('placeholder') || ''
-        key: node.prop('name'), value: value).get()
-
-      postData.params = (params.map (param) -> param.key + '=' + window.csvEscape(param.value)).join(';')
-      @sendRequest(action, postData)
-
-
-    reactivate: ->
-      postData =
-        name: @existingRule.name
-        markdown_description: @existingRule.mdDesc
-        severity: @existingRule.severity
-        status: @existingRule.status
-        template_key: @existingRule.templateKey
-        custom_key: @ui.customRuleCreationKey.val()
-        prevent_reactivation: false
-
-      params = @existingRule.params
-      postData.params = (params.map (param) -> param.key + '=' + param.defaultValue).join(';')
-
-      @sendRequest('create', postData)
-
-
-    sendRequest: (action, postData) ->
-      @$('.modal-error').hide()
-      @$('.modal-warning').hide()
-
-      origFooter = @ui.modalFoot.html()
-      @ui.modalFoot.html '<i class="spinner"></i>'
-
-      jQuery.ajax
-        type: 'POST'
-        url: "#{baseUrl}/api/rules/" + action
-        data: postData
-        error: () ->
-      .done (r) =>
-          delete @templateRule
-          @options.app.showRule r.rule.key
-          @hide()
-      .fail (jqXHR, textStatus, errorThrown) =>
-          if jqXHR.status == 409
-            @existingRule = jqXHR.responseJSON.rule
-            @$('.modal-warning').show()
-            @ui.modalFoot.html Templates['coding-rules-custom-rule-reactivation'](@)
-          else
-            jQuery.ajaxSettings.error(jqXHR, textStatus, errorThrown)
-            @ui.modalFoot.html origFooter
-
-
-    onRender: ->
-      @$el.dialog
-        dialogClass: 'no-close',
-        width: '600px',
-        draggable: false,
-        autoOpen: false,
-        modal: true,
-        minHeight: 50,
-        resizable: false,
-        title: null
-
-      @keyModifiedByUser = false
-
-      format = (state) ->
-        return state.text unless state.id
-        "<i class='icon-severity-#{state.id.toLowerCase()}'></i> #{state.text}"
-
-      severity = (@model && @model.get 'severity') || @templateRule.get 'severity'
-      @ui.customRuleCreationSeverity.val severity
-      @ui.customRuleCreationSeverity.select2
-        width: '250px'
-        minimumResultsForSearch: 999
-        formatResult: format
-        formatSelection: format
-
-      status = (@model && @model.get 'status') || @templateRule.get 'status'
-      @ui.customRuleCreationStatus.val status
-      @ui.customRuleCreationStatus.select2
-        width: '250px'
-        minimumResultsForSearch: 999
-
-
-    show: ->
-      @render()
-      @$el.dialog 'open'
-
-
-    hide: ->
-      @$el.dialog 'close'
-
-
-    serializeData: ->
-      params = {}
-      if @templateRule
-        params = @templateRule.get 'params'
-      else if @model and @model.has 'params'
-        params = @model.get('params').map (p) ->
-          _.extend p,
-            value: p.defaultValue
-
-      _.extend super,
-        change: @model && @model.has 'key'
-        params: params
-        severities: ['BLOCKER', 'CRITICAL', 'MAJOR', 'MINOR', 'INFO']
-        statuses: _.map @options.app.statuses, (value, key) ->
-          id: key
-          text: value
diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-debt-popup-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-debt-popup-view.coffee
deleted file mode 100644 (file)
index c8882d8..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-define [
-  'backbone.marionette'
-  'templates/coding-rules'
-  'common/popup'
-], (
-  Marionette
-  Templates
-  Popup
-) ->
-
-  class CodingRulesDebtPopupView extends Popup
-    template: Templates['coding-rules-debt-popup']
-
-    serializeData: ->
-      _.extend super,
-        subcharacteristic: @options.app.getSubcharacteristicName(@model.get 'debtSubChar')
diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-detail-custom-rule-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-detail-custom-rule-view.coffee
deleted file mode 100644 (file)
index 2167046..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-define [
-  'backbone.marionette'
-  'templates/coding-rules'
-], (
-  Marionette
-  Templates
-) ->
-
-  class CodingRulesDetailCustomRuleView extends Marionette.ItemView
-    tagName: 'tr'
-    className: 'coding-rules-detail-custom-rule'
-    template: Templates['coding-rules-detail-custom-rule']
-
-    ui:
-      delete: '.coding-rules-detail-custom-rule-delete'
-
-    events:
-      'click @ui.delete': 'delete'
-
-    delete: ->
-      confirmDialog
-        title: t 'delete'
-        html: t 'are_you_sure'
-        yesHandler: =>
-          origEl = @$el.html()
-          @$el.html '<i class="spinner"></i>'
-
-          jQuery.ajax
-            type: 'POST'
-            url: "#{baseUrl}/api/rules/delete"
-            data:
-              key: @model.get 'key'
-          .done =>
-            templateKey = @options.templateKey or @options.templateRule.get 'key'
-            @options.app.showRule templateKey
-          .fail =>
-            @$el.html origEl
-
-    serializeData: ->
-      _.extend super,
-        templateRule: @options.templateRule
-        canWrite: @options.app.canWrite
diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-detail-custom-rules-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-detail-custom-rules-view.coffee
deleted file mode 100644 (file)
index e43d4ca..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-define [
-  'backbone.marionette'
-  'coding-rules/views/coding-rules-detail-custom-rule-view'
-], (
-  Marionette
-  CodingRulesDetailCustomRuleView
-) ->
-
-  class CodingRulesDetailCustomRulesView extends Marionette.CollectionView
-    tagName: 'table'
-    className: 'width100'
-    itemView: CodingRulesDetailCustomRuleView
-
-    itemViewOptions: ->
-      app: @options.app
-      templateRule: @options.templateRule
diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-detail-quality-profile-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-detail-quality-profile-view.coffee
deleted file mode 100644 (file)
index 7a1544b..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-define [
-  'backbone.marionette',
-  'templates/coding-rules'
-], (
-  Marionette,
-  Templates
-) ->
-
-  class CodingRulesDetailQualityProfileView extends Marionette.ItemView
-    className: 'coding-rules-detail-quality-profile'
-    template: Templates['coding-rules-detail-quality-profile']
-
-
-    modelEvents:
-      'change': 'render'
-
-
-    ui:
-      change: '.coding-rules-detail-quality-profile-change'
-      revert: '.coding-rules-detail-quality-profile-revert'
-      deactivate: '.coding-rules-detail-quality-profile-deactivate'
-
-
-    events:
-      'click @ui.change': 'change'
-      'click @ui.revert': 'revert'
-      'click @ui.deactivate': 'deactivate'
-
-
-    change: ->
-      @options.app.codingRulesQualityProfileActivationView.model = @model
-      @options.app.codingRulesQualityProfileActivationView.show()
-
-
-    revert: ->
-      ruleKey = @options.rule.get('key')
-      confirmDialog
-        title: t 'coding_rules.revert_to_parent_definition'
-        html: tp 'coding_rules.revert_to_parent_definition.confirm', @getParent().name
-        yesHandler: =>
-          jQuery.ajax
-            type: 'POST'
-            url: "#{baseUrl}/api/qualityprofiles/activate_rule"
-            data:
-              profile_key: @model.get('qProfile')
-              rule_key: ruleKey
-              reset: true
-          .done =>
-            @options.app.showRule ruleKey
-
-
-    deactivate: ->
-      ruleKey = @options.rule.get('key')
-      myProfile = _.findWhere(@options.app.qualityProfiles, key: @model.get('qProfile'))
-      confirmDialog
-        title: t 'coding_rules.deactivate'
-        html: tp 'coding_rules.deactivate.confirm', myProfile.name
-        yesHandler: =>
-          jQuery.ajax
-            type: 'POST'
-            url: "#{baseUrl}/api/qualityprofiles/deactivate_rule"
-            data:
-              profile_key: @model.get('qProfile')
-              rule_key: ruleKey
-          .done =>
-            @options.app.showRule ruleKey
-
-
-    enableUpdate: ->
-      @ui.update.prop 'disabled', false
-
-
-    getParent: ->
-      return null unless @model.get('inherit') && @model.get('inherit') != 'NONE'
-      myProfile = _.findWhere(@options.app.qualityProfiles, key: @model.get('qProfile'))
-      parentKey = myProfile.parentKey
-      parent = _.extend {}, _.findWhere(@options.app.qualityProfiles, key: parentKey)
-      parentActiveInfo = @model.collection.findWhere(qProfile: parentKey) or new Backbone.Model()
-      _.extend parent, parentActiveInfo.toJSON()
-      parent
-
-
-    enhanceParameters: ->
-      parent = @getParent()
-      params = _.sortBy(@model.get('params'), 'key')
-      return params unless parent
-      params.map (p) ->
-        parentParam = _.findWhere(parent.params, key: p.key)
-        if parentParam
-          _.extend p, original: _.findWhere(parent.params, key: p.key).value
-        else
-          p
-
-
-    serializeData: ->
-      hash = _.extend super,
-        parent: @getParent()
-        parameters: @enhanceParameters()
-        canWrite: @options.app.canWrite
-        templateKey: @options.rule.get 'templateKey'
-        isTemplate: @options.rule.get 'isTemplate'
diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-detail-quality-profiles-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-detail-quality-profiles-view.coffee
deleted file mode 100644 (file)
index 1a5a9f6..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-define [
-  'backbone.marionette'
-  'coding-rules/views/coding-rules-detail-quality-profile-view'
-], (
-  Marionette,
-  CodingRulesDetailQualityProfileView
-) ->
-
-  class CodingRulesDetailQualityProfilesView extends Marionette.CollectionView
-    itemView: CodingRulesDetailQualityProfileView
-
-    itemViewOptions: ->
-      app: @options.app
-      rule: @options.rule
-      qualityProfiles: @collection
diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-detail-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-detail-view.coffee
deleted file mode 100644 (file)
index d9697a3..0000000
+++ /dev/null
@@ -1,344 +0,0 @@
-define [
-  'backbone'
-  'backbone.marionette'
-  'coding-rules/views/coding-rules-detail-quality-profiles-view'
-  'coding-rules/views/coding-rules-detail-quality-profile-view'
-  'coding-rules/views/coding-rules-detail-custom-rules-view'
-  'coding-rules/views/coding-rules-detail-custom-rule-view'
-  'coding-rules/views/coding-rules-parameter-popup-view'
-  'coding-rules/views/coding-rules-debt-popup-view'
-  'templates/coding-rules'
-], (
-  Backbone
-  Marionette
-  CodingRulesDetailQualityProfilesView
-  CodingRulesDetailQualityProfileView
-  CodingRulesDetailCustomRulesView
-  CodingRulesDetailCustomRuleView
-  CodingRulesParameterPopupView
-  CodingRulesDebtPopupView
-  Templates
-) ->
-
-  class CodingRulesDetailView extends Marionette.Layout
-    template: Templates['coding-rules-detail']
-
-
-    regions:
-      qualityProfilesRegion: '#coding-rules-detail-quality-profiles'
-      customRulesRegion: '.coding-rules-detail-custom-rules-section'
-      customRulesListRegion: '#coding-rules-detail-custom-rules'
-      contextRegion: '.coding-rules-detail-context'
-
-
-    ui:
-      tagsChange: '.coding-rules-detail-tags-change'
-      tagInput: '.coding-rules-detail-tag-input'
-      tagsEdit: '.coding-rules-detail-tag-edit'
-      tagsEditDone: '.coding-rules-detail-tag-edit-done'
-      tagsEditCancel: '.coding-rules-details-tag-edit-cancel'
-      tagsList: '.coding-rules-detail-tag-list'
-
-      subcharacteristic: '.coding-rules-subcharacteristic'
-
-      descriptionExtra: '#coding-rules-detail-description-extra'
-      extendDescriptionLink: '#coding-rules-detail-extend-description'
-      extendDescriptionForm: '.coding-rules-detail-extend-description-form'
-      extendDescriptionSubmit: '#coding-rules-detail-extend-description-submit'
-      extendDescriptionRemove: '#coding-rules-detail-extend-description-remove'
-      extendDescriptionText: '#coding-rules-detail-extend-description-text'
-      extendDescriptionSpinner: '#coding-rules-detail-extend-description-spinner'
-      cancelExtendDescription: '#coding-rules-detail-extend-description-cancel'
-
-      activateQualityProfile: '#coding-rules-quality-profile-activate'
-      activateContextQualityProfile: '.coding-rules-detail-quality-profile-activate'
-      changeQualityProfile: '.coding-rules-detail-quality-profile-update'
-      createCustomRule: '#coding-rules-custom-rules-create'
-      changeCustomRule: '#coding-rules-detail-custom-rule-change'
-      changeManualRule: '#coding-rules-detail-manual-rule-change'
-      deleteCustomRule: '#coding-rules-detail-rule-delete'
-
-
-    events:
-      'click @ui.tagsChange': 'changeTags'
-      'click @ui.tagsEditDone': 'editDone'
-      'click @ui.tagsEditCancel': 'cancelEdit'
-
-      'click @ui.extendDescriptionLink': 'showExtendDescriptionForm'
-      'click @ui.cancelExtendDescription': 'hideExtendDescriptionForm'
-      'click @ui.extendDescriptionSubmit': 'submitExtendDescription'
-      'click @ui.extendDescriptionRemove': 'removeExtendedDescription'
-
-      'click @ui.activateQualityProfile': 'activateQualityProfile'
-      'click @ui.activateContextQualityProfile': 'activateContextQualityProfile'
-      'click @ui.changeQualityProfile': 'changeQualityProfile'
-      'click @ui.createCustomRule': 'createCustomRule'
-      'click @ui.changeCustomRule': 'changeCustomRule'
-      'click @ui.changeManualRule': 'changeManualRule'
-      'click @ui.deleteCustomRule': 'deleteRule'
-
-      'click .coding-rules-detail-parameter-name': 'toggleParameterDescription'
-      'click .coding-rules-subcharacteristic': 'showDebtPopup'
-
-    initialize: (options) ->
-      super options
-
-      if @model.get 'params'
-        origParams = @model.get('params')
-        @model.set 'params', _.sortBy(origParams, 'key')
-
-      _.map options.actives, (active) =>
-        _.extend active, options.app.getQualityProfileByKey active.qProfile
-      qualityProfiles = new Backbone.Collection options.actives,
-        comparator: 'name'
-      @qualityProfilesView = new CodingRulesDetailQualityProfilesView
-        app: @options.app
-        collection: qualityProfiles
-        rule: @model
-
-      unless @model.get 'isTemplate'
-        qualityProfileKey = @options.app.getQualityProfile()
-
-        if qualityProfileKey
-          @contextProfile = qualityProfiles.findWhere qProfile: qualityProfileKey
-          unless @contextProfile
-            @contextProfile = new Backbone.Model
-              key: qualityProfileKey, name: @options.app.qualityProfileFilter.view.renderValue()
-          @contextQualityProfileView = new CodingRulesDetailQualityProfileView
-            app: @options.app
-            model: @contextProfile
-            rule: @model
-            qualityProfiles: qualityProfiles
-
-          @listenTo @contextProfile, 'destroy', @hideContext
-
-    onRender: ->
-      @$el.find('.open-modal').modal()
-
-      if @model.get 'isTemplate'
-        @$(@contextRegion.el).hide()
-
-        if _.isEmpty(@options.actives)
-          @$(@qualityProfilesRegion.el).hide()
-        else
-          @qualityProfilesRegion.show @qualityProfilesView
-
-        @$(@customRulesRegion.el).show()
-        customRulesOriginal = @$(@customRulesRegion.el).html()
-
-        @$(@customRulesRegion.el).html '<i class="spinner"></i>'
-
-        customRules = new Backbone.Collection()
-        jQuery.ajax
-          url: "#{baseUrl}/api/rules/search"
-          data:
-            template_key: @model.get 'key'
-            f: 'name,severity,params'
-        .done (r) =>
-          customRules.add r.rules
-
-          # Protect against element disappearing due to navigation
-          if @customRulesRegion
-            if customRules.isEmpty() and not @options.app.canWrite
-              @$(@customRulesRegion.el).hide()
-            else
-              @customRulesView = new CodingRulesDetailCustomRulesView
-                app: @options.app
-                collection: customRules
-                templateRule: @model
-              @$(@customRulesRegion.el).html customRulesOriginal
-              @customRulesListRegion.show @customRulesView
-
-      else
-        @$(@customRulesRegion.el).hide()
-        @$(@qualityProfilesRegion.el).show()
-        @qualityProfilesRegion.show @qualityProfilesView
-
-        if @options.app.getQualityProfile() and (@options.app.canWrite or @contextProfile.has('severity'))
-          @$(@contextRegion.el).show()
-          @contextRegion.show @contextQualityProfileView
-        else
-          @$(@contextRegion.el).hide()
-
-      that = @
-      jQuery.ajax
-        url: "#{baseUrl}/api/rules/tags"
-      .done (r) =>
-        if @ui.tagInput.select2
-          # Prevent synchronization issue with navigation
-          @ui.tagInput.select2
-            tags: _.difference (_.difference r.tags, that.model.get 'tags'), that.model.get 'sysTags'
-            width: '300px'
-
-      @ui.tagsEdit.hide()
-
-      @ui.extendDescriptionForm.hide()
-      @ui.extendDescriptionSpinner.hide()
-
-
-    toggleParameterDescription: (e) ->
-      jQuery(e.currentTarget).next('.coding-rules-detail-parameter-description').toggle();
-
-
-    showDebtPopup: (e) ->
-      e.stopPropagation()
-      jQuery('body').click()
-      popup = new CodingRulesDebtPopupView
-        model: @model
-        app: @options.app
-        triggerEl: jQuery(e.currentTarget)
-      popup.render()
-      false
-
-
-    hideContext: ->
-      @contextRegion.reset()
-      @$(@contextRegion.el).hide()
-
-
-    changeTags: ->
-      if @ui.tagsEdit.show
-        @ui.tagsEdit.show()
-      if @ui.tagsList.hide
-        @ui.tagsList.hide()
-      @tagsBuffer = @ui.tagInput.select2 'val'
-      key.setScope 'tags'
-      key 'escape', 'tags', => @cancelEdit()
-
-
-    cancelEdit: ->
-      key.unbind 'escape', 'tags'
-      if @ui.tagsList.show
-        @ui.tagsList.show()
-      if @ui.tagInput.select2
-        console.log @tagsBuffer
-        @ui.tagInput.select2 'val', @tagsBuffer
-        @ui.tagInput.select2 'close'
-      if @ui.tagsEdit.hide
-        @ui.tagsEdit.hide()
-
-
-    editDone: ->
-      @ui.tagsEdit.html '<i class="spinner"></i>'
-      tags = @ui.tagInput.val()
-      jQuery.ajax
-        type: 'POST'
-        url: "#{baseUrl}/api/rules/update"
-        data:
-          key: @model.get 'key'
-          tags: tags
-      .done (r) =>
-          @model.set 'tags', r.rule.tags
-          @cancelEdit()
-      .always =>
-        @render()
-
-
-    showExtendDescriptionForm: ->
-      @ui.descriptionExtra.hide()
-      @ui.extendDescriptionForm.show()
-      key.setScope 'extraDesc'
-      key 'escape', 'extraDesc', => @hideExtendDescriptionForm()
-      @ui.extendDescriptionText.focus()
-
-
-    hideExtendDescriptionForm: ->
-      key.unbind 'escape', 'extraDesc'
-      @ui.descriptionExtra.show()
-      @ui.extendDescriptionForm.hide()
-
-
-    submitExtendDescription: ->
-      @ui.extendDescriptionForm.hide()
-      @ui.extendDescriptionSpinner.show()
-      jQuery.ajax
-        type: 'POST'
-        url: "#{baseUrl}/api/rules/update"
-        dataType: 'json'
-        data:
-          key: @model.get 'key'
-          markdown_note: @ui.extendDescriptionText.val()
-      .done (r) =>
-        @model.set
-          htmlNote: r.rule.htmlNote
-          mdNote: r.rule.mdNote
-        @render()
-
-
-    removeExtendedDescription: ->
-      confirmDialog
-        html: t 'coding_rules.remove_extended_description.confirm'
-        yesHandler: =>
-          @ui.extendDescriptionText.val ''
-          @submitExtendDescription()
-
-
-    activateQualityProfile: ->
-      @options.app.codingRulesQualityProfileActivationView.model = null
-      @options.app.codingRulesQualityProfileActivationView.show()
-
-
-    activateContextQualityProfile: ->
-      @options.app.codingRulesQualityProfileActivationView.model = @contextProfile
-      @options.app.codingRulesQualityProfileActivationView.show()
-
-    createCustomRule: ->
-      @options.app.codingRulesCustomRuleCreationView.templateRule = @model
-      @options.app.codingRulesCustomRuleCreationView.model = new Backbone.Model()
-      @options.app.codingRulesCustomRuleCreationView.show()
-
-
-    changeCustomRule: ->
-      @options.app.codingRulesCustomRuleCreationView.model = @model
-      @options.app.codingRulesCustomRuleCreationView.show()
-
-
-    changeManualRule: ->
-      @options.app.codingRulesManualRuleCreationView.model = @model
-      @options.app.codingRulesManualRuleCreationView.show()
-
-
-    deleteRule: ->
-      ruleType = if @model.has('templateKey') then 'custom' else 'manual'
-      confirmDialog
-        title: t 'delete'
-        html: tp "coding_rules.delete.#{ruleType}.confirm", @model.get('name')
-        yesHandler: =>
-          jQuery.ajax
-            type: 'POST'
-            url: "#{baseUrl}/api/rules/delete"
-            data:
-              key: @model.get 'key'
-          .done =>
-            @options.app.fetchFirstPage()
-          .fail =>
-            @options.app.showRule @model.get('key')
-
-
-    serializeData: ->
-      contextQualityProfile = @options.app.getQualityProfile()
-      repoKey = @model.get 'repo'
-      isManual = (@options.app.manualRepository().key == repoKey)
-      isCustom = (@model.has 'templateKey')
-
-      qualityProfilesVisible = not isManual
-      if qualityProfilesVisible
-        if @model.get 'isTemplate'
-          qualityProfilesVisible = (not _.isEmpty(@options.actives))
-        else
-          qualityProfilesVisible = (@options.app.canWrite or not _.isEmpty(@options.actives))
-
-
-      _.extend super,
-        contextQualityProfile: contextQualityProfile
-        contextQualityProfileName: @options.app.qualityProfileFilter.view.renderValue()
-        qualityProfile: @contextProfile
-        language: @options.app.languages[@model.get 'lang']
-        repository: _.find(@options.app.repositories, (repo) -> repo.key == repoKey).name
-        isManual: isManual
-        canWrite: @options.app.canWrite
-        isEditable: (@options.app.canWrite and (isManual or isCustom))
-        qualityProfilesVisible: qualityProfilesVisible
-        subcharacteristic: @options.app.getSubcharacteristicName(@model.get 'debtSubChar')
-        createdAt: moment(@model.get 'createdAt').toDate()
-        allTags: _.union @model.get('sysTags'), @model.get('tags')
diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-facets-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-facets-view.coffee
deleted file mode 100644 (file)
index a83094f..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-define [
-  'backbone.marionette'
-  'templates/coding-rules'
-], (
-  Marionette,
-  Templates
-) ->
-
-  class CodingRulesFacetsView extends Marionette.ItemView
-    template: Templates['coding-rules-facets']
-
-
-    ui:
-      facets: '.navigator-facets-list-item'
-      options: '.facet'
-
-
-    events:
-      'click @ui.options': 'selectOption'
-
-
-    initialize: ->
-      super()
-      that = @
-      @options.collection.each (facet) ->
-        property = facet.get 'property'
-        facet.set 'property_message', t 'coding_rules.facets.' + property
-        facet.set 'limitReached', facet.get('values').length >= 10
-        _.each(facet.get('values'), (value) ->
-          value.text = that.options.app.facetLabel(property, value.val)
-        )
-
-    selectOption: (e) ->
-      option = jQuery(e.currentTarget)
-      option.toggleClass 'active'
-      property = option.closest('.navigator-facets-list-item').data('property')
-      value = option.data('key')
-      @options.app.filterBarView.toggle(property, value)
-      @applyOptions()
-
-
-    applyOptions: ->
-      @options.app.fetchFirstPage()
-
-
-    restoreFromQuery: (params) ->
-      @ui.options.each ->
-        jQuery(@).removeClass('active')
-      @ui.facets.each ->
-        property = jQuery(@).data 'property'
-        if !!params[property]
-          _(params[property].split(',')).map (value) ->
-            jQuery('.navigator-facets-list-item[data-property="' + property + '"] .facet[data-key="' + value + '"]').addClass 'active'
diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-list-empty-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-list-empty-view.coffee
deleted file mode 100644 (file)
index c3eb8d4..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-define [
-  'backbone.marionette',
-  'templates/coding-rules'
-], (
-  Marionette,
-  Templates
-) ->
-
-  class CodingRulesListEmptyView extends Marionette.ItemView
-    tagName: 'li'
-    className: 'navigator-results-no-results'
-    template: Templates['coding-rules-list-empty']
diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-list-item-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-list-item-view.coffee
deleted file mode 100644 (file)
index 0c77a63..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-define [
-  'backbone.marionette',
-  'coding-rules/views/coding-rules-detail-view',
-  'templates/coding-rules'
-], (
-  Marionette,
-  CodingRulesDetailView,
-  Templates
-) ->
-
-  class CodingRulesListItemView extends Marionette.ItemView
-    tagName: 'li'
-    template: Templates['coding-rules-list-item']
-    activeClass: 'active'
-
-
-    events: ->
-      'click': 'showDetail'
-
-
-    showDetail: ->
-      @options.listView.selectIssue @$el
-      @options.app.showRule @model.get('key')
-
-
-    serializeData: ->
-      tags = _.union @model.get('sysTags'), @model.get('tags')
-      _.extend super,
-        manualRuleLabel: t 'coding_rules.manual_rule'
-        allTags: tags
-        showDetails: (@model.get('status') != 'READY') || (_.isArray(tags) && tags.length > 0)
diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-list-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-list-view.coffee
deleted file mode 100644 (file)
index b62e4a2..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-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
-
-
-    initialize: ->
-      openRule = (el) -> el.click()
-      @openRule = _.debounce openRule, 300
-      key.setScope 'list'
-
-
-    onRender: ->
-      key 'up', 'list', (e) =>
-        @selectPrev()
-        #e.stopPropagation()
-      key 'down', 'list', (e) =>
-        @selectNext()
-        #e.stopPropagation()
-
-      $scrollEl = jQuery('.navigator-results')
-      scrollEl = $scrollEl.get(0)
-      onScroll = =>
-        if scrollEl.offsetHeight + scrollEl.scrollTop >= scrollEl.scrollHeight
-          @options.app.fetchNextPage()
-      throttledScroll = _.throttle onScroll, 300
-      $scrollEl.off('scroll').on 'scroll', throttledScroll
-
-
-    onClose: ->
-      @unbindEvents()
-
-
-    unbindEvents: ->
-      key.unbind 'up', 'list'
-      key.unbind 'down', 'list'
-
-
-    selectIssue: (el, open) ->
-      @$('.active').removeClass 'active'
-      el.addClass 'active'
-      ruleKey = el.find('[name]').attr('name')
-      rule = @collection.findWhere key: ruleKey
-      @selected = @collection.indexOf(rule)
-      @openRule el if open
-
-
-    selectFirst: ->
-      @selected = -1
-      @selectNext()
-
-
-    selectCurrent: ->
-      @selected--
-      @selectNext()
-
-
-    selectNext: ->
-      if @selected + 1 < @collection.length
-        @selected += 1
-        child = @$el.children().eq(@selected)
-        container = jQuery('.navigator-results')
-        containerHeight = container.height()
-        bottom = child.position().top + child.outerHeight()
-        if bottom > containerHeight
-          container.scrollTop(container.scrollTop() - containerHeight + bottom)
-        @selectIssue child, true
-
-
-    selectPrev: ->
-      if @selected > 0
-        @selected -= 1
-        child = @$el.children().eq(@selected)
-        container = jQuery('.navigator-results')
-        top = child.position().top
-        if top < 0
-          container.scrollTop(container.scrollTop() + top)
-        @selectIssue child, true
diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-manual-rule-creation-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-manual-rule-creation-view.coffee
deleted file mode 100644 (file)
index fdae346..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-define [
-  'backbone.marionette',
-  'templates/coding-rules'
-], (
-  Marionette,
-  Templates
-) ->
-
-  class CodingRulesManualRuleCreationView extends Marionette.ItemView
-    template: Templates['coding-rules-manual-rule-creation']
-
-
-    ui:
-      manualRuleCreationKey: '#coding-rules-manual-rule-creation-key'
-      manualRuleCreationName: '#coding-rules-manual-rule-creation-name'
-      manualRuleCreationHtmlDescription: '#coding-rules-manual-rule-creation-html-description'
-      manualRuleCreationSeverity: '#coding-rules-manual-rule-creation-severity'
-      manualRuleCreationStatus: '#coding-rules-manual-rule-creation-status'
-      manualRuleCreationParameters: '[name]'
-      manualRuleCreationCreate: '#coding-rules-manual-rule-creation-create'
-      manualRuleCreationReactivate: '#coding-rules-manual-rule-creation-reactivate'
-      modalFoot: '.modal-foot'
-
-
-    events:
-      'input @ui.manualRuleCreationName': 'generateKey'
-      'keydown @ui.manualRuleCreationName': 'generateKey'
-      'keyup @ui.manualRuleCreationName': 'generateKey'
-
-      'input @ui.manualRuleCreationKey': 'flagKey'
-      'keydown @ui.manualRuleCreationKey': 'flagKey'
-      'keyup @ui.manualRuleCreationKey': 'flagKey'
-
-      'click #coding-rules-manual-rule-creation-cancel': 'hide'
-      'click @ui.manualRuleCreationCreate': 'create'
-      'click @ui.manualRuleCreationReactivate': 'reactivate'
-
-
-    generateKey: ->
-      unless @keyModifiedByUser
-        if @ui.manualRuleCreationKey
-          generatedKey = @ui.manualRuleCreationName.val().latinize().replace(/[^A-Za-z0-9]/g, '_')
-          @ui.manualRuleCreationKey.val generatedKey
-
-    flagKey: ->
-      @keyModifiedByUser = true
-      # Cannot use @ui.manualRuleCreationReactivate.hide() directly since it was not there at initial render
-      jQuery(@ui.manualRuleCreationReactivate.selector).hide()
-
-
-    create: ->
-      action = 'create'
-      if @model and @model.has 'key'
-        action = 'update'
-
-      postData =
-        name: @ui.manualRuleCreationName.val()
-        markdown_description: @ui.manualRuleCreationHtmlDescription.val()
-
-      if @model && @model.has 'key'
-        postData.key = @model.get 'key'
-      else
-        postData.manual_key = @ui.manualRuleCreationKey.val()
-        postData.prevent_reactivation = true
-
-      @sendRequest(action, postData)
-
-
-    reactivate: ->
-      postData =
-        name: @existingRule.name
-        markdown_description: @existingRule.mdDesc
-        manual_key: @ui.manualRuleCreationKey.val()
-        prevent_reactivation: false
-
-      @sendRequest('create', postData)
-
-
-    sendRequest: (action, postData) ->
-      @$('.modal-error').hide()
-      @$('.modal-warning').hide()
-
-      origFooter = @ui.modalFoot.html()
-      @ui.modalFoot.html '<i class="spinner"></i>'
-
-      jQuery.ajax
-        type: 'POST'
-        url: "#{baseUrl}/api/rules/" + action
-        data: postData
-        error: () ->
-      .done (r) =>
-          @options.app.showRule r.rule.key
-          @hide()
-      .fail (jqXHR, textStatus, errorThrown) =>
-          if jqXHR.status == 409
-            @existingRule = jqXHR.responseJSON.rule
-            @$('.modal-warning').show()
-            @ui.modalFoot.html Templates['coding-rules-manual-rule-reactivation'](@)
-          else
-            jQuery.ajaxSettings.error(jqXHR, textStatus, errorThrown)
-            @ui.modalFoot.html origFooter
-
-
-    onRender: ->
-      @$el.dialog
-        dialogClass: 'no-close',
-        width: '600px',
-        draggable: false,
-        autoOpen: false,
-        modal: true,
-        minHeight: 50,
-        resizable: false,
-        title: null
-
-      @keyModifiedByUser = false
-
-      format = (state) ->
-        return state.text unless state.id
-        "<i class='icon-severity-#{state.id.toLowerCase()}'></i> #{state.text}"
-
-
-    show: ->
-      @render()
-      @$el.dialog 'open'
-
-
-    hide: ->
-      @$el.dialog 'close'
-
-
-    serializeData: ->
-      _.extend super,
-        change: @model && @model.has 'key'
diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-parameter-popup-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-parameter-popup-view.coffee
deleted file mode 100644 (file)
index 52ece5d..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-define [
-  'backbone.marionette'
-  'templates/coding-rules'
-  'common/popup'
-], (
-  Marionette
-  Templates
-  Popup
-) ->
-
-  $ = jQuery
-
-
-  class CodingRulesParameterPopupView extends Popup
-    template: Templates['coding-rules-parameter-popup']
diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-quality-profile-activation-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-quality-profile-activation-view.coffee
deleted file mode 100644 (file)
index 9660c29..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-define [
-  'backbone.marionette',
-  'templates/coding-rules'
-], (
-  Marionette,
-  Templates
-) ->
-
-  class CodingRulesQualityProfileActivationView extends Marionette.ItemView
-    className: 'coding-rules-modal'
-    template: Templates['coding-rules-quality-profile-activation']
-
-
-    ui:
-      qualityProfileSelect: '#coding-rules-quality-profile-activation-select'
-      qualityProfileSeverity: '#coding-rules-quality-profile-activation-severity'
-      qualityProfileActivate: '#coding-rules-quality-profile-activation-activate'
-      qualityProfileParameters: '[name]'
-
-
-    events:
-      'click #coding-rules-quality-profile-activation-cancel': 'hide'
-      'click @ui.qualityProfileActivate': 'activate'
-
-
-    activate: ->
-      profileKey = @ui.qualityProfileSelect.val()
-      params = @ui.qualityProfileParameters.map(->
-        key: jQuery(@).prop('name'), value: jQuery(@).val() || jQuery(@).prop('placeholder') || '').get()
-
-      paramsHash = (params.map (param) -> param.key + '=' + window.csvEscape(param.value)).join(';')
-
-      if @model
-        profileKey = @model.get('qProfile')
-        unless profileKey
-          profileKey = @model.get('key')
-      severity = @ui.qualityProfileSeverity.val()
-
-      origFooter = @$('.modal-foot').html()
-      @$('.modal-foot').html '<i class="spinner"></i>'
-
-      ruleKey = @rule.get('key')
-      jQuery.ajax
-        type: 'POST'
-        url: "#{baseUrl}/api/qualityprofiles/activate_rule"
-        data:
-          profile_key: profileKey
-          rule_key: ruleKey
-          severity: severity
-          params: paramsHash
-      .done =>
-          @options.app.showRule ruleKey
-          @hide()
-      .fail =>
-          @$('.modal-foot').html origFooter
-
-
-    onRender: ->
-      @$el.dialog
-        dialogClass: 'no-close',
-        width: '600px',
-        draggable: false,
-        autoOpen: false,
-        modal: true,
-        minHeight: 50,
-        resizable: false,
-        title: null
-
-      @ui.qualityProfileSelect.select2
-        width: '250px'
-        minimumResultsForSearch: 5
-
-      format = (state) ->
-        return state.text unless state.id
-        "<i class='icon-severity-#{state.id.toLowerCase()}'></i> #{state.text}"
-
-      severity = (@model && @model.get 'severity') || @rule.get 'severity'
-      @ui.qualityProfileSeverity.val severity
-      @ui.qualityProfileSeverity.select2
-        width: '250px'
-        minimumResultsForSearch: 999
-        formatResult: format
-        formatSelection: format
-
-
-    show: ->
-      @render()
-      @$el.dialog 'open'
-
-
-    hide: ->
-      @$el.dialog 'close'
-
-
-    getAvailableQualityProfiles: (lang) ->
-      activeQualityProfiles =  @options.app.detailView.qualityProfilesView.collection
-      inactiveProfiles = _.reject @options.app.qualityProfiles, (profile) =>
-        activeQualityProfiles.findWhere key: profile.key
-      _.filter inactiveProfiles, (profile) =>
-        profile.lang == lang
-
-
-    serializeData: ->
-      params = @rule.get 'params'
-      if @model
-        modelParams = @model.get 'params'
-        if modelParams
-          params = params.map (p) ->
-            parentParam = _.findWhere(modelParams, key: p.key)
-            if parentParam
-              _.extend p, value: _.findWhere(modelParams, key: p.key).value
-            else
-              p
-
-      availableProfiles = @getAvailableQualityProfiles(@rule.get 'lang')
-
-      _.extend super,
-        rule: @rule.toJSON()
-        change: @model && @model.has 'severity'
-        params: params
-        qualityProfiles: availableProfiles
-        severities: ['BLOCKER', 'CRITICAL', 'MAJOR', 'MINOR', 'INFO']
-        saveEnabled: not _.isEmpty(availableProfiles) or (@model and @model.get('qProfile'))
-        isCustomRule: (@model and @model.has('templateKey')) or @rule.has 'templateKey'
diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/filter-bar-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/filter-bar-view.coffee
deleted file mode 100644 (file)
index b01ee86..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-define [
-  'navigator/filters/filter-bar',
-  'navigator/filters/base-filters',
-  'navigator/filters/favorite-filters',
-  'navigator/filters/more-criteria-filters',
-  'navigator/filters/read-only-filters',
-  'templates/coding-rules'
-], (
-  FilterBarView,
-  BaseFilters,
-  FavoriteFiltersModule,
-  MoreCriteriaFilters,
-  ReadOnlyFilterView,
-  Templates
-) ->
-
-  class CodingRulesFilterBarView extends FilterBarView
-    template: Templates['coding-rules-filter-bar']
-
-    collectionEvents:
-      'change:enabled': 'changeEnabled'
-
-
-    events:
-      'click .navigator-filter-submit': 'search'
-
-
-    onRender: ->
-      @selectFirst()
-
-
-    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: ->
-      readOnlyFilters = @collection.where(type: ReadOnlyFilterView)
-      disabledFilters = _.difference(@collection.where(enabled: false), readOnlyFilters)
-      if disabledFilters.length > 0
-        @moreCriteriaFilter = new BaseFilters.Filter
-          type: MoreCriteriaFilters.MoreCriteriaFilterView,
-          enabled: true,
-          optional: false,
-          filters: disabledFilters
-        @collection.add @moreCriteriaFilter
-
-
-    changeEnabled: ->
-      if @moreCriteriaFilter?
-        disabledFilters = _.reject @collection.where(enabled: false), (filter) ->
-          filter.get('type') in [MoreCriteriaFilters.MoreCriteriaFilterView, ReadOnlyFilterView]
-
-        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: ->
-      @$('.navigator-filter-submit').blur()
-      @options.app.state.set
-        query: this.options.app.getQuery(),
-        search: true
-      @options.app.fetchFirstPage()
-
-
-    fetchNextPage: ->
-      @options.app.fetchNextPage()
-
-
-    restoreFromWsQuery: (query) ->
-      params = _.map(query, (value, key) ->
-        'key': key
-        'value': value
-      )
-      @restoreFromQuery params
-
-
-    toggle: (property, value) ->
-      filter = @collection.findWhere(property: property)
-      unless filter.view.isActive()
-        @moreCriteriaFilter.view.detailsView.enableByProperty(property)
-      choice = filter.view.choices.get(value)
-      choice.set 'checked', !choice.get('checked')
-      filter.view.detailsView.updateValue()
-      filter.view.detailsView.updateLists()
diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/filters/activation-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/filters/activation-filter-view.coffee
deleted file mode 100644 (file)
index da9e451..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-define [
-  'coding-rules/views/filters/profile-dependent-filter-view'
-], (
-  ProfileDependentFilterView
-) ->
-
-  class ActivationFilterView extends ProfileDependentFilterView
-    tooltip: 'coding_rules.filters.activation.help'
-
-
-    makeActive: ->
-      super
-      filterValue = @model.get 'value'
-      if !filterValue or filterValue.length == 0
-        @choices.each (model) -> model.set 'checked', model.id == 'true'
-        @model.set 'value', ['true']
-        @detailsView.updateLists()
-
-
-
-    showDetails: ->
-      super unless @$el.is '.navigator-filter-inactive'
-
-
-    restore: (value) ->
-      value = value.split(',') if _.isString(value)
-      if @choices && value.length > 0
-        @choices.each (model) -> model.set 'checked', value.indexOf(model.id) >= 0
-        @model.set value: value, enabled: true
-        @onChangeQualityProfile()
-      else
-        @clear()
diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/filters/active-severities-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/filters/active-severities-filter-view.coffee
deleted file mode 100644 (file)
index 8cbe81e..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-
-define [
-  'coding-rules/views/filters/profile-dependent-filter-view'
-], (
-  ProfileDependentFilterView
-) ->
-
-  class ActiveSeveritiesFilterView extends ProfileDependentFilterView
-    tooltip: 'coding_rules.filters.active_severity.inactive'
diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/filters/characteristic-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/filters/characteristic-filter-view.coffee
deleted file mode 100644 (file)
index efa29a7..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-define [
-  'navigator/filters/choice-filters'
-], (
-  ChoiceFilters
-) ->
-
-  class CharacteriticFilterView extends ChoiceFilters.ChoiceFilterView
-
-    initialize: ->
-      super
-      @choices.comparator = 'text'
-      @choices.sort()
diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/filters/inheritance-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/filters/inheritance-filter-view.coffee
deleted file mode 100644 (file)
index 145dc06..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-define [
-  'coding-rules/views/filters/profile-dependent-filter-view'
-], (
-  ProfileDependentFilterView
-) ->
-
-  class InheritanceFilterView extends ProfileDependentFilterView
-    tooltip: 'coding_rules.filters.inheritance.inactive'
-
-    onChangeQualityProfile: ->
-      qualityProfileKey = @qualityProfileFilter.get 'value'
-      if _.isArray(qualityProfileKey) && qualityProfileKey.length == 1
-        qualityProfile = @options.app.getQualityProfileByKey qualityProfileKey[0]
-        if qualityProfile.parentKey
-          parentQualityProfile = @options.app.getQualityProfile qualityProfile.parentKey
-          if parentQualityProfile
-            @makeActive()
-          else
-            @makeInactive()
-        else
-          @makeInactive()
-      else
-        @makeInactive()
diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/filters/language-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/filters/language-filter-view.coffee
deleted file mode 100644 (file)
index b52dcb2..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-define [
-  'navigator/filters/choice-filters',
-  'templates/coding-rules'
-], (
-  ChoiceFilters,
-  Templates
-) ->
-
-  class LanguageFilterView extends ChoiceFilters.ChoiceFilterView
-
-    modelEvents:
-      'change:value': 'onChangeValue'
-      'change:enabled': 'focus',
-
-
-    initialize: ->
-      super
-      @choices.comparator = 'text'
-      @choices.sort()
-      @app = @model.get 'app'
-      @listenTo @app.qualityProfileFilter, 'change:value', @onChangeProfile
-      @selectedFromProfile = false
-
-    onChangeProfile: ->
-      profiles = @app.qualityProfileFilter.get 'value'
-      if _.isArray(profiles) && profiles.length > 0
-        profile = _.findWhere @app.qualityProfiles, key: profiles[0]
-        @options.filterBarView.moreCriteriaFilter.view.detailsView.enableByProperty(@detailsView.model.get 'property')
-        @choices.each (item) -> item.set 'checked', item.id == profile.lang
-        @refreshValues()
-        @selectedFromProfile = true
-      else if @selectedFromProfile
-        @choices.each (item) -> item.set 'checked', false
-        @refreshValues()
-
-    onChangeValue: ->
-      @selectedFromProfile = false
-      @renderBase()
-
-
-    refreshValues: ->
-      @detailsView.updateValue()
-      @detailsView.updateLists()
-      @render()
-      @hideDetails()
diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/filters/profile-dependent-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/filters/profile-dependent-filter-view.coffee
deleted file mode 100644 (file)
index 5afad40..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-define [
-  'navigator/filters/choice-filters'
-], (
-  ChoiceFilters
-) ->
-
-  class ProfileDependentFilterView extends ChoiceFilters.ChoiceFilterView
-    tooltip: 'coding_rules.filters.activation.help'
-
-    initialize: ->
-      super
-      @qualityProfileFilter = @model.get 'qualityProfileFilter'
-      @listenTo @qualityProfileFilter, 'change:value', @onChangeQualityProfile
-      @onChangeQualityProfile()
-
-
-    onChangeQualityProfile: ->
-      qualityProfileKey = @qualityProfileFilter.get 'value'
-      if _.isArray(qualityProfileKey) && qualityProfileKey.length == 1
-        @makeActive()
-      else
-        @makeInactive()
-
-
-    makeActive: ->
-      @model.set inactive: false, title: ''
-      @model.trigger 'change:enabled'
-      @$el.removeClass('navigator-filter-inactive').prop 'title', ''
-      @options.filterBarView.moreCriteriaFilter.view.detailsView.enableByProperty(@detailsView.model.get 'property')
-      @hideDetails()
-
-
-    makeInactive: ->
-      @model.set inactive: true, title: t @tooltip
-      @model.trigger 'change:enabled'
-      @choices.each (model) -> model.set 'checked', false
-      @detailsView.updateLists()
-      @detailsView.updateValue()
-      @$el.addClass('navigator-filter-inactive').prop 'title', t @tooltip
-
-
-    showDetails: ->
-      super unless @$el.is '.navigator-filter-inactive'
-
-
-    restore: (value) ->
-      value = value.split(',') if _.isString(value)
-      if @choices && value.length > 0
-        @model.set value: value, enabled: true
-        @choices.each (item) ->
-          item.set 'checked', false
-        _.each value, (v) =>
-          cModel = @choices.findWhere id: v
-          cModel.set 'checked', true
-        @onChangeQualityProfile()
-      else
-        @clear()
diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/filters/quality-profile-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/filters/quality-profile-filter-view.coffee
deleted file mode 100644 (file)
index d665930..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-define [
-  'navigator/filters/choice-filters',
-  'templates/coding-rules'
-], (
-  ChoiceFilters,
-  Templates
-) ->
-
-  class QualityProfileDetailFilterView extends ChoiceFilters.DetailsChoiceFilterView
-    itemTemplate: Templates['coding-rules-profile-filter-detail']
-
-
-  class QualityProfileFilterView extends ChoiceFilters.ChoiceFilterView
-
-    initialize: ->
-      super
-        detailsView: QualityProfileDetailFilterView
-
-      @app = @model.get 'app'
-
-      @allProfiles = @model.get 'choices'
-      @updateChoices @allProfiles
-
-      @listenTo @app.languageFilter, 'change:value', @onChangeLanguage
-      @onChangeLanguage()
-
-
-    onChangeLanguage: ->
-      languages = @app.languageFilter.get 'value'
-      if _.isArray(languages) && languages.length > 0
-        @filterLanguages(languages)
-      else
-        @updateChoices(@allProfiles)
-
-    filterLanguages: (languages) ->
-      languageProfiles = _.filter( @allProfiles, (prof) -> languages.indexOf(prof.lang) >= 0 )
-      @updateChoices(languageProfiles)
-
-
-    updateChoices: (collection) ->
-      languages = @app.languages
-      currentValue = @model.get('value')
-      @choices = new Backbone.Collection( _.map collection, (item, index) ->
-          new Backbone.Model
-            id: item.key
-            text: item.name
-            checked: false
-            index: index
-            language: languages[item.lang]
-        comparator: 'index'
-      )
-      if currentValue
-        @restore(currentValue)
-      @render()
-
-    render: ->
-      super
-      if @model.get 'value'
-        @$el.addClass('navigator-filter-context')
-      else
-        @$el.removeClass('navigator-filter-context')
diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/filters/query-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/filters/query-filter-view.coffee
deleted file mode 100644 (file)
index ee8e70d..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-define [
-  'backbone',
-  'backbone.marionette',
-  'navigator/filters/base-filters',
-  'navigator/filters/string-filters',
-  'navigator/filters/choice-filters',
-  'templates/coding-rules',
-  'common/handlebars-extensions'
-], (
-  Backbone,
-  Marionette,
-  BaseFilters,
-  StringFilterView,
-  ChoiceFilters,
-  Templates
-) ->
-
-  class QueryFilterView extends StringFilterView
-    template: Templates['coding-rules-query-filter']
-    className: 'navigator-filter navigator-filter-query'
-
-    events:
-      'keypress input': 'checkSubmit'
-      'change input': 'change'
-      'click': 'focus'
-      'blur': 'blur'
-
-
-    change: (e) ->
-      @model.set 'value', $j(e.target).val()
-      @options.app.codingRules.sorting = sort: '', asc: ''
-
-
-    clear: ->
-      super
-      @focus()
-
-
-    focus: ->
-      @$(':input').focus();
-
-
-    blur: ->
-      @$(':input').blur();
-
-
-    serializeData: ->
-      return _.extend({}, @model.toJSON(),
-        value: this.model.get('value') || ''
-      )
-
-
-    initialize: ->
-      super detailsView: null
-      @model.set('size', 25) unless @model.get 'size'
-
-
-    checkSubmit: (e) ->
-      if (e.which == 13)
-        e.preventDefault()
-        @change(e)
-        @blur()
-        @options.app.filterBarView.$('.navigator-filter-submit').focus()
-        @options.app.filterBarView.$('.navigator-filter-submit').click()
-
-
-    renderInput: ->
-      # Done in template
-
-
-    toggleDetails: ->
-      # NOP
-
-
-    isDefaultValue: ->
-      true
-
-
-    renderBase: ->
-      super
-      @$el.prop('title', '');
diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/filters/repository-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/filters/repository-filter-view.coffee
deleted file mode 100644 (file)
index aeae2be..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-define [
-  'navigator/filters/choice-filters',
-  'templates/coding-rules'
-], (
-  ChoiceFilters,
-  Templates
-) ->
-
-  class RepositoryDetailFilterView extends ChoiceFilters.DetailsChoiceFilterView
-    itemTemplate: Templates['coding-rules-repository-detail']
-
-
-  class RepositoryFilterView extends ChoiceFilters.ChoiceFilterView
-
-    initialize: ->
-      super
-        detailsView: RepositoryDetailFilterView
-
-      @app = @model.get 'app'
-
-      @allRepositories = @model.get 'choices'
-      @updateChoices @allRepositories
-
-      @listenTo @app.languageFilter, 'change:value', @onChangeLanguage
-      @onChangeLanguage()
-
-
-    onChangeLanguage: ->
-      languages = @app.languageFilter.get 'value'
-      if _.isArray(languages) && languages.length > 0
-        @filterLanguages(languages)
-      else
-        @updateChoices(@allRepositories)
-
-    filterLanguages: (languages) ->
-      languageRepositories = _.filter( @allRepositories, (repo) -> languages.indexOf(repo.language) >= 0 )
-      @updateChoices(languageRepositories)
-
-
-    updateChoices: (collection) ->
-      languages = @app.languages
-      currentValue = @model.get('value')
-      @choices = new Backbone.Collection( _.map collection, (item, index) ->
-          new Backbone.Model
-            id: item.key
-            text: item.name
-            checked: false
-            index: index
-            language: languages[item.language]
-        comparator: (item) ->
-          [item.get('text'), item.get('language')]
-      )
-      if currentValue
-        @restore(currentValue)
-      @render()
diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/filters/tag-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/filters/tag-filter-view.coffee
deleted file mode 100644 (file)
index 01366e7..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-define [
-  'navigator/filters/choice-filters'
-], (
-  ChoiceFilters
-) ->
-
-  class TagFilterView extends ChoiceFilters.ChoiceFilterView
-
-    initialize: ->
-      super()
-      @loadTags()
-      # TODO Register an event handler to reload tags when they are modified on a rule
-
-
-    loadTags: ->
-      tagsXHR = jQuery.ajax
-        url: "#{baseUrl}/api/rules/tags"
-        async: false
-
-      jQuery.when(tagsXHR).done (r) =>
-        @choices = new Backbone.Collection(
-          _.map(r.tags, (tag) ->
-            new Backbone.Model
-              id: tag
-              text: tag
-          ),
-          comparator: 'text')
-
-        if @tagToRestore
-          @restore(@tagToRestore)
-          @tagToRestore = null
-        @render()
-
-    restore: (value) ->
-      unless @choices.isEmpty()
-        super(value)
-      else
-        @tagToRestore = value
diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/header-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/header-view.coffee
deleted file mode 100644 (file)
index caa03b5..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-define [
-  'backbone.marionette',
-  'templates/coding-rules'
-], (
-  Marionette,
-  Templates
-) ->
-
-  class CodingRulesHeaderView extends Marionette.ItemView
-    template: Templates['coding-rules-header']
-
-
-    events:
-      'click #coding-rules-new-search': 'newSearch'
-      'click #coding-rules-create-rule': 'createRule'
-
-
-    newSearch: ->
-      @options.app.router.emptyQuery()
-
-
-    createRule: ->
-      @options.app.createManualRule()
-
-
-    serializeData: ->
-      _.extend super,
-        'canWrite': @options.app.canWrite
index 9ae6f8b3604685dc6d52a04522fedc5176c8072d..c40aeee41de058bdfafdc7ff1dfd2f94d8ee7d01 100644 (file)
@@ -22,7 +22,7 @@ requirejs [
   'issues/models/state'
   'issues/layout'
   'issues/models/issues'
-  'issues/models/facets'
+  'components/navigator/models/facets'
   'issues/models/filters'
 
   'issues/controller'
@@ -70,7 +70,7 @@ requirejs [
 
   App.addInitializer ->
     @state = new State()
-    @issues = new Issues()
+    @list = new Issues()
     @facets = new Facets()
     @filters = new Filters()
 
@@ -82,7 +82,7 @@ requirejs [
   App.addInitializer ->
     @issuesView = new WorkspaceListView
       app: @
-      collection: @issues
+      collection: @list
     @layout.workspaceListRegion.show @issuesView
     @issuesView.bindScrollEvents()
 
@@ -90,7 +90,7 @@ requirejs [
   App.addInitializer ->
     @workspaceHeaderView = new WorkspaceHeaderView
       app: @
-      collection: @issues
+      collection: @list
     @layout.workspaceHeaderRegion.show @workspaceHeaderView
 
 
index 88dbf3311a39fc1866a0f0416e7f0c9d6f8e539a..31f3c0baff516db81df91831701950cc33a5fc71 100644 (file)
@@ -52,11 +52,11 @@ define [
         selectedIssueView.find(".js-issue-#{action}").click()
 
       key 'up', 'componentViewer', =>
-        @options.app.controller.selectPreviousIssue()
+        @options.app.controller.selectPrev()
         false
 
       key 'down', 'componentViewer', =>
-        @options.app.controller.selectNextIssue()
+        @options.app.controller.selectNext()
         false
 
       key 'left', 'componentViewer', =>
@@ -88,7 +88,7 @@ define [
 
     select: ->
       selected = @options.app.state.get 'selectedIndex'
-      selectedIssue = @options.app.issues.at selected
+      selectedIssue = @options.app.list.at selected
       if selectedIssue.get('component') == @model.get('key')
         @scrollToIssue selectedIssue.get('key')
       else
@@ -99,7 +99,7 @@ define [
     getSelectedIssueEl: ->
       selected = @options.app.state.get 'selectedIndex'
       return null unless selected?
-      selectedIssue = @options.app.issues.at selected
+      selectedIssue = @options.app.list.at selected
       return null unless selectedIssue?
       selectedIssueView = @$("#issue-#{selectedIssue.get('key')}")
       if selectedIssueView.length > 0 then selectedIssueView else null
@@ -108,7 +108,7 @@ define [
     selectIssue: (e) ->
       key = $(e.currentTarget).data 'issue-key'
       issue = @issues.find (issue) -> issue.get('key') == key
-      index = @options.app.issues.indexOf issue
+      index = @options.app.list.indexOf issue
       @options.app.state.set selectedIndex: index
 
 
@@ -120,7 +120,7 @@ define [
       else
         @unbindShortcuts()
         selected = @options.app.state.get 'selectedIndex'
-        selectedIssue = @options.app.issues.at selected
+        selectedIssue = @options.app.list.at selected
         @options.app.controller.showComponentViewer selectedIssue
 
 
@@ -149,11 +149,11 @@ define [
 
 
     requestIssues: ->
-      if @options.app.issues.last().get('component') == @model.get('key')
+      if @options.app.list.last().get('component') == @model.get('key')
         r = @options.app.controller.fetchNextPage()
       else r = $.Deferred().resolve().promise()
       r.done =>
-        @issues.reset @options.app.issues.filter (issue) => issue.get('component') == @model.key()
+        @issues.reset @options.app.list.filter (issue) => issue.get('component') == @model.key()
         @issues.reset @limitIssues @issues
         @addIssuesPerLineMeta @issues
 
@@ -174,7 +174,7 @@ define [
 
     addNextIssuesPage: ->
       componentKey = @model.get 'key'
-      @issues.add @options.app.issues.filter (issue) => issue.get('component') == componentKey
+      @issues.add @options.app.list.filter (issue) => issue.get('component') == componentKey
 
 
     scrollToLine: (line) ->
index d937228a9e8c22691bf0047b8b6b51ab9f78e866..4bc75e7d472babccfc3277ab6859ddc10b738e28 100644 (file)
@@ -1,10 +1,10 @@
 define [
-  'backbone.marionette'
+  'components/navigator/controller'
 
   'issues/component-viewer/main'
   'issues/component-viewer/state'
 ], (
-  Marionette
+  Controller
 
   ComponentViewer
   ComponentViewerState
@@ -12,56 +12,33 @@ define [
 
   $ = jQuery
   EXTRA_FIELDS = 'actions,transitions,assigneeName,reporterName,actionPlanName'
-  PAGE_SIZE = 50
-  ALL_FACETS = ['severities', 'statuses', 'resolutions', 'projectUuids', 'moduleUuids', 'componentUuids', 'assignees', 'reporters', 'rules',
-                'tags', 'languages', 'actionPlans', 'creationDate', 'issues']
   FACET_DATA_FIELDS = ['components', 'projects', 'users', 'rules', 'actionPlans', 'languages']
-  FACETS_FROM_SERVER = ['severities', 'statuses', 'resolutions', 'actionPlans', 'projectUuids', 'rules', 'tags'
-                        'assignees', 'reporters', 'componentUuids', 'languages']
-  TRANSFORM = {
-    'resolved': 'resolutions'
-    'assigned': 'assignees'
-    'planned': 'actionPlans'
-    'createdAt': 'creationDate'
-    'createdBefore': 'creationDate'
-    'createdAfter': 'creationDate'
-  }
 
 
-  class extends Marionette.Controller
-
-    initialize: (options) ->
-      @listenTo options.app.state, 'change:query', @fetchIssues
-
+  class extends Controller
+    allFacets: ['severities', 'statuses', 'resolutions', 'projectUuids', 'moduleUuids', 'componentUuids', 'assignees',
+                'reporters', 'rules', 'tags', 'languages', 'actionPlans', 'creationDate', 'issues'],
+    facetsFromServer: ['severities', 'statuses', 'resolutions', 'actionPlans', 'projectUuids', 'rules', 'tags',
+                       'assignees', 'reporters', 'componentUuids', 'languages'],
+    transform: {
+      'resolved': 'resolutions'
+      'assigned': 'assignees'
+      'planned': 'actionPlans'
+      'createdAt': 'creationDate'
+      'createdBefore': 'creationDate'
+      'createdAfter': 'creationDate'
+    },
 
     _issuesParameters: ->
       p: @options.app.state.get 'page'
-      ps: PAGE_SIZE
+      ps: @pageSize
       s: 'FILE_LINE'
       asc: true
       extra_fields: EXTRA_FIELDS
       facets: @_facetsFromServer().join()
 
 
-    _allFacets: ->
-      ALL_FACETS.map (facet) -> { property: facet }
-
-
-    _enabledFacets: ->
-      facets = @options.app.state.get 'facets'
-      criteria = Object.keys @options.app.state.get 'query'
-      facets = facets.concat criteria
-      facets = facets.map (facet) ->
-        if TRANSFORM[facet]? then TRANSFORM[facet] else facet
-      facets.filter (facet) -> ALL_FACETS.indexOf(facet) != -1
-
-
-    _facetsFromServer: ->
-      facets = @_enabledFacets()
-      facets.filter (facet) -> FACETS_FROM_SERVER.indexOf(facet) != -1
-
-
-    fetchIssues: (firstPage = true) ->
+    fetchList: (firstPage = true) ->
       if firstPage
         @options.app.state.set { selectedIndex: 0, page: 1 }, { silent: true }
         @closeComponentViewer()
@@ -72,12 +49,12 @@ define [
       fetchIssuesProcess = window.process.addBackgroundProcess()
       $.get "#{baseUrl}/api/issues/search", data
       .done (r) =>
-        issues = @options.app.issues.parseIssues r
+        issues = @options.app.list.parseIssues r
         if firstPage
-          @options.app.issues.reset issues
+          @options.app.list.reset issues
         else
-          @options.app.issues.add issues
-        @options.app.issues.setIndex()
+          @options.app.list.add issues
+        @options.app.list.setIndex()
         FACET_DATA_FIELDS.forEach (field) => @options.app.facets[field] = r[field]
         @options.app.facets.reset @_allFacets()
         @options.app.facets.add r.facets, merge: true
@@ -92,11 +69,6 @@ define [
         window.process.failBackgroundProcess fetchIssuesProcess
 
 
-    fetchNextPage: ->
-      @options.app.state.nextPage()
-      @fetchIssues false
-
-
     fetchFilters: ->
       $.get "#{baseUrl}/api/issue_filters/app", (r) =>
         @options.app.state.set
@@ -105,35 +77,6 @@ define [
         @options.app.filters.reset r.favorites
 
 
-    enableFacet: (id) ->
-      facet = @options.app.facets.get id
-      if facet.has('values') || FACETS_FROM_SERVER.indexOf(id) == -1
-        facet.set enabled: true
-      else
-        p = window.process.addBackgroundProcess()
-        @requestFacet(id)
-        .done =>
-          facet.set enabled: true
-          window.process.finishBackgroundProcess p
-        .fail ->
-          window.process.failBackgroundProcess p
-
-
-    disableFacet: (id) ->
-      facet = @options.app.facets.get id
-      facet.set enabled: false
-      @options.app.facetsView.children.findByModel(facet).disable()
-
-
-    toggleFacet: (id) ->
-      facet = @options.app.facets.get id
-      if facet.get('enabled') then @disableFacet(id) else @enableFacet(id)
-
-
-    enableFacets: (facets) ->
-      facets.forEach @enableFacet, @
-
-
     _mergeCollections: (a, b) ->
       collection = new Backbone.Collection a
       collection.add b, merge: true
@@ -162,29 +105,17 @@ define [
       @options.app.state.set filter: filter, changed: false
 
 
-    parseQuery: (query, separator = '|') ->
-      q = {}
-      (query || '').split(separator).forEach (t) ->
-        tokens = t.split('=')
-        if tokens[0] && tokens[1]?
-          q[tokens[0]] = decodeURIComponent tokens[1]
+    parseQuery: ->
+      q = super
       # Do not allow to modify the sorting
       delete q.asc
       delete q.s
       q
 
 
-    getQuery: (separator = '|') ->
-      filter = @options.app.state.get 'query'
-      route = []
-      _.map filter, (value, property) ->
-        route.push "#{property}=#{encodeURIComponent value}"
-      route.join separator
-
-
-    getRoute: (separator = '|') ->
+    getRoute: ->
       filter = @options.app.state.get 'filter'
-      query = @getQuery separator
+      query = super
       if filter?
         if @options.app.state.get('changed') && query.length > 0
           query = "id=#{filter.id}|#{query}"
@@ -220,20 +151,5 @@ define [
       @options.app.layout.workspaceComponentViewerRegion.reset()
       @options.app.layout.hideComponentViewer()
       @options.app.issuesView.bindScrollEvents()
-      @options.app.issuesView.scrollToIssue()
-
-
-    selectNextIssue: ->
-      index = @options.app.state.get('selectedIndex') + 1
-      if index < @options.app.issues.length
-        @options.app.state.set selectedIndex: index
-      else
-        unless @options.app.state.get('maxResultsReached')
-          @fetchNextPage().done =>
-            @options.app.state.set selectedIndex: index
-
+      @options.app.issuesView.scrollTo()
 
-    selectPreviousIssue: ->
-      index = @options.app.state.get('selectedIndex') - 1
-      if index >= 0
-        @options.app.state.set selectedIndex: index
index b030690c29be5faca761c5bbe7b9d38b5a2e5194..78f0860d3d70c0800e15dc99363c1b26ee29d9a5 100644 (file)
@@ -1,5 +1,5 @@
 define [
-  'backbone.marionette'
+  'components/navigator/facets-view'
 
   'issues/facets/base-facet'
   'issues/facets/severity-facet'
@@ -17,7 +17,8 @@ define [
   'issues/facets/language-facet'
   'issues/facets/issue-key-facet'
 ], (
-  Marionette
+  FacetsView
+
   BaseFacet
   SeverityFacet
   StatusFacet
@@ -35,9 +36,7 @@ define [
   IssueKeyFacet
 ) ->
 
-  class extends Marionette.CollectionView
-    className: 'issues-facets-list'
-
+  class extends FacetsView
 
     getItemView: (model) ->
       switch model.get 'property'
@@ -56,17 +55,3 @@ define [
         when 'languages' then LanguageFacet
         when 'issues' then IssueKeyFacet
         else BaseFacet
-
-
-    itemViewOptions: ->
-      app: @options.app
-
-
-    collectionEvents: ->
-      'change:enabled': 'updateState'
-
-
-    updateState: ->
-      enabledFacets = @collection.filter (model) -> model.get('enabled')
-      enabledFacetIds = enabledFacets.map (model) -> model.id
-      @options.app.state.set facets: enabledFacetIds
index 6ecc3a387be72011a4f7d884fc0201f732ad48fd..4959fd2a72845f89a1c0865426e2006c627b7771 100644 (file)
@@ -17,7 +17,7 @@ define [
       super
       value = @options.app.state.get('query')['planned']
       if value? && (!value || value == 'false')
-        @$('.js-issues-facet').filter("[data-unplanned]").addClass 'active'
+        @$('.js-facet').filter("[data-unplanned]").addClass 'active'
 
 
     toggleFacet: (e) ->
index c2f1e99ac650eaeed764d447e815199d6215dcfd..43c48eb193d5feac3e72ef30c997dfd03a474969 100644 (file)
@@ -21,7 +21,7 @@ define [
       super
       value = @options.app.state.get('query')['assigned']
       if value? && (!value || value == 'false')
-        @$('.js-issues-facet').filter("[data-unassigned]").addClass 'active'
+        @$('.js-facet').filter("[data-unassigned]").addClass 'active'
 
 
     toggleFacet: (e) ->
@@ -54,7 +54,7 @@ define [
 
     addCustomValue: ->
       property = @model.get 'property'
-      customValue = @$('.js-issues-custom-value').select2 'val'
+      customValue = @$('.js-custom-value').select2 'val'
       value = @getValue()
       value += ',' if value.length > 0
       value += customValue
index b13643544b29eb34575123cc98f309e4b1ba1300..a9781dfcbe1719f8b0d1c1f8adf51d082833fd40 100644 (file)
@@ -1,69 +1,10 @@
 define [
-  'backbone.marionette'
+  'components/navigator/facets/base-facet'
   'templates/issues'
 ], (
-  Marionette
+  BaseFacet
   Templates
 ) ->
 
-  $ = jQuery
-
-
-  class extends Marionette.ItemView
-    className: 'issues-facet-box'
+  class extends BaseFacet
     template: Templates['issues-base-facet']
-
-
-    modelEvents: ->
-      'change': 'render'
-
-
-    events: ->
-      'click .js-issues-facet-toggle': 'toggle'
-      'click .js-issues-facet': 'toggleFacet'
-
-
-    onRender: ->
-      @$el.toggleClass 'issues-facet-box-collapsed', !@model.get('enabled')
-
-      property = @model.get 'property'
-      value = @options.app.state.get('query')[property]
-      if typeof value == 'string'
-        value.split(',').forEach (s) =>
-          facet = @$('.js-issues-facet').filter("[data-value='#{s}']")
-          if facet.length > 0
-            parent = facet.parent()
-            facet.addClass('active')#.detach().prependTo parent
-
-
-    toggle: ->
-      @options.app.controller.toggleFacet @model.id
-
-
-    getValue: ->
-      @$('.js-issues-facet.active').map(-> $(@).data 'value').get().join()
-
-
-    toggleFacet: (e) ->
-      $(e.currentTarget).toggleClass 'active'
-      property = @model.get 'property'
-      value = @getValue()
-      obj = {}
-      obj[property] = value
-      @options.app.state.updateFilter obj
-
-
-    disable: ->
-      property = @model.get 'property'
-      obj = {}
-      obj[property] = null
-      @options.app.state.updateFilter obj
-
-
-    sortValues: (values) ->
-      _.sortBy values, (v) -> -v.count
-
-
-    serializeData: ->
-      _.extend super,
-        values: @sortValues @model.getValues()
index 2fd4c8f53a6a7832fe8e29f43f2c5e804904fa09..21ed4e09a3d626eeddde7a6dea53f5187b522b88 100644 (file)
@@ -19,7 +19,7 @@ define [
 
 
     onRender: ->
-      @$el.toggleClass 'issues-facet-box-collapsed', !@model.get('enabled')
+      @$el.toggleClass 'search-navigator-facet-box-collapsed', !@model.get('enabled')
 
       @$('input').datepicker
         dateFormat: 'yy-mm-dd'
index 6a75a0cd776109100722d599f4cd38dc9981a90c..6712695e8f2bcc8fa6730ad0911fe23591932e63 100644 (file)
@@ -13,7 +13,7 @@ define [
 
     events: ->
       _.extend super,
-        'change .js-issues-custom-value': 'addCustomValue'
+        'change .js-custom-value': 'addCustomValue'
 
 
     getUrl: ->
@@ -42,7 +42,7 @@ define [
 
     addCustomValue: ->
       property = @model.get 'property'
-      customValue = @$('.js-issues-custom-value').select2 'val'
+      customValue = @$('.js-custom-value').select2 'val'
       value = @getValue()
       value += ',' if value.length > 0
       value += customValue
index b017d613157e23380e6a9c31b2815ca2401ebb9f..ed3bb7e5450db365e7e5984b438a4573fcefe1d5 100644 (file)
@@ -18,7 +18,7 @@ define [
 
       value = @options.app.state.get('query')['resolved']
       if value? && (!value || value == 'false')
-        @$('.js-issues-facet').filter("[data-unresolved]").addClass 'active'
+        @$('.js-facet').filter("[data-unresolved]").addClass 'active'
 
 
     toggleFacet: (e) ->
index c4db10359f9d37ab0af053485d27df9a9739fd65..ec4a576d8ec447498e2f9046c4097556c3c2e7a5 100644 (file)
@@ -12,7 +12,7 @@ define [
       languages = @options.app.state.get('query').languages
       if languages?
         url += "&languages=#{languages}"
-      @$('.js-issues-custom-value').select2
+      @$('.js-custom-value').select2
         placeholder: 'Search...'
         minimumInputLength: 2
         allowClear: false
index 159c016935650c3425526ef4e0e4e4de41375808..81b3c33f3f9f0bceb3ae70fc170cbfa0ef129787 100644 (file)
@@ -12,7 +12,7 @@ define [
       tags = @options.app.state.get('query').tags
       if tags?
         url += "&tags=#{tags}"
-      @$('.js-issues-custom-value').select2
+      @$('.js-custom-value').select2
         placeholder: 'Search...'
         minimumInputLength: 0
         allowClear: false
index 21d07786b85ce7a1d3a1176674a6a86a09394793..a1dfae26087a26e8daee6af136000b9e0d98fd3b 100644 (file)
@@ -14,13 +14,13 @@ define [
 
 
     events:
-      'click .js-issues-toggle-filters': 'toggleFilters'
-      'click .js-issues-filter': 'applyFilter'
-      'click #issues-new-search': 'newSearch'
-      'click #issues-filter-save-as': 'saveAs'
-      'click #issues-filter-save': 'save'
-      'click #issues-filter-copy': 'copy'
-      'click #issues-filter-edit': 'edit'
+      'click .js-toggle-filters': 'toggleFilters'
+      'click .js-filter': 'applyFilter'
+      'click .js-new-search': 'newSearch'
+      'click .js-filter-save-as': 'saveAs'
+      'click .js-filter-save': 'save'
+      'click .js-filter-copy': 'copy'
+      'click .js-filter-edit': 'edit'
 
 
     initialize: (options) ->
@@ -35,15 +35,15 @@ define [
 
 
     onRender: ->
-      @$el.toggleClass 'issues-filters-selected', @options.app.state.has('filter')
+      @$el.toggleClass 'search-navigator-filters-selected', @options.app.state.has('filter')
 
 
     toggleFilters: (e) ->
       e.stopPropagation()
-      @$('.issues-filters-list').toggle()
+      @$('.search-navigator-filters-list').toggle()
       $('body').on 'click.issues-filters', =>
         $('body').off 'click.issues-filters'
-        @$('.issues-filters-list').hide()
+        @$('.search-navigator-filters-list').hide()
 
 
     applyFilter: (e) ->
index a39d515384bc42df2431b37e379a45c124fbe8ab..85d06a2a3f1cea42adca480b5978d031df52d73b 100644 (file)
@@ -15,10 +15,10 @@ define [
 
 
     regions:
-      filtersRegion: '.issues-filters'
-      facetsRegion: '.issues-facets'
-      workspaceHeaderRegion: '.issues-workspace-header'
-      workspaceListRegion: '.issues-workspace-list'
+      filtersRegion: '.search-navigator-filters'
+      facetsRegion: '.search-navigator-facets'
+      workspaceHeaderRegion: '.search-navigator-workspace-header'
+      workspaceListRegion: '.search-navigator-workspace-list'
       workspaceComponentViewerRegion: '.issues-workspace-component-viewer'
 
 
@@ -31,13 +31,13 @@ define [
 
 
     onRender: ->
-      @$('.issues-side').isolatedScroll()
+      @$('.search-navigator-side').isolatedScroll()
 
 
     onScroll: ->
       scrollTop = $(window).scrollTop()
-      $('.issues').toggleClass 'sticky', scrollTop >= @topOffset
-      @$('.issues-side').css top: Math.max(0, Math.min(@topOffset - scrollTop, @topOffset))
+      $('.search-navigator').toggleClass 'sticky', scrollTop >= @topOffset
+      @$('.search-navigator-side').css top: Math.max(0, Math.min(@topOffset - scrollTop, @topOffset))
 
 
     showSpinner: (region) ->
index 49040ea3c79d7c31fc093916146d48adc70ea706..197104042dde2e7da926fb9f7d95a943163c5f4c 100644 (file)
@@ -1,48 +1,14 @@
 define [
-  'backbone'
+  'components/navigator/models/state'
 ], (
-  Backbone
+  State
 ) ->
 
-  class extends Backbone.Model
+  class extends State
 
     defaults:
       page: 1
       maxResultsReached: false
-
       query: {}
-
       facets: ['severities', 'statuses', 'resolutions']
 
-
-    nextPage: ->
-      page = @get 'page'
-      @set page: page + 1
-
-
-    cleanQuery: (query) ->
-      q = {}
-      Object.keys(query).forEach (key) ->
-        q[key] = query[key] if query[key]
-      q
-
-
-    _areQueriesEqual: (a, b) ->
-      equal = Object.keys(a).length == Object.keys(b).length
-      Object.keys(a).forEach (key) ->
-        equal = equal && (a[key] == b[key])
-      equal
-
-
-    updateFilter: (obj) ->
-      oldQuery = @get('query')
-      query = _.extend {}, oldQuery, obj
-      query = @cleanQuery query
-      @setQuery query unless @_areQueriesEqual oldQuery, query
-
-
-    setQuery: (query) ->
-      @set { query: query }, { silent: true }
-      @set changed: true
-      @trigger 'change:query'
-
index b85773f6c4343170dae2ec82b958cb3feced6234..79057861a9b5a79d178e039987d1ca607ced0629 100644 (file)
@@ -1,21 +1,18 @@
 define [
-  'backbone'
+  'components/navigator/router'
 ], (
-  Backbone
+  Router
 ) ->
 
-  class extends Backbone.Router
-    routeSeparator: '|'
-
+  class extends Router
     routes:
       '': 'emptyQuery'
       ':query': 'index'
 
 
     initialize: (options) ->
-      @options = options
-      @listenTo @options.app.state, 'change:query', @updateRoute
-      @listenTo @options.app.state, 'change:filter', @updateRoute
+      super
+      @listenTo options.app.state, 'change:filter', @updateRoute
 
 
     emptyQuery: ->
@@ -36,9 +33,3 @@ define [
             @options.app.controller.applyFilter filter
       else
         @options.app.state.setQuery query
-
-
-    updateRoute: ->
-      route = @options.app.controller.getRoute()
-      @navigate route
-
index ec225348f4727448e766acd4d5f19c51dade9518..696261ffab113e00e14b4e12b0aa659c74ea74f3 100644 (file)
@@ -1,36 +1,29 @@
 define [
-  'backbone.marionette'
+  'components/navigator/workspace-header-view'
   'templates/issues'
 ], (
-  Marionette
+  WorkspaceHeaderView
   Templates
 ) ->
 
   $ = jQuery
 
 
-  class extends Marionette.ItemView
+  class extends WorkspaceHeaderView
     template: Templates['issues-workspace-header']
 
 
-    collectionEvents:
-      'all': 'render'
-
-
-    events:
-      'click .js-back': 'returnToList'
-      'click #issues-bulk-change': 'bulkChange'
-      'click #issues-reload': 'reloadIssues'
-      'click .js-issues-next': 'selectNextIssue'
-      'click .js-issues-prev': 'selectPrevIssue'
+    events: ->
+      _.extend super,
+        'click .js-back': 'returnToList'
 
 
-    initialize: (options) ->
-      @listenTo options.app.state, 'change', @render
+    initialize: ->
+      super
       @_onBulkIssues = window.onBulkIssues
       window.onBulkIssues = =>
         $('#modal').dialog 'close'
-        @options.app.controller.fetchIssues()
+        @options.app.controller.fetchList()
 
 
     onClose: ->
@@ -45,21 +38,3 @@ define [
       query = @options.app.controller.getQuery '&'
       url = "#{baseUrl}/issues/bulk_change_form?#{query}"
       openModalWindow url, {}
-
-
-    reloadIssues: ->
-      @options.app.controller.fetchIssues()
-
-
-    selectNextIssue: ->
-      @options.app.controller.selectNextIssue()
-
-
-    selectPrevIssue: ->
-      @options.app.controller.selectPreviousIssue()
-
-
-    serializeData: ->
-      _.extend super,
-        state: @options.app.state.toJSON()
-
index f6514ea9ff9858182063f119b60965623c7e320b..f77d383a31adf25f517d63e387c7581266e30586 100644 (file)
@@ -5,7 +5,7 @@ define [
 ) ->
 
   class extends Marionette.ItemView
-    className: 'issues-no-results'
+    className: 'search-navigator-no-results'
 
 
     template: ->
index d81b015538ce525c389ea17143600386369b8ef7..2e91d9053d3dd0e6db5b2489a475473f5698044a 100644 (file)
@@ -14,13 +14,14 @@ define [
 
 
     initialize: (options) ->
+      super
       @listenTo options.app.state, 'change:selectedIndex', @select
 
 
     onRender: ->
       super
-      @$el.addClass 'issue-navigate-right'
       @select()
+      @$el.addClass 'issue-navigate-right'
 
 
     select: ->
index d52d55bf4d5d7f020de1f09cb0caafa4d9c278b2..7b139ff35b1b472249772ddf1a641bfe84c7adfa 100644 (file)
@@ -1,10 +1,10 @@
 define [
-  'backbone.marionette'
+  'components/navigator/workspace-list-view'
   'templates/issues'
   'issues/workspace-list-item-view'
   'issues/workspace-list-empty-view'
 ], (
-  Marionette
+  WorkspaceListView
   Templates
   IssueView
   EmptyView
@@ -17,50 +17,14 @@ define [
   BOTTOM_OFFSET = 10
 
 
-  class extends Marionette.CompositeView
+  class extends WorkspaceListView
     template: Templates['issues-workspace-list']
     componentTemplate: Templates['issues-workspace-list-component']
     itemView: IssueView
-    itemViewContainer: '.js-issues-list'
+    itemViewContainer: '.js-list'
     emptyView: EmptyView
 
 
-    ui:
-      loadMore: '.js-issues-more'
-
-
-    itemViewOptions: ->
-      app: @options.app
-
-
-    collectionEvents:
-      'reset': 'scrollToTop'
-
-
-    initialize: ->
-      @loadMoreThrottled = _.throttle @loadMore, 1000, { trailing: false }
-      @listenTo @options.app.state, 'change:maxResultsReached', @toggleLoadMore
-      @listenTo @options.app.state, 'change:selectedIndex', @scrollToIssue
-      @bindShortcuts()
-
-
-    onClose: ->
-      @unbindScrollEvents()
-      @unbindShortcuts()
-
-
-    toggleLoadMore: ->
-      @ui.loadMore.toggle !@options.app.state.get 'maxResultsReached'
-
-
-    bindScrollEvents: ->
-      $(window).on 'scroll.issues-workspace-list', (=> @onScroll())
-
-
-    unbindScrollEvents: ->
-      $(window).off 'scroll.issues-workspace-list'
-
-
     bindShortcuts: ->
       doTransition = (transition) =>
         selectedIssue = @collection.at @options.app.state.get 'selectedIndex'
@@ -74,13 +38,7 @@ define [
         selectedIssueView = @children.findByModel selectedIssue
         selectedIssueView.$(".js-issue-#{action}").click()
 
-      key 'up', 'list', =>
-        @options.app.controller.selectPreviousIssue()
-        false
-
-      key 'down', 'list', =>
-        @options.app.controller.selectNextIssue()
-        false
+      super
 
       key 'right,return', 'list', =>
         selectedIssue = @collection.at @options.app.state.get 'selectedIndex'
@@ -101,29 +59,7 @@ define [
       key 't', 'list', -> doAction 'edit-tags'
 
 
-    loadMore: ->
-      unless @options.app.state.get 'maxResultsReached'
-        @unbindScrollEvents()
-        @options.app.controller.fetchNextPage().done => @bindScrollEvents()
-
-
-    disablePointerEvents: ->
-      clearTimeout @scrollTimer
-      $('body').addClass 'disabled-pointer-events'
-      @scrollTimer = setTimeout (-> $('body').removeClass 'disabled-pointer-events'), 250
-
-
-    onScroll: ->
-      @disablePointerEvents()
-      if $(window).scrollTop() + $(window).height() >= @ui.loadMore.offset().top
-        @loadMoreThrottled()
-
-
-    scrollToTop: ->
-      @$el.scrollParent().scrollTop 0
-
-
-    scrollToIssue: ->
+    scrollTo: ->
       selectedIssue = @collection.at @options.app.state.get 'selectedIndex'
       return unless selectedIssue?
       selectedIssueView = @children.findByModel selectedIssue
diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-actions.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-actions.hbs
new file mode 100644 (file)
index 0000000..2b3d076
--- /dev/null
@@ -0,0 +1,18 @@
+<div class="navigator-actions-order">
+  {{#if sorting}}
+    {{t 'coding_rules.ordered_by'}} <strong>{{sorting.sortText}}</strong> {{#if sorting.asc}}<i class="icon-sort-asc"></i>{{else}}<i class="icon-sort-desc"></i>{{/if}}
+  {{else}}
+    {{t 'coding_rules.order'}}
+  {{/if}}
+</div>
+<ul class="navigator-actions-order-choices">
+  <li data-sort="" data-asc="">{{t 'coding_rules.sort.relevance'}}</li>
+  <li data-sort="createdAt" data-asc="true">{{t 'coding_rules.sort.creation_date'}} <i class="icon-sort-asc"></i></li>
+  <li data-sort="createdAt" data-asc="false">{{t 'coding_rules.sort.creation_date'}} <i class="icon-sort-desc"></i></li>
+  <li data-sort="name" data-asc="true">{{t 'coding_rules.sort.name'}} <i class="icon-sort-asc"></i></li>
+  <li data-sort="name" data-asc="false">{{t 'coding_rules.sort.name'}} <i class="icon-sort-desc"></i></li>
+</ul>
+<div class="navigator-actions-total">
+  {{t 'coding_rules.found'}}: <strong>{{paging.total}}</strong>
+  {{#if canWrite}}<a class="navigator-actions-bulk icon-bulk-change" title="{{t 'bulk_change'}}"></a>{{/if}}
+</div>
diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-bulk-change-dropdown.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-bulk-change-dropdown.hbs
new file mode 100644 (file)
index 0000000..3fcb25b
--- /dev/null
@@ -0,0 +1,25 @@
+{{! activation }}
+
+<a class="coding-rules-bulk-change-dropdown-link" data-action="activate">
+  {{t 'coding_rules.activate_in'}}&#8230;
+</a>
+
+{{#if allowActivateOnProfile}}
+  <a class="coding-rules-bulk-change-dropdown-link" data-action="activate" data-param="{{qualityProfile}}">
+    {{t 'coding_rules.activate_in'}} <strong>{{qualityProfileName}}</strong>
+  </a>
+{{/if}}
+
+
+
+{{! deactivation }}
+
+<a class="coding-rules-bulk-change-dropdown-link" data-action="deactivate">
+  {{t 'coding_rules.deactivate_in'}}&#8230;
+</a>
+
+{{#if allowDeactivateOnProfile}}
+  <a class="coding-rules-bulk-change-dropdown-link" data-action="deactivate" data-param="{{qualityProfile}}">
+    {{tp 'coding_rules.deactivate_in'}} <strong>{{qualityProfileName}}</strong>
+  </a>
+{{/if}}
diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-bulk-change.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-bulk-change.hbs
new file mode 100644 (file)
index 0000000..441222f
--- /dev/null
@@ -0,0 +1,40 @@
+<form>
+  <div class="modal-head">
+    {{#eq action 'activate'}}
+      <h2>{{t 'coding_rules.activate_in_quality_profile'}} ({{paging.total}} {{t 'coding_rules._rules'}})</h2>
+    {{/eq}}
+    {{#eq action 'deactivate'}}
+      <h2>{{t 'coding_rules.deactivate_in_quality_profile'}} ({{paging.total}} {{t 'coding_rules._rules'}})</h2>
+    {{/eq}}
+  </div>
+
+  <div class="modal-body modal-body-select2">
+    <div class="modal-error"></div>
+    <div class="modal-warning"></div>
+    <div class="modal-notice"></div>
+
+    <div class="modal-field">
+      <h3><label for="coding-rules-bulk-change-profile">
+        {{#eq action 'change-severity'}}{{t 'coding_rules.change_severity_in'}}{{/eq}}
+        {{#eq action 'activate'}}{{t 'coding_rules.activate_in'}}{{/eq}}
+        {{#eq action 'deactivate'}}{{t 'coding_rules.deactivate_in'}}{{/eq}}
+      </label></h3>
+      {{#if qualityProfile}}
+        <h3 class="readonly-field">{{qualityProfileName}}{{#notEq action 'change-severity'}} â€”
+          {{t 'are_you_sure'}}{{/notEq}}</h3>
+      {{else}}
+        <select id="coding-rules-bulk-change-profile">
+          {{#each availableQualityProfiles}}
+            <option value="{{key}}">{{name}} - {{language}}</option>
+          {{/each}}
+        </select>
+      {{/if}}
+    </div>
+  </div>
+
+  <div class="modal-foot">
+    <button id="coding-rules-submit-bulk-change">{{t 'apply'}}</button>
+    <a id="coding-rules-cancel-bulk-change" class="action">{{t 'cancel'}}</a>
+    <a id="coding-rules-close-bulk-change" class="action" style="display:none" href="#">{{t 'close'}}</a>
+  </div>
+</form>
diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-custom-rule-creation.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-custom-rule-creation.hbs
new file mode 100644 (file)
index 0000000..c1244ff
--- /dev/null
@@ -0,0 +1,86 @@
+<form>
+  <div class="modal-head">
+    {{#if change}}
+      <h2>{{t 'coding_rules.update_custom_rule'}}</h2>
+    {{else}}
+      <h2>{{t 'coding_rules.create_custom_rule'}}</h2>
+    {{/if}}
+  </div>
+
+  <div class="modal-body">
+    <div class="modal-error"></div>
+    <div class="modal-warning">{{t 'coding_rules.reactivate.help'}}</div>
+
+    <table>
+      <tr class="property">
+        <th><h3>{{t 'name'}} <em class="mandatory">*</em></h3></th>
+        <td>
+          <input type="text" name="name" id="coding-rules-custom-rule-creation-name"
+            class="coding-rules-name-key" value="{{name}}"/>
+        </td>
+      </tr>
+      <tr class="property">
+        <th><h3>{{t 'key'}}{{#unless change}} <em class="mandatory">*</em>{{/unless}}</h3></th>
+        <td>
+          {{#if change}}
+            <span class="coding-rules-detail-custom-rule-key" title="{{key}}">{{key}}</span>
+          {{else}}
+            <input type="text" name="key" id="coding-rules-custom-rule-creation-key"
+              class="coding-rules-name-key" value="{{internalKey}}"/>
+          {{/if}}
+        </td>
+      </tr>
+      <tr class="property">
+        <th><h3>{{t 'description'}} <em class="mandatory">*</em></h3></th>
+        <td>
+          <textarea type="textarea" name="markdown_description" id="coding-rules-custom-rule-creation-html-description"
+            class="coding-rules-markdown-description" rows="15">{{{mdDesc}}}</textarea>
+          <span class="right">{{> '_markdown-tips' }}</span>
+        </td>
+      </tr>
+      <tr class="property">
+        <th><h3>{{t 'severity'}}</h3></th>
+        <td>
+          <select id="coding-rules-custom-rule-creation-severity">
+            {{#each severities}}
+              <option value="{{this}}">{{t 'severity' this}}</option>
+            {{/each}}
+          </select>
+        </td>
+      </tr>
+      <tr class="property">
+        <th><h3>{{t 'coding_rules.filters.status'}}</h3></th>
+        <td>
+          <select id="coding-rules-custom-rule-creation-status">
+            {{#each statuses}}
+              <option value="{{id}}">{{text}}</option>
+            {{/each}}
+          </select>
+        </td>
+      </tr>
+      {{#each params}}
+        <tr class="property">
+          <th><h3>{{key}}</h3></th>
+          <td>
+            {{#eq type 'TEXT'}}
+              <textarea class="width100" rows="3" name="{{key}}" placeholder="{{defaultValue}}">{{value}}</textarea>
+            {{else}}
+              <input type="text" name="{{key}}" value="{{value}}" placeholder="{{defaultValue}}"/>
+            {{/eq}}
+            <div class="note">{{htmlDesc}}</div>
+            {{#if extra}}
+              <div class="note">{{extra}}</div>
+            {{/if}}
+          </td>
+        </tr>
+      {{/each}}
+    </table>
+  </div>
+
+  <div class="modal-foot">
+    <button id="coding-rules-custom-rule-creation-create">
+      {{#if change}}{{t 'save'}}{{else}}{{t 'create'}}{{/if}}
+    </button>
+    <a id="coding-rules-custom-rule-creation-cancel" class="action">{{t 'cancel'}}</a>
+  </div>
+</form>
diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-custom-rule-reactivation.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-custom-rule-reactivation.hbs
new file mode 100644 (file)
index 0000000..2de07a6
--- /dev/null
@@ -0,0 +1,7 @@
+<button id="coding-rules-custom-rule-creation-reactivate">
+  {{t 'coding_rules.reactivate'}}
+</button>
+<button id="coding-rules-custom-rule-creation-create">
+  {{#if change}}{{t 'save'}}{{else}}{{t 'create'}}{{/if}}
+</button>
+<a id="coding-rules-custom-rule-creation-cancel" class="action">{{t 'cancel'}}</a>
diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-debt-popup.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-debt-popup.hbs
new file mode 100644 (file)
index 0000000..4c3b81c
--- /dev/null
@@ -0,0 +1,28 @@
+<div class="coding-rules-debt-popup bubble-popup-container">
+  <ul class="bubble-popup-list">
+    {{#if debtRemFnType}}
+    <li>
+      <h3>{{t 'coding_rules.remediation_function'}}</h3>
+      {{t 'coding_rules.remediation_function' debtRemFnType}}
+    </li>
+    {{/if}}
+    {{#if debtRemFnCoeff}}
+    <li>
+      <h3>{{t 'coding_rules.remediation_function.coeff'}}</h3>
+      {{debtRemFnCoeff}}
+    </li>
+    {{/if}}
+    {{#if debtRemFnOffset}}
+    <li>
+      <h3>{{#eq debtRemFnType 'CONSTANT_ISSUE'}}
+        {{t 'coding_rules.remediation_function.constant'}}
+        {{else}}
+        {{t 'coding_rules.remediation_function.offset'}}
+        {{/eq}}
+      </h3>
+      {{debtRemFnOffset}}
+    </li>
+    {{/if}}
+</div>
+
+<div class="bubble-popup-arrow"></div>
diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-detail-custom-rule.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-detail-custom-rule.hbs
new file mode 100644 (file)
index 0000000..8bd8ba0
--- /dev/null
@@ -0,0 +1,26 @@
+<td class="coding-rules-detail-custom-rule-name">
+  <a class="nolink" href="#rule_key={{key}}">{{name}}</a>
+</td>
+
+<td class="coding-rules-detail-custom-rule-severity">
+  {{severityIcon severity}} {{t "severity" severity}}
+</td>
+
+<td class="coding-rules-detail-custom-rule-parameters">
+  {{#each parameters}}
+    <div class="coding-rules-detail-custom-rule-parameter">
+      <span class="key">{{key}}</span><span class="sep">:&nbsp;</span><span class="value" title="{{value}}">{{value}}</span>
+    </div>
+  {{/each}}
+  &nbsp;
+</td>
+
+{{#if canWrite}}
+<td class="coding-rules-detail-custom-rule-actions">
+  <div class="button-group">
+    <button class="coding-rules-detail-custom-rule-delete button-red">
+      {{t 'delete'}}
+    </button>
+  </div>
+</td>
+{{/if}}
diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-detail-quality-profile.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-detail-quality-profile.hbs
new file mode 100644 (file)
index 0000000..9f398ea
--- /dev/null
@@ -0,0 +1,77 @@
+<table class="width100">
+  <tbody>
+  <tr>
+    <td class="coding-rules-detail-quality-profile-name">
+      {{name}}
+      {{#if parent}}
+        <div class="coding-rules-detail-quality-profile-inheritance">
+          {{#eq inherit 'OVERRIDES'}}
+            <i class="icon-inheritance" title="{{tp 'coding_rules.overrides' name parent.name}}"></i>
+          {{/eq}}
+          {{#eq inherit 'INHERITED'}}
+            <i class="icon-inheritance" title="{{tp 'coding_rules.inherits' name parent.name}}"></i>
+          {{/eq}}
+          {{parent.name}}
+        </div>
+      {{/if}}
+    </td>
+
+    {{#if severity}}
+      <td class="coding-rules-detail-quality-profile-severity">
+        {{severityIcon severity}} {{t "severity" severity}}
+        {{#if parent}}{{#notEq severity parent.severity}}
+          <div class="coding-rules-detail-quality-profile-inheritance">
+            {{t 'coding_rules.original'}}&nbsp;{{t 'severity' parent.severity}}
+          </div>
+        {{/notEq}}{{/if}}
+      </td>
+
+      {{#unless templateKey}}
+      <td class="coding-rules-detail-quality-profile-parameters">
+        {{#each parameters}}
+          <div class="coding-rules-detail-quality-profile-parameter">
+            <span class="key">{{key}}</span><span class="sep">:&nbsp;</span><span class="value" title="{{value}}">{{value}}</span>
+            {{#if ../parent}}{{#notEq value original}}
+              <div class="coding-rules-detail-quality-profile-inheritance">
+                {{t 'coding_rules.original'}}&nbsp;<span class="value">{{original}}</span>
+              </div>
+            {{/notEq}}{{/if}}
+          </div>
+        {{/each}}
+        &nbsp;
+      </td>
+      {{/unless}}
+
+      {{#if canWrite}}
+      <td class="coding-rules-detail-quality-profile-actions">
+        <div class="button-group">
+          {{#unless isTemplate}}
+            <button class="coding-rules-detail-quality-profile-change">{{t 'change_verb'}}</button>
+          {{/unless}}
+          {{#if parent}}
+            {{#eq inherit 'OVERRIDES'}}
+            <button class="coding-rules-detail-quality-profile-revert button-red">
+              {{t 'coding_rules.revert_to_parent_definition'}}
+            </button>
+            {{/eq}}
+          {{else}}
+            <button class="coding-rules-detail-quality-profile-deactivate button-red">
+              {{t 'coding_rules.deactivate'}}
+            </button>
+          {{/if}}
+        </div>
+      </td>
+      {{/if}}
+
+    {{else}}
+      {{#if canWrite}}{{#unless isTemplate}}
+      <td class="coding-rules-detail-quality-profile-actions">
+        <div class="button-group">
+          <button class="coding-rules-detail-quality-profile-activate">{{t 'coding_rules.activate'}}</button>
+        </div>
+      </td>
+      {{/unless}}{{/if}}
+    {{/if}}
+  </tr>
+  </tbody>
+</table>
diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-detail.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-detail.hbs
new file mode 100644 (file)
index 0000000..7da3581
--- /dev/null
@@ -0,0 +1,166 @@
+<div class="coding-rules-detail-context"></div>
+
+<h3 class="coding-rules-detail-header">
+  {{name}}
+  <a class="coding-rules-detail-permalink" href="#rule_key={{key}}">
+    <i class="icon-link"></i> {{t 'coding_rules.permalink'}}
+  </a>
+</h3>
+<span class="subtitle">{{key}}</span>
+
+<ul class="coding-rules-detail-properties">
+  {{#unless isManual}}
+    <li class="coding-rules-detail-property">{{severityIcon severity}} {{t "severity" severity}}</li>
+  {{/unless}}
+  {{#notEq status 'READY'}}
+    <li class="coding-rules-detail-property">
+      <span class="coding-rules-detail-status coding-rules-detail-not-ready">{{status}}</span>
+    </li>
+  {{/notEq}}
+
+
+  <li class="coding-rules-detail-property coding-rules-detail-tag-list {{#if canWrite}}coding-rules-detail-tags-change{{/if}}">
+    <i class="icon-tags"></i>
+    <span>{{#if allTags}}{{join allTags ', '}}{{else}}{{t 'coding_rules.no_tags'}}{{/if}}</span>
+  </li>
+  {{#if canWrite}}<li class="coding-rules-detail-property coding-rules-detail-tag-edit">
+    {{#if sysTags}}<i class="icon-tags"></i>
+    <span>{{join sysTags ', '}}</span>{{/if}}
+    <input class="coding-rules-detail-tag-input" type="text" value="{{#if tags}}{{join tags ','}}{{/if}}">
+
+    <div class="button-group">
+      <button class="coding-rules-detail-tag-edit-done">{{t 'Done'}}</button>
+    </div>
+    <a class="coding-rules-details-tag-edit-cancel">{{t 'cancel'}}</a>
+  </li>{{/if}}
+
+  {{#if subcharacteristic}}
+    <li class="coding-rules-detail-property coding-rules-subcharacteristic">{{subcharacteristic}}</li>
+  {{/if}}
+  <li class="coding-rules-detail-property">{{t 'coding_rules.available_since'}} {{d createdAt}}</li>
+  <li class="coding-rules-detail-property">{{repository}}{{#unless isManual}} ({{language}}){{/unless}}</li>
+
+  {{#if isTemplate}}
+    <li class="coding-rules-detail-property" title="{{t 'coding_rules.rule_template.title'}}">{{t 'coding_rules.rule_template'}}</li>
+  {{/if}}
+  {{#if templateKey}}
+    <li class="coding-rules-detail-property" title="{{t 'coding_rules.custom_rule.title'}}">{{t 'coding_rules.custom_rule'}}
+      (<a href="#rule_key={{templateKey}}">{{t 'coding_rules.show_template'}}</a>)
+    </li>
+  {{/if}}
+</ul>
+
+<div class="coding-rules-detail-description rule-desc markdown">{{{htmlDesc}}}</div>
+
+{{#unless isEditable}}
+  {{#unless isManual}}
+  <div class="coding-rules-detail-description coding-rules-detail-description-extra">
+    <div id="coding-rules-detail-description-extra">
+      {{#if htmlNote}}
+        <div class="rule-desc marginbottom10 markdown">{{{htmlNote}}}</div>{{/if}}
+      {{#if canWrite}}<div class="button-group">
+        <button id="coding-rules-detail-extend-description">{{t 'coding_rules.extend_description'}}</button>
+      </div>{{/if}}
+    </div>
+
+    {{#if canWrite}}<div class="coding-rules-detail-extend-description-form">
+      <table class="width100">
+        <tbody>
+        <tr>
+          <td class="width100" colspan="2">
+            <textarea id="coding-rules-detail-extend-description-text" rows="4"
+                      style="width: 100%; margin-bottom: 4px;">{{mdNote}}</textarea>
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <div class="button-group">
+              <button id="coding-rules-detail-extend-description-submit">{{t 'save'}}</button>
+              {{#if mdNote}}
+              <button id="coding-rules-detail-extend-description-remove" class="button-red">{{t 'remove'}}</button>
+              {{/if}}
+            </div>
+            <a id="coding-rules-detail-extend-description-cancel" class="action">{{t 'cancel'}}</a>
+          </td>
+          <td class="right">
+            {{> '_markdown-tips' }}
+          </td>
+        </tr>
+        </tbody>
+      </table>
+    </div>
+
+    <div id="coding-rules-detail-extend-description-spinner">
+      <i class="spinner"></i>
+    </div>{{/if}}
+  </div>
+  {{/unless}}
+{{/unless}}
+
+
+{{#if params}}
+  <h3 class="coding-rules-detail-title">{{t 'coding_rules.parameters'}}</h3>
+  <div class="coding-rules-detail-parameters">
+    {{#each params}}
+    <dl class="coding-rules-detail-parameter">
+      <dt class="coding-rules-detail-parameter-name">{{key}}</dt>
+      <dd class="coding-rules-detail-parameter-description" data-key="{{key}}">
+        <p>{{{htmlDesc}}}</p>
+        {{#if ../../templateKey}}
+        <div class="subtitle">
+          {{#if defaultValue }}
+            <span class="value">{{defaultValue}}</span>
+          {{else}}
+            {{t 'coding_rules.parameter.empty'}}
+          {{/if}}
+        </div>
+        {{else}}
+          {{#if defaultValue}}
+          <div class="subtitle">{{t 'coding_rules.parameters.default_value'}} <span class="value">{{defaultValue}}</span></div>
+          {{/if}}
+        {{/if}}
+      </dd>
+    </dl>
+    {{/each}}
+  </div>
+{{/if}}
+
+{{#if isEditable}}
+  <div class="coding-rules-detail-description">
+    <div class="button-group">
+      {{#if isManual}}
+        <button id="coding-rules-detail-manual-rule-change">{{t 'edit'}}</button>
+      {{else}}
+        <button id="coding-rules-detail-custom-rule-change">{{t 'edit'}}</button>
+      {{/if}}
+      <button id="coding-rules-detail-rule-delete" class="button-red">{{t 'delete'}}</button>
+    </div>
+  </div>
+{{/if}}
+
+
+{{#if isTemplate}}
+<div class="coding-rules-detail-custom-rules-section">
+  <h3 class="coding-rules-detail-title">{{t 'coding_rules.custom_rules'}}</h3>
+
+  {{#if canWrite}}<div class="button-group coding-rules-detail-quality-profiles-activation">
+    <button id="coding-rules-custom-rules-create">{{t 'coding_rules.create'}}</button>
+  </div>{{/if}}
+  <div id="coding-rules-detail-custom-rules"></div>
+</div>
+{{/if}}
+
+
+{{#if qualityProfilesVisible}}
+<div class="coding-rules-detail-quality-profiles-section">
+  <h3 class="coding-rules-detail-title">{{t 'coding_rules.quality_profiles'}}</h3>
+
+  {{#if canWrite}}{{#unless isTemplate}}<div class="button-group coding-rules-detail-quality-profiles-activation">
+    <button id="coding-rules-quality-profile-activate">{{t 'coding_rules.activate'}}</button>
+  </div>{{/unless}}{{/if}}
+  {{#if isTemplate}}
+  <div class="coding-rules-detail-quality-profiles-template-caption warning">{{t 'coding_rules.quality_profiles.template_caption'}}</div>
+  {{/if}}
+  <div id="coding-rules-detail-quality-profiles"></div>
+</div>
+{{/if}}
diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-facets.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-facets.hbs
new file mode 100644 (file)
index 0000000..c274fff
--- /dev/null
@@ -0,0 +1,26 @@
+<div class="navigator-facets-list">
+  {{#unless items}}
+  {{t 'coding_rules.no_results'}}
+  {{/unless}}
+  {{#each items}}
+    <div class="navigator-facets-list-item" data-property="{{property}}">
+      <div class="navigator-facets-list-item-name">
+        {{#if limitReached}}
+          {{tp 'coding_rules.facets.top' property_message}}
+        {{else}}
+          {{property_message}}
+        {{/if}}
+      </div>
+      <div class="navigator-facets-list-item-options">
+        {{#each values}}
+          {{#if count}}
+          <a class="facet" data-key="{{val}}" data-property="{{../property}}">
+            <span class="facet-name">{{text}}</span>
+            <span class="facet-stat">{{count}}</span>
+          </a>
+          {{/if}}
+        {{/each}}
+      </div>
+    </div>
+  {{/each}}
+</div>
diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-filter-bar.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-filter-bar.hbs
new file mode 100644 (file)
index 0000000..2e0f52a
--- /dev/null
@@ -0,0 +1,2 @@
+<div class="navigator-filters-list"></div>
+<button class="navigator-filter-submit">{{t 'search_verb'}}</button>
\ No newline at end of file
diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-header.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-header.hbs
new file mode 100644 (file)
index 0000000..6f539db
--- /dev/null
@@ -0,0 +1,6 @@
+<h1 class="navigator-header-title">{{t 'coding_rules.page'}}</h1>
+
+<div class="navigator-header-actions button-group">
+  <button id="coding-rules-new-search">{{t 'coding_rules.new_search'}}</button>
+  {{#if canWrite}}<button id="coding-rules-create-rule">{{t 'coding_rules.create'}}</button>{{/if}}
+</div>
diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-layout.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-layout.hbs
new file mode 100644 (file)
index 0000000..d824a27
--- /dev/null
@@ -0,0 +1,16 @@
+<div class="navigator-header"></div>
+<div class="navigator-filters"></div>
+<div class="navigator-facets"></div>
+
+<div class="navigator-content">
+  <div class="navigator-side">
+    <div style="position:relative; overflow: visible; height: 100%;">
+      <div class="navigator-actions"></div>
+      <div class="navigator-results"></div>
+      <a class="navigator-resizer"><i class="icon-resizer"></i></a>
+    </div>
+  </div>
+  <div class="navigator-main">
+    <div class="navigator-details"></div>
+  </div>
+</div>
\ No newline at end of file
diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-list-empty.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-list-empty.hbs
new file mode 100644 (file)
index 0000000..75e2daf
--- /dev/null
@@ -0,0 +1 @@
+{{t 'coding_rules.no_results'}}
\ No newline at end of file
diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-list-item.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-list-item.hbs
new file mode 100644 (file)
index 0000000..a4244ac
--- /dev/null
@@ -0,0 +1,19 @@
+<div class="line line-small">
+  <span class="coding-rules-detail-status">{{default language manualRuleLabel}}</span>
+
+  {{#if allTags}}
+    &nbsp;&nbsp;
+    <span class="coding-rules-list-tags">
+      <i class="icon-tags"></i>
+      <span>{{join allTags ', '}}</span>
+    </span>
+  {{/if}}
+
+  {{#notEq status 'READY'}}
+    <div class="line-right">
+      <span class="coding-rules-detail-not-ready">{{status}}</span>
+    </div>
+  {{/notEq}}
+</div>
+
+<div class="line" title="{{name}}" name="{{key}}">{{name}}</div>
diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-manual-rule-creation.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-manual-rule-creation.hbs
new file mode 100644 (file)
index 0000000..389dd69
--- /dev/null
@@ -0,0 +1,50 @@
+<form>
+  <div class="modal-head">
+    {{#if change}}
+      <h2>{{t 'coding_rules.update_manual_rule'}}</h2>
+    {{else}}
+      <h2>{{t 'coding_rules.create_manual_rule'}}</h2>
+    {{/if}}
+  </div>
+
+  <div class="modal-body">
+    <div class="modal-error"></div>
+    <div class="modal-warning">{{t 'coding_rules.reactivate.help'}}</div>
+
+    <table>
+      <tr class="property">
+        <th><h3>{{t 'name'}} <em class="mandatory">*</em></h3></th>
+        <td>
+          <input type="text" name="name" id="coding-rules-manual-rule-creation-name"
+            class="coding-rules-name-key" value="{{name}}"/>
+        </td>
+      </tr>
+      <tr class="property">
+        <th><h3>{{t 'key'}}{{#unless change}} <em class="mandatory">*</em>{{/unless}}</h3></th>
+        <td>
+          {{#if change}}
+            {{key}}
+          {{else}}
+            <input type="text" name="key" id="coding-rules-manual-rule-creation-key"
+              class="coding-rules-name-key" value="{{internalKey}}"/>
+          {{/if}}
+        </td>
+      </tr>
+      <tr class="property">
+        <th><h3>{{t 'description'}} <em class="mandatory">*</em></h3></th>
+        <td>
+          <textarea type="textarea" name="markdown_description" id="coding-rules-manual-rule-creation-html-description"
+            class="coding-rules-markdown-description" rows="15">{{{mdDesc}}}</textarea>
+          <span class="right">{{> '_markdown-tips' }}</span>
+        </td>
+      </tr>
+    </table>
+  </div>
+
+  <div class="modal-foot">
+    <button id="coding-rules-manual-rule-creation-create">
+      {{#if change}}{{t 'save'}}{{else}}{{t 'create'}}{{/if}}
+    </button>
+    <a id="coding-rules-manual-rule-creation-cancel" class="action">{{t 'cancel'}}</a>
+  </div>
+</form>
diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-manual-rule-reactivation.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-manual-rule-reactivation.hbs
new file mode 100644 (file)
index 0000000..2410c7f
--- /dev/null
@@ -0,0 +1,7 @@
+<button id="coding-rules-manual-rule-creation-reactivate">
+  {{t 'coding_rules.reactivate'}}
+</button>
+<button id="coding-rules-manual-rule-creation-create">
+  {{#if change}}{{t 'save'}}{{else}}{{t 'create'}}{{/if}}
+</button>
+<a id="coding-rules-manual-rule-creation-cancel" class="action">{{t 'cancel'}}</a>
diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-parameter-popup.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-parameter-popup.hbs
new file mode 100644 (file)
index 0000000..0299ced
--- /dev/null
@@ -0,0 +1,12 @@
+<div class="coding-rules-parameter-full-description bubble-popup-container">
+  <div class="bubble-popup-title">{{key}}</div>
+
+    {{{htmlDesc}}}
+    {{#if defaultValue}}
+      <div>
+        {{t 'coding_rules.parameters.default_value'}} {{defaultValue}}
+      </div>
+    {{/if}}
+</div>
+
+<div class="bubble-popup-arrow"></div>
diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-profile-filter-detail.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-profile-filter-detail.hbs
new file mode 100644 (file)
index 0000000..3a3b44c
--- /dev/null
@@ -0,0 +1,16 @@
+<li>
+  <label title="{{id}}" data-id="{{id}}">
+    <span>
+      <i class="icon-checkbox {{#if checked}}icon-checkbox-checked{{/if}} {{#unless multiple}}icon-checkbox-single{{/unless}}"></i>
+      {{text}}
+    </span>
+
+    {{#if language}}
+      <br>
+      <span>
+        <i class="icon-checkbox icon-checkbox-invisible"></i>
+        <span class="subtitle">{{language}}</span>
+      </span>
+    {{/if}}
+  </label>
+</li>
diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-quality-profile-activation.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-quality-profile-activation.hbs
new file mode 100644 (file)
index 0000000..e407448
--- /dev/null
@@ -0,0 +1,76 @@
+<form>
+  <div class="modal-head">
+    {{#if change}}
+      <h2>{{t 'coding_rules.change_details'}}</h2>
+    {{else}}
+      <h2>{{t 'coding_rules.activate_in_quality_profile'}}</h2>
+    {{/if}}
+  </div>
+
+  <div class="modal-body modal-body-select2">
+    <div class="modal-error"></div>
+
+    <table>
+      <tr class="property">
+        <th><h3>{{t 'coding_rules.quality_profile'}}</h3></th>
+        <td>
+          {{#if key}}
+            {{name}}
+          {{else}}
+            <select id="coding-rules-quality-profile-activation-select">
+              {{#each qualityProfiles}}
+                <option value="{{key}}">{{name}}</option>
+              {{/each}}
+            </select>
+          {{/if}}
+        </td>
+      </tr>
+      <tr class="property">
+        <th><h3>{{t 'severity'}}</h3></th>
+        <td>
+          <select id="coding-rules-quality-profile-activation-severity">
+            {{#each severities}}
+              <option value="{{this}}">{{t 'severity' this}}</option>
+            {{/each}}
+          </select>
+        </td>
+      </tr>
+      {{#if isCustomRule}}
+      <tr class="property">
+        <td colspan="2" class="note">{{t 'coding_rules.custom_rule.activation_notice'}}</td>
+      {{else}}
+      {{#each params}}
+        <tr class="property">
+          <th><h3>{{key}}</h3></th>
+          <td>
+            {{#eq type 'TEXT'}}
+              <textarea class="width100" rows="3" name="{{key}}" placeholder="{{defaultValue}}">{{value}}</textarea>
+            {{else}}
+              {{#eq type 'BOOLEAN'}}
+              <select name="{{key}}" value="{{value}}">
+                <option value="{{defaultValue}}">{{t 'default'}} ({{t defaultValue}})</option>
+                <option value="true"{{#eq value 'true'}} selected="selected"{{/eq}}>{{t 'true'}}</option>
+                <option value="false"{{#eq value 'false'}} selected="selected"{{/eq}}>{{t 'false'}}</option>
+              </select>
+              {{else}}
+              <input type="text" name="{{key}}" value="{{value}}" placeholder="{{defaultValue}}">
+              {{/eq}}
+            {{/eq}}
+            <div class="note">{{description}}</div>
+            {{#if extra}}
+              <div class="note">{{extra}}</div>
+            {{/if}}
+          </td>
+        </tr>
+      {{/each}}
+      {{/if}}
+    </table>
+  </div>
+
+  <div class="modal-foot">
+    <button id="coding-rules-quality-profile-activation-activate" {{#unless saveEnabled}}disabled="disabled"{{/unless}}>
+      {{#if change}}{{t 'save'}}{{else}}{{t 'coding_rules.activate'}}{{/if}}
+    </button>
+    <a id="coding-rules-quality-profile-activation-cancel" class="action">{{t 'cancel'}}</a>
+  </div>
+</form>
diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-query-filter.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-query-filter.hbs
new file mode 100644 (file)
index 0000000..392a690
--- /dev/null
@@ -0,0 +1,3 @@
+<input type="text"
+  size="{{size}}" name="{{property}}" value="{{value}}"
+  class="query-filter-input"/>
diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-repository-detail.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-repository-detail.hbs
new file mode 100644 (file)
index 0000000..3a3b44c
--- /dev/null
@@ -0,0 +1,16 @@
+<li>
+  <label title="{{id}}" data-id="{{id}}">
+    <span>
+      <i class="icon-checkbox {{#if checked}}icon-checkbox-checked{{/if}} {{#unless multiple}}icon-checkbox-single{{/unless}}"></i>
+      {{text}}
+    </span>
+
+    {{#if language}}
+      <br>
+      <span>
+        <i class="icon-checkbox icon-checkbox-invisible"></i>
+        <span class="subtitle">{{language}}</span>
+      </span>
+    {{/if}}
+  </label>
+</li>
diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-actions.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-actions.hbs
deleted file mode 100644 (file)
index 2b3d076..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-<div class="navigator-actions-order">
-  {{#if sorting}}
-    {{t 'coding_rules.ordered_by'}} <strong>{{sorting.sortText}}</strong> {{#if sorting.asc}}<i class="icon-sort-asc"></i>{{else}}<i class="icon-sort-desc"></i>{{/if}}
-  {{else}}
-    {{t 'coding_rules.order'}}
-  {{/if}}
-</div>
-<ul class="navigator-actions-order-choices">
-  <li data-sort="" data-asc="">{{t 'coding_rules.sort.relevance'}}</li>
-  <li data-sort="createdAt" data-asc="true">{{t 'coding_rules.sort.creation_date'}} <i class="icon-sort-asc"></i></li>
-  <li data-sort="createdAt" data-asc="false">{{t 'coding_rules.sort.creation_date'}} <i class="icon-sort-desc"></i></li>
-  <li data-sort="name" data-asc="true">{{t 'coding_rules.sort.name'}} <i class="icon-sort-asc"></i></li>
-  <li data-sort="name" data-asc="false">{{t 'coding_rules.sort.name'}} <i class="icon-sort-desc"></i></li>
-</ul>
-<div class="navigator-actions-total">
-  {{t 'coding_rules.found'}}: <strong>{{paging.total}}</strong>
-  {{#if canWrite}}<a class="navigator-actions-bulk icon-bulk-change" title="{{t 'bulk_change'}}"></a>{{/if}}
-</div>
diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-bulk-change-dropdown.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-bulk-change-dropdown.hbs
deleted file mode 100644 (file)
index 3fcb25b..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-{{! activation }}
-
-<a class="coding-rules-bulk-change-dropdown-link" data-action="activate">
-  {{t 'coding_rules.activate_in'}}&#8230;
-</a>
-
-{{#if allowActivateOnProfile}}
-  <a class="coding-rules-bulk-change-dropdown-link" data-action="activate" data-param="{{qualityProfile}}">
-    {{t 'coding_rules.activate_in'}} <strong>{{qualityProfileName}}</strong>
-  </a>
-{{/if}}
-
-
-
-{{! deactivation }}
-
-<a class="coding-rules-bulk-change-dropdown-link" data-action="deactivate">
-  {{t 'coding_rules.deactivate_in'}}&#8230;
-</a>
-
-{{#if allowDeactivateOnProfile}}
-  <a class="coding-rules-bulk-change-dropdown-link" data-action="deactivate" data-param="{{qualityProfile}}">
-    {{tp 'coding_rules.deactivate_in'}} <strong>{{qualityProfileName}}</strong>
-  </a>
-{{/if}}
diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-bulk-change.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-bulk-change.hbs
deleted file mode 100644 (file)
index 441222f..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-<form>
-  <div class="modal-head">
-    {{#eq action 'activate'}}
-      <h2>{{t 'coding_rules.activate_in_quality_profile'}} ({{paging.total}} {{t 'coding_rules._rules'}})</h2>
-    {{/eq}}
-    {{#eq action 'deactivate'}}
-      <h2>{{t 'coding_rules.deactivate_in_quality_profile'}} ({{paging.total}} {{t 'coding_rules._rules'}})</h2>
-    {{/eq}}
-  </div>
-
-  <div class="modal-body modal-body-select2">
-    <div class="modal-error"></div>
-    <div class="modal-warning"></div>
-    <div class="modal-notice"></div>
-
-    <div class="modal-field">
-      <h3><label for="coding-rules-bulk-change-profile">
-        {{#eq action 'change-severity'}}{{t 'coding_rules.change_severity_in'}}{{/eq}}
-        {{#eq action 'activate'}}{{t 'coding_rules.activate_in'}}{{/eq}}
-        {{#eq action 'deactivate'}}{{t 'coding_rules.deactivate_in'}}{{/eq}}
-      </label></h3>
-      {{#if qualityProfile}}
-        <h3 class="readonly-field">{{qualityProfileName}}{{#notEq action 'change-severity'}} â€”
-          {{t 'are_you_sure'}}{{/notEq}}</h3>
-      {{else}}
-        <select id="coding-rules-bulk-change-profile">
-          {{#each availableQualityProfiles}}
-            <option value="{{key}}">{{name}} - {{language}}</option>
-          {{/each}}
-        </select>
-      {{/if}}
-    </div>
-  </div>
-
-  <div class="modal-foot">
-    <button id="coding-rules-submit-bulk-change">{{t 'apply'}}</button>
-    <a id="coding-rules-cancel-bulk-change" class="action">{{t 'cancel'}}</a>
-    <a id="coding-rules-close-bulk-change" class="action" style="display:none" href="#">{{t 'close'}}</a>
-  </div>
-</form>
diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-custom-rule-creation.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-custom-rule-creation.hbs
deleted file mode 100644 (file)
index c1244ff..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-<form>
-  <div class="modal-head">
-    {{#if change}}
-      <h2>{{t 'coding_rules.update_custom_rule'}}</h2>
-    {{else}}
-      <h2>{{t 'coding_rules.create_custom_rule'}}</h2>
-    {{/if}}
-  </div>
-
-  <div class="modal-body">
-    <div class="modal-error"></div>
-    <div class="modal-warning">{{t 'coding_rules.reactivate.help'}}</div>
-
-    <table>
-      <tr class="property">
-        <th><h3>{{t 'name'}} <em class="mandatory">*</em></h3></th>
-        <td>
-          <input type="text" name="name" id="coding-rules-custom-rule-creation-name"
-            class="coding-rules-name-key" value="{{name}}"/>
-        </td>
-      </tr>
-      <tr class="property">
-        <th><h3>{{t 'key'}}{{#unless change}} <em class="mandatory">*</em>{{/unless}}</h3></th>
-        <td>
-          {{#if change}}
-            <span class="coding-rules-detail-custom-rule-key" title="{{key}}">{{key}}</span>
-          {{else}}
-            <input type="text" name="key" id="coding-rules-custom-rule-creation-key"
-              class="coding-rules-name-key" value="{{internalKey}}"/>
-          {{/if}}
-        </td>
-      </tr>
-      <tr class="property">
-        <th><h3>{{t 'description'}} <em class="mandatory">*</em></h3></th>
-        <td>
-          <textarea type="textarea" name="markdown_description" id="coding-rules-custom-rule-creation-html-description"
-            class="coding-rules-markdown-description" rows="15">{{{mdDesc}}}</textarea>
-          <span class="right">{{> '_markdown-tips' }}</span>
-        </td>
-      </tr>
-      <tr class="property">
-        <th><h3>{{t 'severity'}}</h3></th>
-        <td>
-          <select id="coding-rules-custom-rule-creation-severity">
-            {{#each severities}}
-              <option value="{{this}}">{{t 'severity' this}}</option>
-            {{/each}}
-          </select>
-        </td>
-      </tr>
-      <tr class="property">
-        <th><h3>{{t 'coding_rules.filters.status'}}</h3></th>
-        <td>
-          <select id="coding-rules-custom-rule-creation-status">
-            {{#each statuses}}
-              <option value="{{id}}">{{text}}</option>
-            {{/each}}
-          </select>
-        </td>
-      </tr>
-      {{#each params}}
-        <tr class="property">
-          <th><h3>{{key}}</h3></th>
-          <td>
-            {{#eq type 'TEXT'}}
-              <textarea class="width100" rows="3" name="{{key}}" placeholder="{{defaultValue}}">{{value}}</textarea>
-            {{else}}
-              <input type="text" name="{{key}}" value="{{value}}" placeholder="{{defaultValue}}"/>
-            {{/eq}}
-            <div class="note">{{htmlDesc}}</div>
-            {{#if extra}}
-              <div class="note">{{extra}}</div>
-            {{/if}}
-          </td>
-        </tr>
-      {{/each}}
-    </table>
-  </div>
-
-  <div class="modal-foot">
-    <button id="coding-rules-custom-rule-creation-create">
-      {{#if change}}{{t 'save'}}{{else}}{{t 'create'}}{{/if}}
-    </button>
-    <a id="coding-rules-custom-rule-creation-cancel" class="action">{{t 'cancel'}}</a>
-  </div>
-</form>
diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-custom-rule-reactivation.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-custom-rule-reactivation.hbs
deleted file mode 100644 (file)
index 2de07a6..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<button id="coding-rules-custom-rule-creation-reactivate">
-  {{t 'coding_rules.reactivate'}}
-</button>
-<button id="coding-rules-custom-rule-creation-create">
-  {{#if change}}{{t 'save'}}{{else}}{{t 'create'}}{{/if}}
-</button>
-<a id="coding-rules-custom-rule-creation-cancel" class="action">{{t 'cancel'}}</a>
diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-debt-popup.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-debt-popup.hbs
deleted file mode 100644 (file)
index 4c3b81c..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-<div class="coding-rules-debt-popup bubble-popup-container">
-  <ul class="bubble-popup-list">
-    {{#if debtRemFnType}}
-    <li>
-      <h3>{{t 'coding_rules.remediation_function'}}</h3>
-      {{t 'coding_rules.remediation_function' debtRemFnType}}
-    </li>
-    {{/if}}
-    {{#if debtRemFnCoeff}}
-    <li>
-      <h3>{{t 'coding_rules.remediation_function.coeff'}}</h3>
-      {{debtRemFnCoeff}}
-    </li>
-    {{/if}}
-    {{#if debtRemFnOffset}}
-    <li>
-      <h3>{{#eq debtRemFnType 'CONSTANT_ISSUE'}}
-        {{t 'coding_rules.remediation_function.constant'}}
-        {{else}}
-        {{t 'coding_rules.remediation_function.offset'}}
-        {{/eq}}
-      </h3>
-      {{debtRemFnOffset}}
-    </li>
-    {{/if}}
-</div>
-
-<div class="bubble-popup-arrow"></div>
diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-detail-custom-rule.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-detail-custom-rule.hbs
deleted file mode 100644 (file)
index 8bd8ba0..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-<td class="coding-rules-detail-custom-rule-name">
-  <a class="nolink" href="#rule_key={{key}}">{{name}}</a>
-</td>
-
-<td class="coding-rules-detail-custom-rule-severity">
-  {{severityIcon severity}} {{t "severity" severity}}
-</td>
-
-<td class="coding-rules-detail-custom-rule-parameters">
-  {{#each parameters}}
-    <div class="coding-rules-detail-custom-rule-parameter">
-      <span class="key">{{key}}</span><span class="sep">:&nbsp;</span><span class="value" title="{{value}}">{{value}}</span>
-    </div>
-  {{/each}}
-  &nbsp;
-</td>
-
-{{#if canWrite}}
-<td class="coding-rules-detail-custom-rule-actions">
-  <div class="button-group">
-    <button class="coding-rules-detail-custom-rule-delete button-red">
-      {{t 'delete'}}
-    </button>
-  </div>
-</td>
-{{/if}}
diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-detail-quality-profile.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-detail-quality-profile.hbs
deleted file mode 100644 (file)
index 9f398ea..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-<table class="width100">
-  <tbody>
-  <tr>
-    <td class="coding-rules-detail-quality-profile-name">
-      {{name}}
-      {{#if parent}}
-        <div class="coding-rules-detail-quality-profile-inheritance">
-          {{#eq inherit 'OVERRIDES'}}
-            <i class="icon-inheritance" title="{{tp 'coding_rules.overrides' name parent.name}}"></i>
-          {{/eq}}
-          {{#eq inherit 'INHERITED'}}
-            <i class="icon-inheritance" title="{{tp 'coding_rules.inherits' name parent.name}}"></i>
-          {{/eq}}
-          {{parent.name}}
-        </div>
-      {{/if}}
-    </td>
-
-    {{#if severity}}
-      <td class="coding-rules-detail-quality-profile-severity">
-        {{severityIcon severity}} {{t "severity" severity}}
-        {{#if parent}}{{#notEq severity parent.severity}}
-          <div class="coding-rules-detail-quality-profile-inheritance">
-            {{t 'coding_rules.original'}}&nbsp;{{t 'severity' parent.severity}}
-          </div>
-        {{/notEq}}{{/if}}
-      </td>
-
-      {{#unless templateKey}}
-      <td class="coding-rules-detail-quality-profile-parameters">
-        {{#each parameters}}
-          <div class="coding-rules-detail-quality-profile-parameter">
-            <span class="key">{{key}}</span><span class="sep">:&nbsp;</span><span class="value" title="{{value}}">{{value}}</span>
-            {{#if ../parent}}{{#notEq value original}}
-              <div class="coding-rules-detail-quality-profile-inheritance">
-                {{t 'coding_rules.original'}}&nbsp;<span class="value">{{original}}</span>
-              </div>
-            {{/notEq}}{{/if}}
-          </div>
-        {{/each}}
-        &nbsp;
-      </td>
-      {{/unless}}
-
-      {{#if canWrite}}
-      <td class="coding-rules-detail-quality-profile-actions">
-        <div class="button-group">
-          {{#unless isTemplate}}
-            <button class="coding-rules-detail-quality-profile-change">{{t 'change_verb'}}</button>
-          {{/unless}}
-          {{#if parent}}
-            {{#eq inherit 'OVERRIDES'}}
-            <button class="coding-rules-detail-quality-profile-revert button-red">
-              {{t 'coding_rules.revert_to_parent_definition'}}
-            </button>
-            {{/eq}}
-          {{else}}
-            <button class="coding-rules-detail-quality-profile-deactivate button-red">
-              {{t 'coding_rules.deactivate'}}
-            </button>
-          {{/if}}
-        </div>
-      </td>
-      {{/if}}
-
-    {{else}}
-      {{#if canWrite}}{{#unless isTemplate}}
-      <td class="coding-rules-detail-quality-profile-actions">
-        <div class="button-group">
-          <button class="coding-rules-detail-quality-profile-activate">{{t 'coding_rules.activate'}}</button>
-        </div>
-      </td>
-      {{/unless}}{{/if}}
-    {{/if}}
-  </tr>
-  </tbody>
-</table>
diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-detail.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-detail.hbs
deleted file mode 100644 (file)
index 7da3581..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-<div class="coding-rules-detail-context"></div>
-
-<h3 class="coding-rules-detail-header">
-  {{name}}
-  <a class="coding-rules-detail-permalink" href="#rule_key={{key}}">
-    <i class="icon-link"></i> {{t 'coding_rules.permalink'}}
-  </a>
-</h3>
-<span class="subtitle">{{key}}</span>
-
-<ul class="coding-rules-detail-properties">
-  {{#unless isManual}}
-    <li class="coding-rules-detail-property">{{severityIcon severity}} {{t "severity" severity}}</li>
-  {{/unless}}
-  {{#notEq status 'READY'}}
-    <li class="coding-rules-detail-property">
-      <span class="coding-rules-detail-status coding-rules-detail-not-ready">{{status}}</span>
-    </li>
-  {{/notEq}}
-
-
-  <li class="coding-rules-detail-property coding-rules-detail-tag-list {{#if canWrite}}coding-rules-detail-tags-change{{/if}}">
-    <i class="icon-tags"></i>
-    <span>{{#if allTags}}{{join allTags ', '}}{{else}}{{t 'coding_rules.no_tags'}}{{/if}}</span>
-  </li>
-  {{#if canWrite}}<li class="coding-rules-detail-property coding-rules-detail-tag-edit">
-    {{#if sysTags}}<i class="icon-tags"></i>
-    <span>{{join sysTags ', '}}</span>{{/if}}
-    <input class="coding-rules-detail-tag-input" type="text" value="{{#if tags}}{{join tags ','}}{{/if}}">
-
-    <div class="button-group">
-      <button class="coding-rules-detail-tag-edit-done">{{t 'Done'}}</button>
-    </div>
-    <a class="coding-rules-details-tag-edit-cancel">{{t 'cancel'}}</a>
-  </li>{{/if}}
-
-  {{#if subcharacteristic}}
-    <li class="coding-rules-detail-property coding-rules-subcharacteristic">{{subcharacteristic}}</li>
-  {{/if}}
-  <li class="coding-rules-detail-property">{{t 'coding_rules.available_since'}} {{d createdAt}}</li>
-  <li class="coding-rules-detail-property">{{repository}}{{#unless isManual}} ({{language}}){{/unless}}</li>
-
-  {{#if isTemplate}}
-    <li class="coding-rules-detail-property" title="{{t 'coding_rules.rule_template.title'}}">{{t 'coding_rules.rule_template'}}</li>
-  {{/if}}
-  {{#if templateKey}}
-    <li class="coding-rules-detail-property" title="{{t 'coding_rules.custom_rule.title'}}">{{t 'coding_rules.custom_rule'}}
-      (<a href="#rule_key={{templateKey}}">{{t 'coding_rules.show_template'}}</a>)
-    </li>
-  {{/if}}
-</ul>
-
-<div class="coding-rules-detail-description rule-desc markdown">{{{htmlDesc}}}</div>
-
-{{#unless isEditable}}
-  {{#unless isManual}}
-  <div class="coding-rules-detail-description coding-rules-detail-description-extra">
-    <div id="coding-rules-detail-description-extra">
-      {{#if htmlNote}}
-        <div class="rule-desc marginbottom10 markdown">{{{htmlNote}}}</div>{{/if}}
-      {{#if canWrite}}<div class="button-group">
-        <button id="coding-rules-detail-extend-description">{{t 'coding_rules.extend_description'}}</button>
-      </div>{{/if}}
-    </div>
-
-    {{#if canWrite}}<div class="coding-rules-detail-extend-description-form">
-      <table class="width100">
-        <tbody>
-        <tr>
-          <td class="width100" colspan="2">
-            <textarea id="coding-rules-detail-extend-description-text" rows="4"
-                      style="width: 100%; margin-bottom: 4px;">{{mdNote}}</textarea>
-          </td>
-        </tr>
-        <tr>
-          <td>
-            <div class="button-group">
-              <button id="coding-rules-detail-extend-description-submit">{{t 'save'}}</button>
-              {{#if mdNote}}
-              <button id="coding-rules-detail-extend-description-remove" class="button-red">{{t 'remove'}}</button>
-              {{/if}}
-            </div>
-            <a id="coding-rules-detail-extend-description-cancel" class="action">{{t 'cancel'}}</a>
-          </td>
-          <td class="right">
-            {{> '_markdown-tips' }}
-          </td>
-        </tr>
-        </tbody>
-      </table>
-    </div>
-
-    <div id="coding-rules-detail-extend-description-spinner">
-      <i class="spinner"></i>
-    </div>{{/if}}
-  </div>
-  {{/unless}}
-{{/unless}}
-
-
-{{#if params}}
-  <h3 class="coding-rules-detail-title">{{t 'coding_rules.parameters'}}</h3>
-  <div class="coding-rules-detail-parameters">
-    {{#each params}}
-    <dl class="coding-rules-detail-parameter">
-      <dt class="coding-rules-detail-parameter-name">{{key}}</dt>
-      <dd class="coding-rules-detail-parameter-description" data-key="{{key}}">
-        <p>{{{htmlDesc}}}</p>
-        {{#if ../../templateKey}}
-        <div class="subtitle">
-          {{#if defaultValue }}
-            <span class="value">{{defaultValue}}</span>
-          {{else}}
-            {{t 'coding_rules.parameter.empty'}}
-          {{/if}}
-        </div>
-        {{else}}
-          {{#if defaultValue}}
-          <div class="subtitle">{{t 'coding_rules.parameters.default_value'}} <span class="value">{{defaultValue}}</span></div>
-          {{/if}}
-        {{/if}}
-      </dd>
-    </dl>
-    {{/each}}
-  </div>
-{{/if}}
-
-{{#if isEditable}}
-  <div class="coding-rules-detail-description">
-    <div class="button-group">
-      {{#if isManual}}
-        <button id="coding-rules-detail-manual-rule-change">{{t 'edit'}}</button>
-      {{else}}
-        <button id="coding-rules-detail-custom-rule-change">{{t 'edit'}}</button>
-      {{/if}}
-      <button id="coding-rules-detail-rule-delete" class="button-red">{{t 'delete'}}</button>
-    </div>
-  </div>
-{{/if}}
-
-
-{{#if isTemplate}}
-<div class="coding-rules-detail-custom-rules-section">
-  <h3 class="coding-rules-detail-title">{{t 'coding_rules.custom_rules'}}</h3>
-
-  {{#if canWrite}}<div class="button-group coding-rules-detail-quality-profiles-activation">
-    <button id="coding-rules-custom-rules-create">{{t 'coding_rules.create'}}</button>
-  </div>{{/if}}
-  <div id="coding-rules-detail-custom-rules"></div>
-</div>
-{{/if}}
-
-
-{{#if qualityProfilesVisible}}
-<div class="coding-rules-detail-quality-profiles-section">
-  <h3 class="coding-rules-detail-title">{{t 'coding_rules.quality_profiles'}}</h3>
-
-  {{#if canWrite}}{{#unless isTemplate}}<div class="button-group coding-rules-detail-quality-profiles-activation">
-    <button id="coding-rules-quality-profile-activate">{{t 'coding_rules.activate'}}</button>
-  </div>{{/unless}}{{/if}}
-  {{#if isTemplate}}
-  <div class="coding-rules-detail-quality-profiles-template-caption warning">{{t 'coding_rules.quality_profiles.template_caption'}}</div>
-  {{/if}}
-  <div id="coding-rules-detail-quality-profiles"></div>
-</div>
-{{/if}}
diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-facets.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-facets.hbs
deleted file mode 100644 (file)
index c274fff..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-<div class="navigator-facets-list">
-  {{#unless items}}
-  {{t 'coding_rules.no_results'}}
-  {{/unless}}
-  {{#each items}}
-    <div class="navigator-facets-list-item" data-property="{{property}}">
-      <div class="navigator-facets-list-item-name">
-        {{#if limitReached}}
-          {{tp 'coding_rules.facets.top' property_message}}
-        {{else}}
-          {{property_message}}
-        {{/if}}
-      </div>
-      <div class="navigator-facets-list-item-options">
-        {{#each values}}
-          {{#if count}}
-          <a class="facet" data-key="{{val}}" data-property="{{../property}}">
-            <span class="facet-name">{{text}}</span>
-            <span class="facet-stat">{{count}}</span>
-          </a>
-          {{/if}}
-        {{/each}}
-      </div>
-    </div>
-  {{/each}}
-</div>
diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-filter-bar.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-filter-bar.hbs
deleted file mode 100644 (file)
index 2e0f52a..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-<div class="navigator-filters-list"></div>
-<button class="navigator-filter-submit">{{t 'search_verb'}}</button>
\ No newline at end of file
diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-filters.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-filters.hbs
new file mode 100644 (file)
index 0000000..45ce48c
--- /dev/null
@@ -0,0 +1,9 @@
+<div class="search-navigator-filters-header">
+  <span class="search-navigator-filters-name">{{t 'coding_rules.page'}}</span>
+</div>
+
+<div class="search-navigator-filters-actions">
+  <div class="button-group">
+    <button class="js-new-search" id="coding-rules-new-search">{{t 'issue_filter.new_search'}}</button>
+  </div>
+</div>
diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-header.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-header.hbs
deleted file mode 100644 (file)
index 6f539db..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-<h1 class="navigator-header-title">{{t 'coding_rules.page'}}</h1>
-
-<div class="navigator-header-actions button-group">
-  <button id="coding-rules-new-search">{{t 'coding_rules.new_search'}}</button>
-  {{#if canWrite}}<button id="coding-rules-create-rule">{{t 'coding_rules.create'}}</button>{{/if}}
-</div>
index d824a27fb199851d2b33237b54de249aaaf92379..8f46e4f8fb13a7b4b40942d63b44332e3a9aec74 100644 (file)
@@ -1,16 +1,10 @@
-<div class="navigator-header"></div>
-<div class="navigator-filters"></div>
-<div class="navigator-facets"></div>
+<div class="search-navigator-side">
+  <div class="search-navigator-filters"></div>
+  <div class="search-navigator-facets"></div>
+</div>
 
-<div class="navigator-content">
-  <div class="navigator-side">
-    <div style="position:relative; overflow: visible; height: 100%;">
-      <div class="navigator-actions"></div>
-      <div class="navigator-results"></div>
-      <a class="navigator-resizer"><i class="icon-resizer"></i></a>
-    </div>
-  </div>
-  <div class="navigator-main">
-    <div class="navigator-details"></div>
-  </div>
-</div>
\ No newline at end of file
+<div class="search-navigator-workspace">
+  <div class="search-navigator-workspace-header"></div>
+  <div class="search-navigator-workspace-list"></div>
+  <div class="search-navigator-workspace-details"></div>
+</div>
diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-list-empty.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-list-empty.hbs
deleted file mode 100644 (file)
index 75e2daf..0000000
+++ /dev/null
@@ -1 +0,0 @@
-{{t 'coding_rules.no_results'}}
\ No newline at end of file
diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-list-item.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-list-item.hbs
deleted file mode 100644 (file)
index a4244ac..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-<div class="line line-small">
-  <span class="coding-rules-detail-status">{{default language manualRuleLabel}}</span>
-
-  {{#if allTags}}
-    &nbsp;&nbsp;
-    <span class="coding-rules-list-tags">
-      <i class="icon-tags"></i>
-      <span>{{join allTags ', '}}</span>
-    </span>
-  {{/if}}
-
-  {{#notEq status 'READY'}}
-    <div class="line-right">
-      <span class="coding-rules-detail-not-ready">{{status}}</span>
-    </div>
-  {{/notEq}}
-</div>
-
-<div class="line" title="{{name}}" name="{{key}}">{{name}}</div>
diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-manual-rule-creation.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-manual-rule-creation.hbs
deleted file mode 100644 (file)
index 389dd69..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-<form>
-  <div class="modal-head">
-    {{#if change}}
-      <h2>{{t 'coding_rules.update_manual_rule'}}</h2>
-    {{else}}
-      <h2>{{t 'coding_rules.create_manual_rule'}}</h2>
-    {{/if}}
-  </div>
-
-  <div class="modal-body">
-    <div class="modal-error"></div>
-    <div class="modal-warning">{{t 'coding_rules.reactivate.help'}}</div>
-
-    <table>
-      <tr class="property">
-        <th><h3>{{t 'name'}} <em class="mandatory">*</em></h3></th>
-        <td>
-          <input type="text" name="name" id="coding-rules-manual-rule-creation-name"
-            class="coding-rules-name-key" value="{{name}}"/>
-        </td>
-      </tr>
-      <tr class="property">
-        <th><h3>{{t 'key'}}{{#unless change}} <em class="mandatory">*</em>{{/unless}}</h3></th>
-        <td>
-          {{#if change}}
-            {{key}}
-          {{else}}
-            <input type="text" name="key" id="coding-rules-manual-rule-creation-key"
-              class="coding-rules-name-key" value="{{internalKey}}"/>
-          {{/if}}
-        </td>
-      </tr>
-      <tr class="property">
-        <th><h3>{{t 'description'}} <em class="mandatory">*</em></h3></th>
-        <td>
-          <textarea type="textarea" name="markdown_description" id="coding-rules-manual-rule-creation-html-description"
-            class="coding-rules-markdown-description" rows="15">{{{mdDesc}}}</textarea>
-          <span class="right">{{> '_markdown-tips' }}</span>
-        </td>
-      </tr>
-    </table>
-  </div>
-
-  <div class="modal-foot">
-    <button id="coding-rules-manual-rule-creation-create">
-      {{#if change}}{{t 'save'}}{{else}}{{t 'create'}}{{/if}}
-    </button>
-    <a id="coding-rules-manual-rule-creation-cancel" class="action">{{t 'cancel'}}</a>
-  </div>
-</form>
diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-manual-rule-reactivation.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-manual-rule-reactivation.hbs
deleted file mode 100644 (file)
index 2410c7f..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<button id="coding-rules-manual-rule-creation-reactivate">
-  {{t 'coding_rules.reactivate'}}
-</button>
-<button id="coding-rules-manual-rule-creation-create">
-  {{#if change}}{{t 'save'}}{{else}}{{t 'create'}}{{/if}}
-</button>
-<a id="coding-rules-manual-rule-creation-cancel" class="action">{{t 'cancel'}}</a>
diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-parameter-popup.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-parameter-popup.hbs
deleted file mode 100644 (file)
index 0299ced..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-<div class="coding-rules-parameter-full-description bubble-popup-container">
-  <div class="bubble-popup-title">{{key}}</div>
-
-    {{{htmlDesc}}}
-    {{#if defaultValue}}
-      <div>
-        {{t 'coding_rules.parameters.default_value'}} {{defaultValue}}
-      </div>
-    {{/if}}
-</div>
-
-<div class="bubble-popup-arrow"></div>
diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-profile-filter-detail.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-profile-filter-detail.hbs
deleted file mode 100644 (file)
index 3a3b44c..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-<li>
-  <label title="{{id}}" data-id="{{id}}">
-    <span>
-      <i class="icon-checkbox {{#if checked}}icon-checkbox-checked{{/if}} {{#unless multiple}}icon-checkbox-single{{/unless}}"></i>
-      {{text}}
-    </span>
-
-    {{#if language}}
-      <br>
-      <span>
-        <i class="icon-checkbox icon-checkbox-invisible"></i>
-        <span class="subtitle">{{language}}</span>
-      </span>
-    {{/if}}
-  </label>
-</li>
diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-quality-profile-activation.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-quality-profile-activation.hbs
deleted file mode 100644 (file)
index e407448..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-<form>
-  <div class="modal-head">
-    {{#if change}}
-      <h2>{{t 'coding_rules.change_details'}}</h2>
-    {{else}}
-      <h2>{{t 'coding_rules.activate_in_quality_profile'}}</h2>
-    {{/if}}
-  </div>
-
-  <div class="modal-body modal-body-select2">
-    <div class="modal-error"></div>
-
-    <table>
-      <tr class="property">
-        <th><h3>{{t 'coding_rules.quality_profile'}}</h3></th>
-        <td>
-          {{#if key}}
-            {{name}}
-          {{else}}
-            <select id="coding-rules-quality-profile-activation-select">
-              {{#each qualityProfiles}}
-                <option value="{{key}}">{{name}}</option>
-              {{/each}}
-            </select>
-          {{/if}}
-        </td>
-      </tr>
-      <tr class="property">
-        <th><h3>{{t 'severity'}}</h3></th>
-        <td>
-          <select id="coding-rules-quality-profile-activation-severity">
-            {{#each severities}}
-              <option value="{{this}}">{{t 'severity' this}}</option>
-            {{/each}}
-          </select>
-        </td>
-      </tr>
-      {{#if isCustomRule}}
-      <tr class="property">
-        <td colspan="2" class="note">{{t 'coding_rules.custom_rule.activation_notice'}}</td>
-      {{else}}
-      {{#each params}}
-        <tr class="property">
-          <th><h3>{{key}}</h3></th>
-          <td>
-            {{#eq type 'TEXT'}}
-              <textarea class="width100" rows="3" name="{{key}}" placeholder="{{defaultValue}}">{{value}}</textarea>
-            {{else}}
-              {{#eq type 'BOOLEAN'}}
-              <select name="{{key}}" value="{{value}}">
-                <option value="{{defaultValue}}">{{t 'default'}} ({{t defaultValue}})</option>
-                <option value="true"{{#eq value 'true'}} selected="selected"{{/eq}}>{{t 'true'}}</option>
-                <option value="false"{{#eq value 'false'}} selected="selected"{{/eq}}>{{t 'false'}}</option>
-              </select>
-              {{else}}
-              <input type="text" name="{{key}}" value="{{value}}" placeholder="{{defaultValue}}">
-              {{/eq}}
-            {{/eq}}
-            <div class="note">{{description}}</div>
-            {{#if extra}}
-              <div class="note">{{extra}}</div>
-            {{/if}}
-          </td>
-        </tr>
-      {{/each}}
-      {{/if}}
-    </table>
-  </div>
-
-  <div class="modal-foot">
-    <button id="coding-rules-quality-profile-activation-activate" {{#unless saveEnabled}}disabled="disabled"{{/unless}}>
-      {{#if change}}{{t 'save'}}{{else}}{{t 'coding_rules.activate'}}{{/if}}
-    </button>
-    <a id="coding-rules-quality-profile-activation-cancel" class="action">{{t 'cancel'}}</a>
-  </div>
-</form>
diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-query-filter.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-query-filter.hbs
deleted file mode 100644 (file)
index 392a690..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-<input type="text"
-  size="{{size}}" name="{{property}}" value="{{value}}"
-  class="query-filter-input"/>
diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-repository-detail.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-repository-detail.hbs
deleted file mode 100644 (file)
index 3a3b44c..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-<li>
-  <label title="{{id}}" data-id="{{id}}">
-    <span>
-      <i class="icon-checkbox {{#if checked}}icon-checkbox-checked{{/if}} {{#unless multiple}}icon-checkbox-single{{/unless}}"></i>
-      {{text}}
-    </span>
-
-    {{#if language}}
-      <br>
-      <span>
-        <i class="icon-checkbox icon-checkbox-invisible"></i>
-        <span class="subtitle">{{language}}</span>
-      </span>
-    {{/if}}
-  </label>
-</li>
diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-rule-details.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-rule-details.hbs
new file mode 100644 (file)
index 0000000..935dd66
--- /dev/null
@@ -0,0 +1,162 @@
+<h3 class="coding-rules-detail-header">
+  {{name}}
+  <a class="coding-rules-detail-permalink icon-link" target="_blank" href="#rule_key={{key}}"></a>
+</h3>
+<span class="subtitle">{{key}}</span>
+
+<ul class="coding-rules-detail-properties">
+  {{#unless isManual}}
+    <li class="coding-rules-detail-property">{{severityIcon severity}} {{t "severity" severity}}</li>
+  {{/unless}}
+  {{#notEq status 'READY'}}
+    <li class="coding-rules-detail-property">
+      <span class="coding-rules-detail-status coding-rules-detail-not-ready">{{status}}</span>
+    </li>
+  {{/notEq}}
+
+
+  <li class="coding-rules-detail-property coding-rules-detail-tag-list {{#if canWrite}}coding-rules-detail-tags-change{{/if}}">
+    <i class="icon-tags"></i>
+    <span>{{#if allTags}}{{join allTags ', '}}{{else}}{{t 'coding_rules.no_tags'}}{{/if}}</span>
+  </li>
+  {{#if canWrite}}<li class="coding-rules-detail-property coding-rules-detail-tag-edit">
+    {{#if sysTags}}<i class="icon-tags"></i>
+      <span>{{join sysTags ', '}}</span>{{/if}}
+    <input class="coding-rules-detail-tag-input" type="text" value="{{#if tags}}{{join tags ','}}{{/if}}">
+
+    <div class="button-group">
+      <button class="coding-rules-detail-tag-edit-done">{{t 'Done'}}</button>
+    </div>
+    <a class="coding-rules-details-tag-edit-cancel">{{t 'cancel'}}</a>
+  </li>{{/if}}
+
+  {{#if subCharacteristic}}
+    <li class="coding-rules-detail-property coding-rules-subcharacteristic">{{subCharacteristic}}</li>
+  {{/if}}
+  <li class="coding-rules-detail-property">{{t 'coding_rules.available_since'}} {{d createdAt}}</li>
+  <li class="coding-rules-detail-property">{{repository}}{{#unless isManual}} ({{language}}){{/unless}}</li>
+
+  {{#if isTemplate}}
+    <li class="coding-rules-detail-property" title="{{t 'coding_rules.rule_template.title'}}">{{t 'coding_rules.rule_template'}}</li>
+  {{/if}}
+  {{#if templateKey}}
+    <li class="coding-rules-detail-property" title="{{t 'coding_rules.custom_rule.title'}}">{{t 'coding_rules.custom_rule'}}
+      (<a href="#rule_key={{templateKey}}">{{t 'coding_rules.show_template'}}</a>)
+    </li>
+  {{/if}}
+</ul>
+
+<div class="coding-rules-detail-description rule-desc markdown">{{{htmlDesc}}}</div>
+
+{{#unless isEditable}}
+  {{#unless isManual}}
+    <div class="coding-rules-detail-description coding-rules-detail-description-extra">
+      <div id="coding-rules-detail-description-extra">
+        {{#if htmlNote}}
+          <div class="rule-desc marginbottom10 markdown">{{{htmlNote}}}</div>{{/if}}
+        {{#if canWrite}}<div class="button-group">
+          <button id="coding-rules-detail-extend-description">{{t 'coding_rules.extend_description'}}</button>
+        </div>{{/if}}
+      </div>
+
+      {{#if canWrite}}<div class="coding-rules-detail-extend-description-form">
+        <table class="width100">
+          <tbody>
+          <tr>
+            <td class="width100" colspan="2">
+            <textarea id="coding-rules-detail-extend-description-text" rows="4"
+                      style="width: 100%; margin-bottom: 4px;">{{mdNote}}</textarea>
+            </td>
+          </tr>
+          <tr>
+            <td>
+              <div class="button-group">
+                <button id="coding-rules-detail-extend-description-submit">{{t 'save'}}</button>
+                {{#if mdNote}}
+                  <button id="coding-rules-detail-extend-description-remove" class="button-red">{{t 'remove'}}</button>
+                {{/if}}
+              </div>
+              <a id="coding-rules-detail-extend-description-cancel" class="action">{{t 'cancel'}}</a>
+            </td>
+            <td class="right">
+              {{> '_markdown-tips' }}
+            </td>
+          </tr>
+          </tbody>
+        </table>
+      </div>
+
+        <div id="coding-rules-detail-extend-description-spinner">
+          <i class="spinner"></i>
+        </div>{{/if}}
+    </div>
+  {{/unless}}
+{{/unless}}
+
+
+{{#if params}}
+  <h3 class="coding-rules-detail-title">{{t 'coding_rules.parameters'}}</h3>
+  <div class="coding-rules-detail-parameters">
+    {{#each params}}
+      <dl class="coding-rules-detail-parameter">
+        <dt class="coding-rules-detail-parameter-name">{{key}}</dt>
+        <dd class="coding-rules-detail-parameter-description" data-key="{{key}}">
+          <p>{{{htmlDesc}}}</p>
+          {{#if ../../templateKey}}
+            <div class="subtitle">
+              {{#if defaultValue }}
+                <span class="value">{{defaultValue}}</span>
+              {{else}}
+                {{t 'coding_rules.parameter.empty'}}
+              {{/if}}
+            </div>
+          {{else}}
+            {{#if defaultValue}}
+              <div class="subtitle">{{t 'coding_rules.parameters.default_value'}} <span class="value">{{defaultValue}}</span></div>
+            {{/if}}
+          {{/if}}
+        </dd>
+      </dl>
+    {{/each}}
+  </div>
+{{/if}}
+
+{{#if isEditable}}
+  <div class="coding-rules-detail-description">
+    <div class="button-group">
+      {{#if isManual}}
+        <button id="coding-rules-detail-manual-rule-change">{{t 'edit'}}</button>
+      {{else}}
+        <button id="coding-rules-detail-custom-rule-change">{{t 'edit'}}</button>
+      {{/if}}
+      <button id="coding-rules-detail-rule-delete" class="button-red">{{t 'delete'}}</button>
+    </div>
+  </div>
+{{/if}}
+
+
+{{#if isTemplate}}
+  <div class="coding-rules-detail-custom-rules-section">
+    <h3 class="coding-rules-detail-title">{{t 'coding_rules.custom_rules'}}</h3>
+
+    {{#if canWrite}}<div class="button-group coding-rules-detail-quality-profiles-activation">
+      <button id="coding-rules-custom-rules-create">{{t 'coding_rules.create'}}</button>
+    </div>{{/if}}
+    <div id="coding-rules-detail-custom-rules"></div>
+  </div>
+{{/if}}
+
+
+{{#if qualityProfilesVisible}}
+  <div class="coding-rules-detail-quality-profiles-section">
+    <h3 class="coding-rules-detail-title">{{t 'coding_rules.quality_profiles'}}</h3>
+
+    {{#if canWrite}}{{#unless isTemplate}}<div class="button-group coding-rules-detail-quality-profiles-activation">
+      <button id="coding-rules-quality-profile-activate">{{t 'coding_rules.activate'}}</button>
+    </div>{{/unless}}{{/if}}
+    {{#if isTemplate}}
+      <div class="coding-rules-detail-quality-profiles-template-caption warning">{{t 'coding_rules.quality_profiles.template_caption'}}</div>
+    {{/if}}
+    <div id="coding-rules-detail-quality-profiles"></div>
+  </div>
+{{/if}}
diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-workspace-header.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-workspace-header.hbs
new file mode 100644 (file)
index 0000000..e91dbcd
--- /dev/null
@@ -0,0 +1,30 @@
+<div class="search-navigator-header-component">
+  {{#if state.rule}}
+    <a class="js-back">{{t 'coding_rules.return_to_list'}}</a>
+  {{else}}
+    &nbsp;
+  {{/if}}
+</div>
+
+
+<div class="search-navigator-header-actions">
+  {{#notNull state.total}}
+    <div class="search-navigator-header-pagination">
+      {{#gt state.total 0}}
+        <a class="js-prev icon-prev" title="{{t 'paging_previous'}}"></a>
+        <span class="current">{{sum state.selectedIndex 1}} / <span id="coding-rules-total">{{state.total}}</span></span>
+        <a class="js-next icon-next" title="{{t 'paging_next'}}"></a>
+      {{else}}
+        <span class="current">0 / <span id="coding-rules-total">0</span></span>
+      {{/gt}}
+    </div>
+  {{/notNull}}
+
+
+  <div class="search-navigator-header-buttons button-group">
+    <button class="js-reload">{{t 'reload'}}</button>
+    {{#if state.canBulkChange}}
+      <button class="js-bulk-change">{{t 'bulk_change'}}</button>
+    {{/if}}
+  </div>
+</div>
diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-workspace-list-item.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-workspace-list-item.hbs
new file mode 100644 (file)
index 0000000..fffa5b5
--- /dev/null
@@ -0,0 +1,15 @@
+<div class="coding-rule-inner">
+  <div class="coding-rule-title">
+    <a class="js-rule link-no-underline">{{name}}</a>
+  </div>
+  <div class="coding-rule-meta">
+    <a class="js-lang link-no-underline" data-lang="{{lang}}">{{langName}}</a>
+    {{#notEmpty sysTags}}
+      &nbsp;&nbsp;&nbsp;
+      <i class="icon-tags"></i>
+      {{#each sysTags}}
+        <a class="js-tag link-no-underline" data-tag="{{this}}">{{this}}</a>
+      {{/each}}
+    {{/notEmpty}}
+  </div>
+</div>
diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-workspace-list.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-workspace-list.hbs
new file mode 100644 (file)
index 0000000..37421cb
--- /dev/null
@@ -0,0 +1,5 @@
+<div class="js-list"></div>
+
+<div class="search-navigator-workspace-list-more js-more">
+  <i class="spinner"></i>
+</div>
diff --git a/server/sonar-web/src/main/hbs/coding-rules/facets/_coding-rules-facet-header.hbs b/server/sonar-web/src/main/hbs/coding-rules/facets/_coding-rules-facet-header.hbs
new file mode 100644 (file)
index 0000000..2251f57
--- /dev/null
@@ -0,0 +1,4 @@
+<a class="search-navigator-facet-header js-facet-toggle">
+  <i class="icon-checkbox {{#if enabled}}icon-checkbox-checked{{/if}}"></i>
+  {{t 'coding_rules.facet' property}}
+</a>
diff --git a/server/sonar-web/src/main/hbs/coding-rules/facets/coding-rules-base-facet.hbs b/server/sonar-web/src/main/hbs/coding-rules/facets/coding-rules-base-facet.hbs
new file mode 100644 (file)
index 0000000..fc7fef9
--- /dev/null
@@ -0,0 +1,10 @@
+{{> '_coding-rules-facet-header'}}
+
+<div class="search-navigator-facet-list">
+  {{#each values}}
+    <a class="facet search-navigator-facet js-facet" data-value="{{val}}" title="{{default label val}}">
+      <span class="facet-name">{{default label val}}{{#if extra}} <span class="subtitle">{{extra}}</span>{{/if}}</span>
+      <span class="facet-stat">{{count}}</span>
+    </a>
+  {{/each}}
+</div>
diff --git a/server/sonar-web/src/main/hbs/coding-rules/facets/coding-rules-severity-facet.hbs b/server/sonar-web/src/main/hbs/coding-rules/facets/coding-rules-severity-facet.hbs
new file mode 100644 (file)
index 0000000..b6a386b
--- /dev/null
@@ -0,0 +1,10 @@
+{{> '_coding-rules-facet-header'}}
+
+<div class="search-navigator-facet-list">
+  {{#each values}}
+    <a class="facet search-navigator-facet search-navigator-facet-half js-facet" data-value="{{val}}" title="{{t 'severity' val}}">
+      <span class="facet-name">{{severityIcon val}} {{t 'severity' val}}</span>
+      <span class="facet-stat">{{count}}</span>
+    </a>
+  {{/each}}
+</div>
index 9b59a846155b55e2d7239727184518317c2fe3a7..3b57c6021ea21cd4b009c60ac4159949bc047948 100644 (file)
@@ -1,4 +1,4 @@
-<a class="issues-facet-header js-issues-facet-toggle">
+<a class="search-navigator-facet-header js-facet-toggle">
   <i class="icon-checkbox {{#if enabled}}icon-checkbox-checked{{/if}}"></i>
   {{t 'issues.facet' property}}
 </a>
index d0cdd8715637a5c68c2b6b9e9ebb638a86fd4749..1b7d6dc39a7db08679f4f96dff07545210b41f77 100644 (file)
@@ -1,15 +1,15 @@
 {{> '_issues-facet-header'}}
 
-<div class="issues-facet-list">
+<div class="search-navigator-facet-list">
   {{#each values}}
     {{#eq val ''}}
       {{! unplanned }}
-      <a class="facet issues-facet js-issues-facet" data-unplanned title="{{t 'issue.unplanned'}}">
+      <a class="facet search-navigator-facet js-facet" data-unplanned title="{{t 'issue.unplanned'}}">
         <span class="facet-name">{{t 'issue.unplanned'}}</span>
         <span class="facet-stat">{{count}}</span>
       </a>
     {{else}}
-      <a class="facet issues-facet js-issues-facet" data-value="{{val}}" title="{{label}}">
+      <a class="facet search-navigator-facet js-facet" data-value="{{val}}" title="{{label}}">
         <span class="facet-name">{{label}}</span>
         <span class="facet-stat">{{count}}</span>
       </a>
index 4fd181b9b98a6ea972a256a4b62f352c52d777e9..6e6ab49b1d4c880fcab8bc28635f415bbd71a86d 100644 (file)
@@ -1,22 +1,22 @@
 {{> '_issues-facet-header'}}
 
-<div class="issues-facet-list">
+<div class="search-navigator-facet-list">
   {{#each values}}
     {{#eq val ''}}
       {{! unassigned }}
-      <a class="facet issues-facet js-issues-facet" data-unassigned title="{{t 'unassigned'}}">
+      <a class="facet search-navigator-facet js-facet" data-unassigned title="{{t 'unassigned'}}">
         <span class="facet-name">{{t 'unassigned'}}</span>
         <span class="facet-stat">{{count}}</span>
       </a>
     {{else}}
-      <a class="facet issues-facet js-issues-facet" data-value="{{val}}" title="{{label}}">
+      <a class="facet search-navigator-facet js-facet" data-value="{{val}}" title="{{label}}">
         <span class="facet-name">{{label}}</span>
         <span class="facet-stat">{{count}}</span>
       </a>
     {{/eq}}
   {{/each}}
 
-  <div class="issues-facet-custom-value">
-    <input type="hidden" class="js-issues-custom-value">
+  <div class="search-navigator-facet-custom-value">
+    <input type="hidden" class="js-custom-value">
   </div>
 </div>
index 4fd48a68f4e606a6867f01ef1d19877cf9cede62..7e12ac12daa42cef49451331e2659c6d6cdd58fb 100644 (file)
@@ -1,8 +1,8 @@
 {{> '_issues-facet-header'}}
 
-<div class="issues-facet-list">
+<div class="search-navigator-facet-list">
   {{#each values}}
-    <a class="facet issues-facet js-issues-facet" data-value="{{val}}" title="{{default label val}}">
+    <a class="facet search-navigator-facet js-facet" data-value="{{val}}" title="{{default label val}}">
       <span class="facet-name">{{default label val}}</span>
       <span class="facet-stat">{{count}}</span>
     </a>
index ec0d1bd7a6b576192ffdf81a062ae6d5fde1e598..479bdc19abc07fd34cefc7ed734d9053a88b7c5f 100644 (file)
@@ -1,8 +1,8 @@
 {{> '_issues-facet-header'}}
 
-<div class="issues-facet-list issues-facet-list-align-right">
+<div class="search-navigator-facet-list search-navigator-facet-list-align-right">
   {{#each values}}
-    <a class="facet issues-facet js-issues-facet" data-value="{{val}}" title="{{default label val}}">
+    <a class="facet search-navigator-facet js-facet" data-value="{{val}}" title="{{default label val}}">
       <span class="facet-name">{{default label val}}</span>
       <span class="facet-stat">{{count}}</span>
     </a>
index 5e33e15dd08ded08b31a6a2174ca7c30949e0971..c5b3e5dd47e7d6b055535c1d295ba730609b9d11 100644 (file)
@@ -2,13 +2,13 @@
 
 {{#if createdAt}}
   <input type="hidden" name="createdAt">
-  <div class="issues-facet-container">
+  <div class="search-navigator-facet-container">
     {{dt createdAt}} ({{fromNow createdAt}})
   </div>
 {{else}}
-  <div class="issues-facet-container justify">
-    <input type="text" class="issues-facet-input" name="createdAfter" placeholder="From">
+  <div class="search-navigator-facet-container justify">
+    <input type="text" class="search-navigator-facet-input" name="createdAfter" placeholder="From">
     to
-    <input type="text" class="issues-facet-input" name="createdBefore" placeholder="To">
+    <input type="text" class="search-navigator-facet-input" name="createdBefore" placeholder="To">
   </div>
 {{/if}}
index 79bf7ac15bde2f4e32734b0764b86ec06be6e22c..bb0568a8171c6938aa1622d9545b0eb7896e2409 100644 (file)
@@ -1,14 +1,14 @@
 {{> '_issues-facet-header'}}
 
-<div class="issues-facet-list">
+<div class="search-navigator-facet-list">
   {{#each values}}
-    <a class="facet issues-facet js-issues-facet" data-value="{{val}}" title="{{#if extra}}({{extra}}) {{/if}}{{default label val}}">
+    <a class="facet search-navigator-facet js-facet" data-value="{{val}}" title="{{#if extra}}({{extra}}) {{/if}}{{default label val}}">
       <span class="facet-name">{{default label val}}</span>
       <span class="facet-stat">{{count}}</span>
     </a>
   {{/each}}
 
-  <div class="issues-facet-custom-value">
-    <input type="hidden" class="js-issues-custom-value">
+  <div class="search-navigator-facet-custom-value">
+    <input type="hidden" class="js-custom-value">
   </div>
 </div>
index e146f5a64e6af30417f68c5898c89000283cce15..7d82808b911ee9159aee103c111355c5389a3215 100644 (file)
@@ -1,5 +1,5 @@
 {{> '_issues-facet-header'}}
 
-<div class="issues-facet-container">
+<div class="search-navigator-facet-container">
   {{issues}}
 </div>
index 1eb34815a92f5e21413afb03da4ffe1548dde4a9..72aba97d349cd858a9647d7fc5716ee46b27e2f9 100644 (file)
@@ -1,15 +1,15 @@
 {{> '_issues-facet-header'}}
 
-<div class="issues-facet-list">
+<div class="search-navigator-facet-list">
   {{#each values}}
     {{#eq val ''}}
     {{! unresolved }}
-      <a class="facet issues-facet issues-facet-half js-issues-facet" data-unresolved title="{{t 'unresolved'}}">
+      <a class="facet search-navigator-facet search-navigator-facet-half js-facet" data-unresolved title="{{t 'unresolved'}}">
         <span class="facet-name">{{t 'unresolved'}}</span>
         <span class="facet-stat">{{count}}</span>
       </a>
     {{else}}
-      <a class="facet issues-facet issues-facet-half js-issues-facet" data-value="{{val}}" title="{{t 'issue.resolution' val}}">
+      <a class="facet search-navigator-facet search-navigator-facet-half js-facet" data-value="{{val}}" title="{{t 'issue.resolution' val}}">
         <span class="facet-name">{{t 'issue.resolution' val}}</span>
         <span class="facet-stat">{{count}}</span>
       </a>
index 062e275abb495149849630e3737ede1e32268edc..882b47806249194b5055569b33d800db47da43b5 100644 (file)
@@ -1,8 +1,8 @@
 {{> '_issues-facet-header'}}
 
-<div class="issues-facet-list">
+<div class="search-navigator-facet-list">
   {{#each values}}
-    <a class="facet issues-facet issues-facet-half js-issues-facet" data-value="{{val}}" title="{{t 'severity' val}}">
+    <a class="facet search-navigator-facet search-navigator-facet-half js-facet" data-value="{{val}}" title="{{t 'severity' val}}">
       <span class="facet-name">{{severityIcon val}} {{t 'severity' val}}</span>
       <span class="facet-stat">{{count}}</span>
     </a>
index 02cc4482eec71f8a0ad6c99d846b9ca889df429a..75023f2d9aa848d20a2c4ae7664e610162d08193 100644 (file)
@@ -1,8 +1,8 @@
 {{> '_issues-facet-header'}}
 
-<div class="issues-facet-list">
+<div class="search-navigator-facet-list">
   {{#each values}}
-    <a class="facet issues-facet issues-facet-half js-issues-facet" data-value="{{val}}" title="{{t 'issue.status' val}}">
+    <a class="facet search-navigator-facet search-navigator-facet-half js-facet" data-value="{{val}}" title="{{t 'issue.status' val}}">
       <span class="facet-name">{{statusIcon val}} {{t 'issue.status' val}}</span>
       <span class="facet-stat">{{count}}</span>
     </a>
index b9e3266e3ca2755e52f2d4999b08180c28ebd155..cd51e68565154140048950dd5737eaf261a80add 100644 (file)
@@ -1,36 +1,36 @@
-<div class="issues-filters-list">
+<div class="search-navigator-filters-list">
   {{#each items}}
-    <a class="issues-filters-button issues-filters-filter js-issues-filter" data-id="{{id}}">{{name}}</a>
+    <a class="search-navigator-filters-button search-navigator-filters-filter js-filter" data-id="{{id}}">{{name}}</a>
     <br>
   {{/each}}
-  <a class="issues-filters-manage" href="{{link '/issues/manage'}}"><i class="icon-settings"></i> {{t 'manage'}}</a>
+  <a class="search-navigator-filters-manage" href="{{link '/issues/manage'}}"><i class="icon-settings"></i> {{t 'manage'}}</a>
 </div>
 
-<div class="issues-filters-header">
+<div class="search-navigator-filters-header">
   {{#if state.canManageFilters}}
-    <a class="issues-filters-show-list js-issues-toggle-filters">
+    <a class="search-navigator-filters-show-list js-toggle-filters">
       <i class="icon-list"></i>&nbsp;<span class="issues-filters-name">{{> '_issues-filter-name'}}</span>
     </a>
     {{#if filter.description}}
-      <div class="issues-filters-description">{{filter.description}}</div>
+      <div class="search-navigator-filters-description">{{filter.description}}</div>
     {{/if}}
   {{else}}
-    <span class="issues-filters-name">{{t 'issues'}}</span>
+    <span class="search-navigator-filters-name">{{t 'issues'}}</span>
   {{/if}}
 </div>
 
-<div class="issues-filters-actions">
+<div class="search-navigator-filters-actions">
   <div class="button-group">
-    <button id="issues-new-search">{{t 'issue_filter.new_search'}}</button>
+    <button class="js-new-search" id="issues-new-search">{{t 'issue_filter.new_search'}}</button>
 
     {{#if state.canManageFilters}}
       {{#if filter.canModify}}
-        {{#if state.changed}}<button id="issues-filter-save">{{t 'save'}}</button>{{/if}}
+        {{#if state.changed}}<button class="js-filter-save" id="issues-filter-save">{{t 'save'}}</button>{{/if}}
       {{/if}}
-      {{#unless filter.id}}<button id="issues-filter-save-as">{{t 'save_as'}}</button>{{/unless}}
-      {{#if filter.id}}<button id="issues-filter-copy">{{t 'copy'}}</button>{{/if}}
+      {{#unless filter.id}}<button class="js-filter-save-as" id="issues-filter-save-as">{{t 'save_as'}}</button>{{/unless}}
+      {{#if filter.id}}<button class="js-filter-copy" id="issues-filter-copy">{{t 'copy'}}</button>{{/if}}
       {{#if filter.canModify}}
-        {{#if filter.id}}<button id="issues-filter-edit">{{t 'edit'}}</button>{{/if}}
+        {{#if filter.id}}<button class="js-filter-edit" id="issues-filter-edit">{{t 'edit'}}</button>{{/if}}
       {{/if}}
     {{/if}}
   </div>
index dfa704a6fb8fe115861a9f4b36f47a9aa43c6bcf..f60fecfb03ffc84eed43ac735bdfd0d13223b8ed 100644 (file)
@@ -1,10 +1,10 @@
-<div class="issues-side">
-  <div class="issues-filters"></div>
-  <div class="issues-facets"></div>
+<div class="search-navigator-side">
+  <div class="search-navigator-filters"></div>
+  <div class="search-navigator-facets"></div>
 </div>
 
-<div class="issues-workspace">
-  <div class="issues-workspace-header issues-header"></div>
-  <div class="issues-workspace-list"></div>
+<div class="search-navigator-workspace">
+  <div class="search-navigator-workspace-header"></div>
+  <div class="search-navigator-workspace-list"></div>
   <div class="issues-workspace-component-viewer"></div>
 </div>
index d693e1d1bb5f2ec4b87b736964ed3d9d06f376c8..93175e7c99b93a60569c3e70a0679aeb01cdb58d 100644 (file)
 </div>
 
 
-<div class="issues-header-actions">
+<div class="search-navigator-header-actions">
   {{#notNull state.total}}
-    <div class="issues-header-pagination">
+    <div class="search-navigator-header-pagination">
       {{#gt state.total 0}}
-        <a class="js-issues-prev icon-prev" title="{{t 'paging_previous'}}"></a>
+        <a class="js-prev icon-prev" title="{{t 'paging_previous'}}"></a>
         <span class="current">{{sum state.selectedIndex 1}} / <span id="issues-total">{{state.total}}</span></span>
-        <a class="js-issues-next icon-next" title="{{t 'paging_next'}}"></a>
+        <a class="js-next icon-next" title="{{t 'paging_next'}}"></a>
       {{else}}
         <span class="current">0 / <span id="issues-total">0</span></span>
       {{/gt}}
   {{/notNull}}
 
 
-  <div class="issues-header-buttons button-group">
-    <button id="issues-reload">{{t 'reload'}}</button>
+  <div class="search-navigator-header-buttons button-group">
+    <button id="issues-reload" class="js-reload">{{t 'reload'}}</button>
     {{#if state.canBulkChange}}
-      <button id="issues-bulk-change">{{t 'bulk_change'}}</button>
+      <button id="issues-bulk-change" class="js-bulk-change">{{t 'bulk_change'}}</button>
     {{/if}}
   </div>
 </div>
index 4f9c8376ab6eb941946d55dd3841295f25260d89..37421cb75c2dac4078fc8aa79b48ba40a014338e 100644 (file)
@@ -1,5 +1,5 @@
-<div class="js-issues-list"></div>
+<div class="js-list"></div>
 
-<div class="issues-workspace-list-more js-issues-more">
+<div class="search-navigator-workspace-list-more js-more">
   <i class="spinner"></i>
 </div>
diff --git a/server/sonar-web/src/main/js/coding-rules/app.js b/server/sonar-web/src/main/js/coding-rules/app.js
new file mode 100644 (file)
index 0000000..c42f4a4
--- /dev/null
@@ -0,0 +1,145 @@
+requirejs.config({
+  baseUrl: baseUrl + '/js',
+
+  paths: {
+    'backbone': 'third-party/backbone',
+    'backbone.marionette': 'third-party/backbone.marionette',
+    'handlebars': 'third-party/handlebars'
+  },
+
+  shim: {
+    'backbone.marionette': {
+      deps: ['backbone'],
+      exports: 'Marionette'
+    },
+    'backbone': {
+      exports: 'Backbone'
+    },
+    'handlebars': {
+      exports: 'Handlebars'
+    }
+  }
+});
+
+
+requirejs([
+  'backbone',
+  'backbone.marionette',
+
+  'coding-rules/models/state',
+  'coding-rules/layout',
+  'coding-rules/models/rules',
+  'components/navigator/models/facets',
+
+  'coding-rules/controller',
+  'components/navigator/router',
+
+  'coding-rules/workspace-list-view',
+  'coding-rules//workspace-header-view',
+
+  'coding-rules/facets-view',
+  'coding-rules/filters-view',
+
+  'common/handlebars-extensions'
+],
+    function (Backbone,
+              Marionette,
+              State,
+              Layout,
+              Rules,
+              Facets,
+              Controller,
+              Router,
+              WorkspaceListView,
+              WorkspaceHeaderView,
+              FacetsView,
+              FiltersView) {
+
+      var $ = jQuery,
+          App = new Marionette.Application(),
+          p = window.process.addBackgroundProcess();
+
+      App.addInitializer(function () {
+        this.layout = new Layout();
+        $('.coding-rules').empty().append(this.layout.render().el);
+      });
+
+      App.addInitializer(function () {
+        this.state = new State();
+        this.list = new Rules();
+        this.facets = new Facets();
+      });
+
+      App.addInitializer(function () {
+        this.controller = new Controller({
+          app: this
+        });
+      });
+
+      App.addInitializer(function () {
+        this.workspaceListView = new WorkspaceListView({
+          app: this,
+          collection: this.list
+        });
+        this.layout.workspaceListRegion.show(this.workspaceListView);
+        this.workspaceListView.bindScrollEvents();
+
+        this.workspaceHeaderView = new WorkspaceHeaderView({
+          app: this,
+          collection: this.list
+        });
+        this.layout.workspaceHeaderRegion.show(this.workspaceHeaderView);
+
+        this.facetsView = new FacetsView({
+          app: this,
+          collection: this.facets
+        });
+        this.layout.facetsRegion.show(this.facetsView);
+
+        this.filtersView = new FiltersView({
+          app: this
+        });
+        this.layout.filtersRegion.show(this.filtersView);
+      });
+
+      App.addInitializer(function () {
+        key.setScope('list');
+        this.router = new Router({
+          app: this
+        });
+        Backbone.history.start();
+        window.process.finishBackgroundProcess(p);
+      });
+
+      App.manualRepository = function () {
+        return {
+          key: 'manual',
+          name: t('coding_rules.manual_rules'),
+          language: 'none'
+        };
+      };
+
+      App.getSubCharacteristicName = function (name) {
+        return (App.characteristics[name] || '').replace(': ', ' > ');
+      };
+
+      var appXHR = $.get(baseUrl + '/api/rules/app').done(function(r) {
+        App.canWrite = r.canWrite;
+        App.qualityProfiles = _.sortBy(r.qualityprofiles, ['name', 'lang']);
+        App.languages = _.extend(r.languages, {
+          none: 'None'
+        });
+        _.map(App.qualityProfiles, function(profile) {
+          profile.language = App.languages[profile.lang];
+        });
+        App.repositories = r.repositories;
+        App.repositories.push(App.manualRepository());
+        App.statuses = r.statuses;
+        App.characteristics = r.characteristics;
+      });
+
+      $.when(window.requestMessages(), appXHR).done(function () {
+        App.start();
+      });
+
+    });
diff --git a/server/sonar-web/src/main/js/coding-rules/controller.js b/server/sonar-web/src/main/js/coding-rules/controller.js
new file mode 100644 (file)
index 0000000..3eec23d
--- /dev/null
@@ -0,0 +1,119 @@
+define([
+    'components/navigator/controller',
+    'coding-rules/rule-details-view'
+], function (Controller, RuleDetailsView) {
+
+  var $ = jQuery;
+
+  return Controller.extend({
+    allFacets: ['languages', 'repositories', 'tags', 'qprofile', 'debt_characteristics', 'severities', 'statuses'],
+    facetsFromServer: ['languages', 'repositories', 'tags'],
+    pageSize: 200,
+    ruleFields: ['name', 'lang', 'langName', 'sysTags', 'tags'],
+
+
+    _searchParameters: function () {
+      return {
+        p: this.app.state.get('page'),
+        ps: this.pageSize,
+        facets: true,
+        f: this.ruleFields.join()
+      };
+    },
+
+    fetchList: function (firstPage) {
+      firstPage = firstPage == null ? true : firstPage;
+      if (firstPage) {
+        this.app.state.set({ selectedIndex: 0, page: 1 }, { silent: true });
+      }
+
+      var that = this,
+          url = baseUrl + '/api/rules/search',
+          options = _.extend(this._searchParameters(), this.app.state.get('query')),
+          p = window.process.addBackgroundProcess();
+      return $.get(url, options).done(function (r) {
+        var rules = that.app.list.parseRules(r);
+        if (firstPage) {
+          that.app.list.reset(rules);
+        } else {
+          that.app.list.add(rules);
+        }
+        that.app.list.setIndex();
+        that.app.facets.reset(that._allFacets());
+        that.app.facets.add(r.facets, { merge: true });
+        that.enableFacets(that._enabledFacets());
+        that.app.state.set({
+          page: r.p,
+          pageSize: r.ps,
+          total: r.total,
+          maxResultsReached: r.p * r.ps >= r.total
+        });
+        window.process.finishBackgroundProcess(p);
+      }).fail(function () {
+        window.process.failBackgroundProcess(p);
+      });
+    },
+
+    requestFacet: function (id) {
+      var url = baseUrl + '/api/rules/search',
+          facet = this.app.facets.get(id),
+          options = _.extend({ facets: true, ps: 1 }, this.app.state.get('query'));
+      return $.get(url, options).done(function (r) {
+        var facetData = _.findWhere(r.facets, { property: id });
+        if (facetData) {
+          facet.set(facetData);
+        }
+      });
+    },
+
+    parseQuery: function () {
+      var q = Controller.prototype.parseQuery.apply(this, arguments);
+      delete q.asc;
+      delete q.s;
+      return q;
+    },
+
+    getRuleDetails: function (rule) {
+      var url = baseUrl + '/api/rules/show',
+          options = {
+            key: rule.id,
+            actives: true
+          };
+      return $.get(url, options).done(function (data) {
+        rule.set(data.rule);
+      });
+    },
+
+    showDetails: function (rule) {
+      var that = this;
+      this.app.layout.workspaceDetailsRegion.reset();
+      this.getRuleDetails(rule).done(function () {
+        key.setScope('details');
+        that.app.workspaceListView.unbindScrollEvents();
+        that.app.state.set({ rule: rule });
+        that.app.workspaceDetailsView = new RuleDetailsView({
+          app: that.app,
+          model: rule
+        });
+        that.app.layout.workspaceDetailsRegion.show(that.app.workspaceDetailsView);
+        that.app.layout.showDetails();
+      });
+    },
+
+    showDetailsForSelected: function () {
+      var rule = this.app.list.at(this.app.state.get('selectedIndex'));
+      this.showDetails(rule);
+    },
+
+    hideDetails: function () {
+      key.setScope('list');
+      this.app.state.unset('rule');
+      this.app.layout.workspaceDetailsRegion.reset();
+      this.app.layout.hideDetails();
+      this.app.workspaceListView.bindScrollEvents();
+      this.app.workspaceListView.scrollTo();
+    }
+
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/coding-rules/facets-view.js b/server/sonar-web/src/main/js/coding-rules/facets-view.js
new file mode 100644 (file)
index 0000000..6c34b39
--- /dev/null
@@ -0,0 +1,43 @@
+define([
+  'components/navigator/facets-view',
+  'coding-rules/facets/base-facet',
+  'coding-rules/facets/language-facet',
+  'coding-rules/facets/repository-facet',
+  'coding-rules/facets/quality-profile-facet',
+  'coding-rules/facets/characteristic-facet',
+  'coding-rules/facets/severity-facet',
+  'coding-rules/facets/status-facet'
+],
+    function (FacetsView,
+              BaseFacet,
+              LanguageFacet,
+              RepositoryFacet,
+              QualityProfileFacet,
+              CharacteristicFacet,
+              SeverityFacet,
+              StatusFacet) {
+
+      return FacetsView.extend({
+
+        getItemView: function (model) {
+          switch (model.get('property')) {
+            case 'languages':
+              return LanguageFacet;
+            case 'repositories':
+              return RepositoryFacet;
+            case 'qprofile':
+              return QualityProfileFacet;
+            case 'debt_characteristics':
+              return CharacteristicFacet;
+            case 'severities':
+              return SeverityFacet;
+            case 'statuses':
+              return StatusFacet;
+            default:
+              return BaseFacet;
+          }
+        }
+
+      });
+
+    });
diff --git a/server/sonar-web/src/main/js/coding-rules/facets/base-facet.js b/server/sonar-web/src/main/js/coding-rules/facets/base-facet.js
new file mode 100644 (file)
index 0000000..b757662
--- /dev/null
@@ -0,0 +1,11 @@
+define([
+    'components/navigator/facets/base-facet',
+    'templates/coding-rules'
+], function (BaseFacet, Templates) {
+
+  return BaseFacet.extend({
+    className: 'search-navigator-facet-box',
+    template: Templates['coding-rules-base-facet']
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/coding-rules/facets/characteristic-facet.js b/server/sonar-web/src/main/js/coding-rules/facets/characteristic-facet.js
new file mode 100644 (file)
index 0000000..f0ba535
--- /dev/null
@@ -0,0 +1,37 @@
+define([
+    'coding-rules/facets/base-facet'
+], function (BaseFacet) {
+
+  var $ = jQuery;
+
+  return BaseFacet.extend({
+
+    getValues: function () {
+      var values = _.map(this.options.app.characteristics, function (value, key) {
+        return {
+          label: value,
+          val: key
+        };
+      });
+      return _.sortBy(values, 'label');
+    },
+
+    toggleFacet: function (e) {
+      var obj = {},
+          property = this.model.get('property');
+      if ($(e.currentTarget).is('.active')) {
+        obj[property] = null;
+      } else {
+        obj[property] = $(e.currentTarget).data('value');
+      }
+      this.options.app.state.updateFilter(obj);
+    },
+
+    serializeData: function () {
+      return _.extend(BaseFacet.prototype.serializeData.apply(this, arguments), {
+        values: this.getValues()
+      });
+    }
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/coding-rules/facets/custom-labels-facet.js b/server/sonar-web/src/main/js/coding-rules/facets/custom-labels-facet.js
new file mode 100644 (file)
index 0000000..af54a48
--- /dev/null
@@ -0,0 +1,28 @@
+define([
+  'coding-rules/facets/base-facet'
+], function (BaseFacet) {
+
+  return BaseFacet.extend({
+
+    getLabelsSource: function () {
+      return [];
+    },
+
+    getValues: function () {
+      var that = this,
+          labels = that.getLabelsSource();
+      return this.model.getValues().map(function (item) {
+        return _.extend(item, {
+          label: labels[item.val]
+        });
+      });
+    },
+
+    serializeData: function () {
+      return _.extend(BaseFacet.prototype.serializeData.apply(this, arguments), {
+        values: this.getValues()
+      });
+    }
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/coding-rules/facets/language-facet.js b/server/sonar-web/src/main/js/coding-rules/facets/language-facet.js
new file mode 100644 (file)
index 0000000..6a89c42
--- /dev/null
@@ -0,0 +1,13 @@
+define([
+  'coding-rules/facets/custom-labels-facet'
+], function (CustomLabelsFacet) {
+
+  return CustomLabelsFacet.extend({
+
+    getLabelsSource: function () {
+      return this.options.app.languages;
+    }
+
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/coding-rules/facets/quality-profile-facet.js b/server/sonar-web/src/main/js/coding-rules/facets/quality-profile-facet.js
new file mode 100644 (file)
index 0000000..1e90e2b
--- /dev/null
@@ -0,0 +1,41 @@
+define([
+  'coding-rules/facets/base-facet'
+], function (BaseFacet) {
+
+  var $ = jQuery;
+
+  return BaseFacet.extend({
+
+    getValues: function () {
+      var that = this,
+          values = this.options.app.qualityProfiles.map(function (profile) {
+            return {
+              label: profile.name,
+              extra: that.options.app.languages[profile.lang],
+              val: profile.key
+            };
+          });
+      return _.sortBy(values, 'label');
+    },
+
+    toggleFacet: function (e) {
+      var obj = {},
+          property = this.model.get('property');
+      if ($(e.currentTarget).is('.active')) {
+        obj.activation = null;
+        obj[property] = null;
+      } else {
+        obj.activation = true;
+        obj[property] = $(e.currentTarget).data('value');
+      }
+      this.options.app.state.updateFilter(obj);
+    },
+
+    serializeData: function () {
+      return _.extend(BaseFacet.prototype.serializeData.apply(this, arguments), {
+        values: this.getValues()
+      });
+    }
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/coding-rules/facets/repository-facet.js b/server/sonar-web/src/main/js/coding-rules/facets/repository-facet.js
new file mode 100644 (file)
index 0000000..5bf8361
--- /dev/null
@@ -0,0 +1,27 @@
+define([
+  'coding-rules/facets/custom-labels-facet'
+], function (CustomLabelsFacet) {
+
+  return CustomLabelsFacet.extend({
+
+    getLabelsSource: function () {
+      var repos = this.options.app.repositories;
+      return _.object(_.pluck(repos, 'key'), _.pluck(repos, 'name'));
+    },
+
+    getValues: function () {
+      var that = this,
+          values = CustomLabelsFacet.prototype.getValues.apply(this, arguments);
+      return values.map(function (value) {
+        var repo = _.findWhere(that.options.app.repositories, { key: value.val });
+        if (repo != null) {
+          var langName = that.options.app.languages[repo.language];
+          _.extend(value, { extra: langName });
+        }
+        return value;
+      });
+    }
+
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/coding-rules/facets/severity-facet.js b/server/sonar-web/src/main/js/coding-rules/facets/severity-facet.js
new file mode 100644 (file)
index 0000000..133cc18
--- /dev/null
@@ -0,0 +1,30 @@
+define([
+    'coding-rules/facets/base-facet',
+    'templates/coding-rules'
+], function (BaseFacet, Templates) {
+
+  return BaseFacet.extend({
+    template: Templates['coding-rules-severity-facet'],
+    severities: ['BLOCKER', 'MINOR', 'CRITICAL', 'INFO', 'MAJOR'],
+
+    sortValues: function (values) {
+      var order = this.severities;
+      return _.sortBy(values, function (v) {
+        return order.indexOf(v.val);
+      });
+    },
+
+    getValues: function () {
+      return this.severities.map(function (s) {
+        return { val: s };
+      });
+    },
+
+    serializeData: function () {
+      return _.extend(BaseFacet.prototype.serializeData.apply(this, arguments), {
+        values: this.sortValues(this.getValues())
+      });
+    }
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/coding-rules/facets/status-facet.js b/server/sonar-web/src/main/js/coding-rules/facets/status-facet.js
new file mode 100644 (file)
index 0000000..3429f1a
--- /dev/null
@@ -0,0 +1,23 @@
+define([
+    'coding-rules/facets/base-facet'
+], function (BaseFacet) {
+
+  return BaseFacet.extend({
+
+    getValues: function () {
+      return ['BETA', 'DEPRECATED', 'READY'].map(function (s) {
+        return {
+          label: t('rules.status', s.toLowerCase()),
+          val: s
+        };
+      });
+    },
+
+    serializeData: function () {
+      return _.extend(BaseFacet.prototype.serializeData.apply(this, arguments), {
+        values: this.sortValues(this.getValues())
+      });
+    }
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/coding-rules/filters-view.js b/server/sonar-web/src/main/js/coding-rules/filters-view.js
new file mode 100644 (file)
index 0000000..9c2de65
--- /dev/null
@@ -0,0 +1,18 @@
+define([
+    'backbone.marionette',
+    'templates/coding-rules'
+], function (Marionette, Templates) {
+
+  return Marionette.ItemView.extend({
+    template: Templates['coding-rules-filters'],
+
+    events: {
+      'click .js-new-search': 'newSearch'
+    },
+
+    newSearch: function () {
+      this.options.app.controller.newSearch();
+    }
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/coding-rules/layout.js b/server/sonar-web/src/main/js/coding-rules/layout.js
new file mode 100644 (file)
index 0000000..f6386fa
--- /dev/null
@@ -0,0 +1,58 @@
+define([
+  'backbone.marionette',
+  'templates/coding-rules'
+], function (Marionette, Templates) {
+
+  var $ = jQuery;
+
+  return Marionette.Layout.extend({
+    template: Templates['coding-rules-layout'],
+    topOffset: 30,
+
+    regions: {
+      filtersRegion: '.search-navigator-filters',
+      facetsRegion: '.search-navigator-facets',
+      workspaceHeaderRegion: '.search-navigator-workspace-header',
+      workspaceListRegion: '.search-navigator-workspace-list',
+      workspaceDetailsRegion: '.search-navigator-workspace-details'
+    },
+
+    initialize: function () {
+      var that = this;
+      $(window).on('scroll.search-navigator-layout', function () {
+        that.onScroll();
+      });
+    },
+
+    onClose: function () {
+      $(window).off('scroll.search-navigator-layout');
+    },
+
+    onRender: function () {
+      this.$('.search-navigator-side').isolatedScroll();
+    },
+
+    onScroll: function () {
+      var scrollTop = $(window).scrollTop();
+      $('.search-navigator').toggleClass('sticky', scrollTop >= this.topOffset);
+      this.$('.search-navigator-side').css({
+        top: Math.max(0, Math.min(this.topOffset - scrollTop, this.topOffset))
+      });
+    },
+
+    showDetails: function () {
+      this.scroll = $(window).scrollTop();
+      $('.search-navigator').addClass('search-navigator-extended-view');
+    },
+
+
+    hideDetails: function () {
+      $('.search-navigator').removeClass('search-navigator-extended-view');
+      if (this.scroll != null) {
+        $(window).scrollTop(this.scroll);
+      }
+    }
+
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/coding-rules/models/rule.js b/server/sonar-web/src/main/js/coding-rules/models/rule.js
new file mode 100644 (file)
index 0000000..78c1804
--- /dev/null
@@ -0,0 +1,9 @@
+define([
+    'backbone'
+], function (Backbone) {
+
+  return Backbone.Model.extend({
+    idAttribute: 'key'
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/coding-rules/models/rules.js b/server/sonar-web/src/main/js/coding-rules/models/rules.js
new file mode 100644 (file)
index 0000000..ea0c357
--- /dev/null
@@ -0,0 +1,20 @@
+define([
+  'backbone',
+  'coding-rules/models/rule'
+], function (Backbone, Rule) {
+
+  return Backbone.Collection.extend({
+    model: Rule,
+
+    parseRules: function (r) {
+      return r.rules;
+    },
+
+    setIndex: function () {
+      this.forEach(function (rule, index) {
+        rule.set({ index: index });
+      });
+    }
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/coding-rules/models/state.js b/server/sonar-web/src/main/js/coding-rules/models/state.js
new file mode 100644 (file)
index 0000000..c69164b
--- /dev/null
@@ -0,0 +1,15 @@
+define([
+  'components/navigator/models/state'
+], function (State) {
+
+  return State.extend({
+    defaults: {
+      page: 1,
+      maxResultsReached: false,
+      query: {},
+      facets: []
+    }
+  });
+
+});
+
diff --git a/server/sonar-web/src/main/js/coding-rules/rule-details-view.js b/server/sonar-web/src/main/js/coding-rules/rule-details-view.js
new file mode 100644 (file)
index 0000000..202e169
--- /dev/null
@@ -0,0 +1,56 @@
+define([
+    'backbone.marionette',
+    'templates/coding-rules'
+], function (Marionette, Templates) {
+
+  return Marionette.ItemView.extend({
+    template: Templates['coding-rules-rule-details'],
+
+    modelEvents: {
+      'change': 'render'
+    },
+
+    initialize: function () {
+      this.bindShortcuts();
+    },
+
+    onClose: function () {
+      this.unbindShortcuts();
+    },
+
+    bindShortcuts: function () {
+      var that = this;
+      key('up', 'details', function () {
+        that.options.app.controller.selectPrev();
+        that.options.app.controller.showDetailsForSelected();
+        return false;
+      });
+      key('down', 'details', function () {
+        that.options.app.controller.selectNext();
+        that.options.app.controller.showDetailsForSelected();
+        return false;
+      });
+      key('left', 'details', function () {
+        that.options.app.controller.hideDetails();
+        return false;
+      });
+    },
+
+    unbindShortcuts: function () {
+      key.deleteScope('details');
+    },
+
+    serializeData: function () {
+      var isManual = (this.options.app.manualRepository().key === this.model.get('repo'));
+
+      return _.extend(Marionette.ItemView.prototype.serializeData.apply(this, arguments), {
+        language: this.options.app.languages[this.model.get('lang')],
+        repository: _.findWhere(this.options.app.repositories, { key: this.model.get('repo') }).name,
+        isManual: isManual,
+        subCharacteristic: this.options.app.getSubCharacteristicName(this.model.get('debtSubChar')),
+        allTags: _.union(this.model.get('sysTags'), this.model.get('tags'))
+      });
+    }
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/coding-rules/workspace-header-view.js b/server/sonar-web/src/main/js/coding-rules/workspace-header-view.js
new file mode 100644 (file)
index 0000000..fae2372
--- /dev/null
@@ -0,0 +1,20 @@
+define([
+  'components/navigator/workspace-header-view',
+  'templates/coding-rules'
+], function (WorkspaceHeaderView, Templates) {
+
+  return WorkspaceHeaderView.extend({
+    template: Templates['coding-rules-workspace-header'],
+
+    events: function () {
+      return _.extend(WorkspaceHeaderView.prototype.events.apply(this, arguments), {
+        'click .js-back': 'onBackClick'
+      });
+    },
+
+    onBackClick: function () {
+      this.options.app.controller.hideDetails();
+    }
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/coding-rules/workspace-list-item-view.js b/server/sonar-web/src/main/js/coding-rules/workspace-list-item-view.js
new file mode 100644 (file)
index 0000000..890f05d
--- /dev/null
@@ -0,0 +1,28 @@
+define([
+  'components/navigator/workspace-list-item-view',
+  'templates/coding-rules'
+], function (WorkspaceListItemView, Templates) {
+
+  return WorkspaceListItemView.extend({
+    className: 'coding-rule',
+    template: Templates['coding-rules-workspace-list-item'],
+
+    modelEvents: {
+      'change': 'render'
+    },
+
+    events: {
+      'click': 'selectCurrent',
+      'click .js-rule': 'openRule'
+    },
+
+    selectCurrent: function () {
+      this.options.app.state.set({ selectedIndex: this.model.get('index') });
+    },
+
+    openRule: function () {
+      this.options.app.controller.showDetails(this.model);
+    }
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/coding-rules/workspace-list-view.js b/server/sonar-web/src/main/js/coding-rules/workspace-list-view.js
new file mode 100644 (file)
index 0000000..56d193d
--- /dev/null
@@ -0,0 +1,49 @@
+define([
+  'components/navigator/workspace-list-view',
+  'coding-rules/workspace-list-item-view',
+  'templates/coding-rules'
+], function (WorkspaceListView, WorkspaceListItemView, Templates) {
+
+  var $ = jQuery;
+
+  return WorkspaceListView.extend({
+    template: Templates['coding-rules-workspace-list'],
+    itemView: WorkspaceListItemView,
+    itemViewContainer: '.js-list',
+
+    events: function () {
+      return {
+        'click .js-tag': 'onTagClick',
+        'click .js-lang': 'onLangClick'
+      };
+    },
+
+    bindShortcuts: function () {
+      WorkspaceListView.prototype.bindShortcuts.apply(this, arguments);
+      var that = this;
+      key('right', 'list', function () {
+        that.options.app.controller.showDetailsForSelected();
+        return false;
+      });
+    },
+
+    onTagClick: function (e) {
+      var tag = $(e.currentTarget).data('tag');
+      this.selectTag(tag);
+    },
+
+    onLangClick: function (e) {
+      var lang = $(e.currentTarget).data('lang');
+      this.selectLang(lang);
+    },
+
+    selectTag: function (tag) {
+      this.options.app.state.setQuery({ tags: tag });
+    },
+
+    selectLang: function (lang) {
+      this.options.app.state.setQuery({ languages: lang });
+    }
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/components/navigator/controller.js b/server/sonar-web/src/main/js/components/navigator/controller.js
new file mode 100644 (file)
index 0000000..d1ae597
--- /dev/null
@@ -0,0 +1,142 @@
+define([
+  'backbone.marionette'
+], function (Marionette) {
+
+  return Marionette.Controller.extend({
+    pageSize: 50,
+    allFacets: [],
+    facetsFromServer: [],
+    transform: {},
+
+    initialize: function (options) {
+      this.app = options.app;
+      this.listenTo(options.app.state, 'change:query', this.fetchList);
+    },
+
+    _allFacets: function () {
+      return this.allFacets.map(function (facet) {
+        return {property: facet};
+      });
+    },
+
+    _enabledFacets: function () {
+      var that = this,
+          facets = this.options.app.state.get('facets'),
+          criteria = Object.keys(this.options.app.state.get('query'));
+      facets = facets.concat(criteria);
+      facets = facets.map(function (facet) {
+        return that.transform[facet] != null ? that.transform[facet] : facet;
+      });
+      return facets.filter(function (facet) {
+        return that.allFacets.indexOf(facet) !== -1;
+      });
+    },
+
+    _facetsFromServer: function () {
+      var that = this,
+          facets = this._enabledFacets();
+      return facets.filter(function (facet) {
+        return that.facetsFromServer.indexOf(facet) !== -1;
+      });
+    },
+
+    fetchList: function () {
+
+    },
+
+    fetchNextPage: function () {
+      this.options.app.state.nextPage();
+      return this.fetchList(false);
+    },
+
+    enableFacet: function (id) {
+      var facet = this.options.app.facets.get(id);
+      if (facet.has('values') || this.facetsFromServer.indexOf(id) === -1) {
+        facet.set({enabled: true});
+      } else {
+        var p = window.process.addBackgroundProcess();
+        this.requestFacet(id)
+            .done(function () {
+              facet.set({enabled: true});
+              window.process.finishBackgroundProcess(p);
+            })
+            .fail(function () {
+              window.process.failBackgroundProcess(p);
+            });
+      }
+    },
+
+    disableFacet: function (id) {
+      var facet = this.options.app.facets.get(id);
+      facet.set({enabled: false});
+      this.options.app.facetsView.children.findByModel(facet).disable();
+    },
+
+    toggleFacet: function (id) {
+      var facet = this.options.app.facets.get(id);
+      if (facet.get('enabled')) {
+        this.disableFacet(id);
+      } else {
+        this.enableFacet(id);
+      }
+    },
+
+    enableFacets: function (facets) {
+      facets.forEach(this.enableFacet, this);
+    },
+
+    newSearch: function () {
+      this.options.app.state.setQuery({});
+    },
+
+    parseQuery: function (query, separator) {
+      separator = separator || '|';
+      var q = {};
+      (query || '').split(separator).forEach(function (t) {
+        var tokens = t.split('=');
+        if (tokens[0] && tokens[1] != null) {
+          q[tokens[0]] = decodeURIComponent(tokens[1]);
+        }
+      });
+      return q;
+    },
+
+    getQuery: function (separator) {
+      separator = separator || '|';
+      var filter = this.options.app.state.get('query'),
+          route = [];
+      _.map(filter, function (value, property) {
+        route.push('' + property + '=' + encodeURIComponent(value));
+      });
+      return route.join(separator);
+    },
+
+    getRoute: function (separator) {
+      separator = separator || '|';
+      return this.getQuery(separator);
+    },
+
+    selectNext: function () {
+      var index = this.options.app.state.get('selectedIndex') + 1;
+      if (index < this.options.app.list.length) {
+        this.options.app.state.set({ selectedIndex: index });
+      } else {
+        if (!this.options.app.state.get('maxResultsReached')) {
+          var that = this;
+          this.fetchNextPage().done(function () {
+            that.options.app.state.set({ selectedIndex: index });
+          });
+        }
+      }
+    },
+
+    selectPrev: function () {
+      var index = this.options.app.state.get('selectedIndex') - 1;
+      if (index >= 0) {
+        this.options.app.state.set({ selectedIndex: index });
+      }
+    }
+
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/components/navigator/facets-view.js b/server/sonar-web/src/main/js/components/navigator/facets-view.js
new file mode 100644 (file)
index 0000000..0d3f910
--- /dev/null
@@ -0,0 +1,37 @@
+define([
+  'backbone.marionette',
+  'components/navigator/facets/base-facet'
+], function (Marionette, BaseFacet) {
+
+  return Marionette.CollectionView.extend({
+    className: 'search-navigator-facets-list',
+
+    itemViewOptions: function () {
+      return {
+        app: this.options.app
+      };
+    },
+
+    getItemView: function () {
+      return BaseFacet;
+    },
+
+    collectionEvents: function () {
+      return {
+        'change:enabled': 'updateState'
+      };
+    },
+
+    updateState: function () {
+      var enabledFacets = this.collection.filter(function (model) {
+            return model.get('enabled');
+          }),
+          enabledFacetIds = enabledFacets.map(function (model) {
+            return model.id;
+          });
+      this.options.app.state.set({facets: enabledFacetIds});
+    }
+
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/components/navigator/facets/base-facet.js b/server/sonar-web/src/main/js/components/navigator/facets/base-facet.js
new file mode 100644 (file)
index 0000000..c2c894a
--- /dev/null
@@ -0,0 +1,76 @@
+define([
+    'backbone.marionette'
+], function (Marionette) {
+
+  var $ = jQuery;
+
+  return Marionette.ItemView.extend({
+    className: 'search-navigator-facet-box',
+
+    modelEvents: function () {
+      return {
+        'change': 'render'
+      };
+    },
+
+    events: function () {
+      return {
+        'click .js-facet-toggle': 'toggle',
+        'click .js-facet': 'toggleFacet'
+      };
+    },
+
+    onRender: function () {
+      this.$el.toggleClass('search-navigator-facet-box-collapsed', !this.model.get('enabled'));
+      var that = this,
+          property = this.model.get('property'),
+          value = this.options.app.state.get('query')[property];
+      if (typeof value === 'string') {
+        value.split(',').forEach(function (s) {
+          var facet = that.$('.js-facet').filter('[data-value="' + s + '"]');
+          if (facet.length > 0) {
+            facet.addClass('active');
+          }
+        });
+      }
+    },
+
+    toggle: function () {
+      this.options.app.controller.toggleFacet(this.model.id);
+    },
+
+    getValue: function () {
+      return this.$('.js-facet.active').map(function () {
+        return $(this).data('value');
+      }).get().join();
+    },
+
+    toggleFacet: function (e) {
+      $(e.currentTarget).toggleClass('active');
+      var property = this.model.get('property'),
+          obj = {};
+      obj[property] = this.getValue();
+      this.options.app.state.updateFilter(obj);
+    },
+
+    disable: function () {
+      var property = this.model.get('property'),
+          obj = {};
+      obj[property] = null;
+      this.options.app.state.updateFilter(obj);
+    },
+
+    sortValues: function (values) {
+      return _.sortBy(values, function (v) {
+        return -v.count;
+      });
+    },
+
+    serializeData: function () {
+      return _.extend(Marionette.ItemView.prototype.serializeData.apply(this, arguments), {
+        values: this.sortValues(this.model.getValues())
+      });
+    }
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/components/navigator/models/facet.js b/server/sonar-web/src/main/js/components/navigator/models/facet.js
new file mode 100644 (file)
index 0000000..7d15da0
--- /dev/null
@@ -0,0 +1,22 @@
+define([
+    'backbone'
+], function (Backbone) {
+
+  return Backbone.Model.extend({
+    idAttribute: 'property',
+
+    defaults: {
+      enabled: false
+    },
+
+    getValues: function () {
+      return this.get('values') || [];
+    },
+
+    toggle: function () {
+      var enabled = this.get('enabled');
+      this.set({ enabled: !enabled });
+    }
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/components/navigator/models/facets.js b/server/sonar-web/src/main/js/components/navigator/models/facets.js
new file mode 100644 (file)
index 0000000..88929de
--- /dev/null
@@ -0,0 +1,10 @@
+define([
+  'backbone',
+  'components/navigator/models/facet'
+], function (Backbone, Facet) {
+
+  return Backbone.Collection.extend({
+    model: Facet
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/components/navigator/models/state.js b/server/sonar-web/src/main/js/components/navigator/models/state.js
new file mode 100644 (file)
index 0000000..8a4f2ff
--- /dev/null
@@ -0,0 +1,52 @@
+define([
+    'backbone'
+], function (Backbone) {
+
+  return Backbone.Model.extend({
+    defaults: {
+      page: 1,
+      maxResultsReached: false,
+      query: {},
+      facets: []
+    },
+
+    nextPage: function () {
+      var page = this.get('page');
+      this.set({ page: page + 1 });
+    },
+
+    clearQuery: function (query) {
+      var q = {};
+      Object.keys(query).forEach(function (key) {
+        if (query[key]) {
+          q[key] = query[key];
+        }
+      });
+      return q;
+    },
+
+    _areQueriesEqual: function (a, b) {
+      var equal = Object.keys(a).length === Object.keys(b).length;
+      Object.keys(a).forEach(function (key) {
+        equal = equal && a[key] === b[key];
+      });
+      return equal;
+    },
+
+    updateFilter: function (obj) {
+      var oldQuery = this.get('query'),
+          query = _.extend({}, oldQuery, obj);
+      query = this.clearQuery(query);
+      if (!this._areQueriesEqual(oldQuery, query)) {
+        this.setQuery(query);
+      }
+    },
+
+    setQuery: function (query) {
+      this.set({ query: query }, { silent: true });
+      this.set({ changed: true });
+      this.trigger('change:query');
+    }
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/components/navigator/router.js b/server/sonar-web/src/main/js/components/navigator/router.js
new file mode 100644 (file)
index 0000000..8792dd5
--- /dev/null
@@ -0,0 +1,29 @@
+define([
+    'backbone'
+], function (Backbone) {
+
+  return Backbone.Router.extend({
+    routeSeparator: '|',
+
+    routes: {
+      '': 'index',
+      ':query': 'index'
+    },
+
+    initialize: function (options) {
+      this.options = options;
+      this.listenTo(this.options.app.state, 'change:query', this.updateRoute);
+    },
+
+    index: function (query) {
+      query = this.options.app.controller.parseQuery(query);
+      this.options.app.state.setQuery(query);
+    },
+
+    updateRoute: function () {
+      var route = this.options.app.controller.getRoute();
+      this.navigate(route);
+    }
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/components/navigator/workspace-header-view.js b/server/sonar-web/src/main/js/components/navigator/workspace-header-view.js
new file mode 100644 (file)
index 0000000..aec6efa
--- /dev/null
@@ -0,0 +1,49 @@
+define([
+    'backbone.marionette'
+], function (Marionette) {
+
+  return Marionette.ItemView.extend({
+
+    collectionEvents: function () {
+      return {
+        'all': 'render'
+      };
+    },
+
+    events: function () {
+      return {
+        'click .js-bulk-change': 'bulkChange',
+        'click .js-reload': 'reload',
+        'click .js-next': 'selectNext',
+        'click .js-prev': 'selectPrev'
+      };
+    },
+
+    initialize: function (options) {
+      this.listenTo(options.app.state, 'change', this.render);
+    },
+
+    bulkChange: function () {
+
+    },
+
+    reload: function () {
+      this.options.app.controller.fetchList();
+    },
+
+    selectNext: function () {
+      this.options.app.controller.selectNext();
+    },
+
+    selectPrev: function () {
+      this.options.app.controller.selectPrev();
+    },
+
+    serializeData: function () {
+      return _.extend(Marionette.ItemView.prototype.serializeData.apply(this, arguments), {
+        state: this.options.app.state.toJSON()
+      });
+    }
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/components/navigator/workspace-list-item-view.js b/server/sonar-web/src/main/js/components/navigator/workspace-list-item-view.js
new file mode 100644 (file)
index 0000000..b4bb669
--- /dev/null
@@ -0,0 +1,26 @@
+define([
+    'backbone.marionette'
+], function (Marionette) {
+
+  return Marionette.ItemView.extend({
+
+    initialize: function (options) {
+      this.listenTo(options.app.state, 'change:selectedIndex', this.select);
+    },
+
+    onRender: function () {
+      this.select();
+    },
+
+    select: function () {
+      var selected = this.model.get('index') === this.options.app.state.get('selectedIndex');
+      this.$el.toggleClass('selected', selected);
+    },
+
+    selectCurrent: function () {
+      this.options.app.state.set({ selectedIndex: this.model.get('index') });
+    }
+
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/components/navigator/workspace-list-view.js b/server/sonar-web/src/main/js/components/navigator/workspace-list-view.js
new file mode 100644 (file)
index 0000000..2c9ef0d
--- /dev/null
@@ -0,0 +1,112 @@
+define([
+  'backbone.marionette'
+], function (Marionette) {
+
+  var $ = jQuery;
+
+  return Marionette.CompositeView.extend({
+
+    ui: {
+      loadMore: '.js-more'
+    },
+
+    itemViewOptions: function () {
+      return {
+        app: this.options.app
+      };
+    },
+
+    collectionEvents: {
+      'reset': 'scrollToTop'
+    },
+
+    initialize: function (options) {
+      this.loadMoreThrottled = _.throttle(this.loadMore, 1000, {trailing: false});
+      this.listenTo(options.app.state, 'change:maxResultsReached', this.toggleLoadMore);
+      this.listenTo(options.app.state, 'change:selectedIndex', this.scrollTo);
+      this.bindShortcuts();
+    },
+
+    onClose: function () {
+      this.unbindScrollEvents();
+      this.unbindShortcuts();
+    },
+
+    toggleLoadMore: function () {
+      this.ui.loadMore.toggle(!this.options.app.state.get('maxResultsReached'));
+    },
+
+    bindScrollEvents: function () {
+      var that = this;
+      $(window).on('scroll.workspace-list-view', function () {
+        that.onScroll();
+      });
+    },
+
+    unbindScrollEvents: function () {
+      $(window).off('scroll.workspace-list-view');
+    },
+
+    bindShortcuts: function () {
+      var that = this;
+      key('up', 'list', function () {
+        that.options.app.controller.selectPrev();
+        return false;
+      });
+
+      key('down', 'list', function () {
+        that.options.app.controller.selectNext();
+        return false;
+      });
+    },
+
+    loadMore: function () {
+      if (!this.options.app.state.get('maxResultsReached')) {
+        var that = this;
+        this.unbindScrollEvents();
+        this.options.app.controller.fetchNextPage().done(function () {
+          that.bindScrollEvents();
+        });
+      }
+    },
+
+    disablePointerEvents: function () {
+      clearTimeout(this.scrollTimer);
+      $('body').addClass('disabled-pointer-events');
+      this.scrollTimer = setTimeout(function () {
+        $('body').removeClass('disabled-pointer-events');
+      }, 250);
+    },
+
+    onScroll: function () {
+      this.disablePointerEvents();
+      if ($(window).scrollTop() + $(window).height() >= this.ui.loadMore.offset().top) {
+        this.loadMoreThrottled();
+      }
+    },
+
+    scrollToTop: function () {
+      this.$el.scrollParent().scrollTop(0);
+    },
+
+    scrollTo: function () {
+      var selected = this.collection.at(this.options.app.state.get('selectedIndex'));
+      if (selected == null) {
+        return;
+      }
+      var selectedView = this.children.findByModel(selected),
+          viewTop = selectedView.$el.offset().top,
+          viewBottom = selectedView.$el.offset().top + selectedView.$el.outerHeight(),
+          windowTop = $(window).scrollTop(),
+          windowBottom = windowTop + $(window).height();
+      if (viewTop < windowTop) {
+        $(window).scrollTop(viewTop);
+      }
+      if (viewBottom > windowBottom) {
+        $(window).scrollTop($(window).scrollTop() - windowBottom + viewBottom);
+      }
+    }
+
+  });
+
+});
index 9e764d9e66d6b7d7ed84f0bda88f3fa44576a5bf..56be033ca945a948972fa18d3277a99fb1d0867e 100644 (file)
@@ -44,16 +44,16 @@ casper.test.begin(testName('Base'), function (test) {
           test.assertSelectorContains('.issue', '1 more branches need to be covered by unit tests to reach');
 
           // Filters
-          test.assertExists('.js-issues-toggle-filters');
-          test.assertExists('#issues-new-search');
-          test.assertExists('#issues-filter-save-as');
+          test.assertExists('.js-toggle-filters');
+          test.assertExists('.js-new-search');
+          test.assertExists('.js-filter-save-as');
 
           // Workspace header
           test.assertSelectorContains('#issues-total', '4623');
-          test.assertExists('.js-issues-prev');
-          test.assertExists('.js-issues-next');
-          test.assertExists('#issues-reload');
-          test.assertExists('#issues-bulk-change');
+          test.assertExists('.js-prev');
+          test.assertExists('.js-next');
+          test.assertExists('.js-reload');
+          test.assertExists('.js-bulk-change');
         });
       })
 
index 32cfa03214d226cedf9890ff63f8c4a5cafb3ba6..cfdb7c9c011f5bd43490c968a4aaffe6797e47a9 100644 (file)
@@ -3,7 +3,7 @@ extends ./layouts/main
 block header
   script(src='../js/require.js')
   script.
-    window.waitForMocks('/js/coding-rules/app.js');
+    window.waitForMocks('/js/coding-rules-old/app.js');
 
 block body
   #content
index 28333bca7a8e587c5ec780ef75326451c54fe226..622c74d61df47ef5259abd0525b94a91314672c0 100644 (file)
@@ -4,3 +4,5 @@
 @import "components/modals";
 @import "components/issues";
 @import "components/measures";
+@import "components/rules";
+@import "components/search-navigator";
diff --git a/server/sonar-web/src/main/less/components/rules.less b/server/sonar-web/src/main/less/components/rules.less
new file mode 100644 (file)
index 0000000..affe5c4
--- /dev/null
@@ -0,0 +1,59 @@
+@import (reference) "../variables";
+@import (reference) "../mixins";
+@import (reference) "../ui";
+
+@leftPadding: 10px;
+@rightPadding: 10px;
+@topPadding: 8px;
+@bottomPadding: 8px;
+@lineHeight: @baseFontSize * 1.5;
+
+.coding-rule {
+  padding: @topPadding @rightPadding @bottomPadding @topPadding;
+  border: 1px solid transparent;
+  background-color: #fff;
+
+  &.selected {
+    border-color: @blue !important;
+  }
+}
+
+.coding-rule + .coding-rule {
+  border-top-color: @barBorderColor;
+}
+
+.coding-rule.selected + .coding-rule {
+  border-top-color: transparent;
+}
+
+.coding-rule-inner {
+  .justify;
+  margin-bottom: -16px;
+}
+
+.coding-rule-title {
+  display: inline-block;
+  vertical-align: baseline;
+  line-height: @lineHeight;
+  font-size: @baseFontSize;
+}
+
+.coding-rule-meta {
+  display: inline-block;
+  vertical-align: baseline;
+  line-height: @lineHeight;
+  font-size: @smallFontSize;
+
+  .icon-tags:before {
+    color: @secondFontColor;
+    font-size: @smallFontSize;
+  }
+
+  .js-tag:after {
+    content: ",";
+  }
+
+  .js-tag:last-child:after {
+    content: "";
+  }
+}
diff --git a/server/sonar-web/src/main/less/components/search-navigator.less b/server/sonar-web/src/main/less/components/search-navigator.less
new file mode 100644 (file)
index 0000000..e3ea4d5
--- /dev/null
@@ -0,0 +1,324 @@
+@import (reference) "../variables";
+@import (reference) "../mixins";
+@import (reference) "../ui";
+
+@sideWidth: 300px;
+
+.search-navigator {
+
+  &.sticky {
+
+    .search-navigator-workspace-header {
+      position: fixed;
+      z-index: 4;
+      top: 0;
+      left: @sideWidth;
+      right: 0px;
+    }
+
+    .search-navigator-workspace-list {
+      padding-top: 22px + 5px + 5px + 1px + 10px;
+    }
+
+    .search-navigator-side {
+      position: fixed;
+      z-index: 4;
+      top: 0;
+      bottom: 0;
+      overflow-y: auto;
+    }
+
+  }
+}
+
+.search-navigator-side {
+  position: fixed;
+  z-index: 100;
+  width: @sideWidth;
+  top: 30px; left: 0; bottom: 0;
+  .box-sizing(border-box);
+  background-color: @barBorderColor;
+  overflow-x: hidden;
+}
+
+.search-navigator-facet-box {
+  border-top: 1px solid @barBorderColor;
+  background-color: @barBackgroundColor;
+  font-size: @baseFontSize;
+}
+
+.search-navigator-facet-box-collapsed {
+  background-color: transparent;
+
+  .search-navigator-facet-list,
+  .search-navigator-facet-container {
+    display: none;
+  }
+
+  .search-navigator-facet-header {
+    color: @secondFontColor;
+    font-weight: 400;
+
+    &:hover { color: @blue; }
+  }
+}
+
+.search-navigator-facet {
+  position: relative;
+  width: 100%;
+  margin: 0 0 1px 0;
+  border-color: transparent;
+  .box-sizing(border-box);
+  background-color: @barBackgroundColor;
+  white-space: normal;
+  overflow-x: hidden;
+
+  .facet-name {
+    white-space: nowrap;
+    background-color: @barBackgroundColor;
+    color: @baseFontColor;
+  }
+
+  .facet-stat {
+    position: absolute;
+    top: 0; right: 0;
+    padding: 4px 5px;
+    border: none;
+    background-color: @barBackgroundColor;
+
+    &:before {
+      content: " ";
+      position: absolute;
+      top: 0; bottom: 0; right: 100%;
+      width: 10px;
+      background-image: linear-gradient(to right, fade(@barBackgroundColor, 0%), @barBackgroundColor 75%);
+    }
+  }
+
+  &.active .facet-stat:before {
+    background-image: linear-gradient(to right, fade(@lightBlue, 0%), @lightBlue 75%);
+  }
+}
+
+.search-navigator-facet-half {
+  width: 45%;
+
+  &:nth-child(odd) {
+    margin-right: 10%;
+  }
+}
+
+.search-navigator-facet-header {
+  display: block;
+  padding: 6px 10px;
+  border-bottom: none;
+  color: @baseFontColor;
+  font-weight: 500;
+}
+
+.search-navigator-facet-list {
+  margin: 0 0 0 0;
+  padding: 0 10px 10px;
+  font-size: 0;
+}
+
+.search-navigator-facet-list-align-right {
+
+  .facet-name {
+    float: right;
+
+    &:before {
+      content: " ";
+      position: absolute;
+      top: 0; bottom: 0; left: 0;
+      width: 10px;
+      background-image: linear-gradient(to left, fade(@barBackgroundColor, 0%), @barBackgroundColor 75%);
+    }
+  }
+
+  .facet-stat:before {
+    display: none;
+  }
+
+  .facet.active .facet-name:before {
+    background-image: linear-gradient(to left, fade(@lightBlue, 0%), @lightBlue 75%);
+  }
+
+}
+
+.search-navigator-facet-container {
+  margin-top: 6px;
+  padding: 0 10px 16px;
+}
+
+.search-navigator-facet-custom-value {
+  padding: 0 0 5px;
+  font-size: @baseFontSize;
+}
+
+.search-navigator-facet-input {
+  width: @sideWidth * 0.4;
+}
+
+.search-navigator-filters {
+  position: relative;
+  .clearfix;
+  padding: 5px 10px;
+  background-color: @barBackgroundColor;
+}
+
+.search-navigator-filters-selected {
+  margin-bottom: 5px;
+
+  .search-navigator-filters-header {
+    float: none;
+  }
+
+  .search-navigator-filters-actions {
+    float: none;
+    margin-top: 5px;
+  }
+}
+
+.search-navigator-filters-list {
+  display: none;
+  position: absolute;
+  z-index: 6;
+  top: 31px;
+  left: 0;
+  right: 10px;
+  margin-bottom: 8px;
+  padding: 5px 10px;
+  border: 1px solid #e8e8e8;
+  .box-sizing(border-box);
+  line-height: 1.5;
+  background-color: #fff;
+  box-shadow: @defaultShadow;
+}
+
+.search-navigator-filters-filter {
+
+}
+
+.search-navigator-filters-header {
+  float: left;
+  line-height: 22px;
+}
+
+.search-navigator-filters-name {
+  vertical-align: top;
+  font-size: @bigFontSize;
+}
+
+.search-navigator-filters-description {
+  margin: 4px 0;
+  font-size: @smallFontSize;
+  font-style: italic;
+}
+
+.search-navigator-filters-show-list {
+  margin-right: 4px;
+  border-bottom: none;
+  color: @baseFontColor;
+  font-size: @iconSmallFontSize;
+}
+
+.search-navigator-filters-actions {
+  float: right;
+}
+
+.search-navigator-filters-manage {
+  display: inline-block;
+  margin-top: 4px;
+  border-bottom: none;
+}
+
+.search-navigator-workspace {
+  padding-left: @sideWidth;
+}
+
+.search-navigator-workspace-header {
+  position: relative;
+  margin-bottom: 10px;
+  padding: 5px 0;
+  line-height: 22px;
+  border-bottom: 1px solid @barBorderColor;
+  background-color: @barBackgroundColor;
+  font-size: @smallFontSize;
+
+  .button-group,
+  .button-group > button,
+  .button-group > .button {
+    vertical-align: top;
+  }
+}
+
+.search-navigator-header-component {
+  margin-left: 10px;
+  white-space: nowrap;
+}
+
+.search-navigator-header-actions {
+  position: absolute;
+  top: 0;
+  right: 0;
+  padding: 5px 10px;
+  background-color: @barBackgroundColor;
+  font-size: 0;
+  white-space: nowrap;
+
+  &:before {
+    content: " ";
+    position: absolute;
+    top: 0; bottom: 0; right: 100%;
+    width: 10px;
+    background-image: linear-gradient(to right, fade(@barBackgroundColor, 0%), @barBackgroundColor 75%);
+  }
+}
+
+.search-navigator-header-pagination {
+  display: inline-block;
+  vertical-align: top;
+  margin-right: 20px;
+  font-size: @smallFontSize;
+}
+
+.search-navigator-header-buttons {
+  vertical-align: top;
+}
+
+.search-navigator-workspace-list {
+  padding: 0 5px;
+
+  .issue {
+    max-width: none;
+  }
+}
+
+.search-navigator-workspace-details {
+  display: none;
+  padding: 0 10px;
+}
+
+.search-navigator-workspace-list-more {
+  margin-top: 10px;
+  padding: 5px 10px;
+  text-align: center;
+}
+
+.search-navigator-no-results {
+  padding-top: 10%;
+  color: @secondFontColor;
+  text-align: center;
+}
+
+.search-navigator-extended-view {
+
+  .search-navigator-workspace-list {
+    display: none;
+  }
+
+  .search-navigator-workspace-details {
+    display: block;
+  }
+}
index 2948a304938c97d8d369c6bd04971cb260278d9f..1bb3b601012628465ae96ed0b6ab8af1ae9555ef 100644 (file)
 
   &.sticky {
 
-    .issues-workspace-header {
-      position: fixed;
-      z-index: 4;
-      top: 0;
-      left: @sideWidth;
-      right: 0px;
-    }
-
     .issues-workspace-list,
     .issues-workspace-component-viewer {
       padding-top: 22px + 5px + 5px + 1px + 10px;
     }
 
-    .issues-side {
-      position: fixed;
-      z-index: 4;
-      top: 0;
-      bottom: 0;
-      overflow-y: auto;
-    }
-
-  }
-}
-
-.issues-side {
-  position: fixed;
-  z-index: 100;
-  width: @sideWidth;
-  top: 30px; left: 0; bottom: 0;
-  .box-sizing(border-box);
-  background-color: @barBorderColor;
-  overflow-x: hidden;
-}
-
-.issues-facet-box {
-  border-top: 1px solid @barBorderColor;
-  background-color: @barBackgroundColor;
-  font-size: @baseFontSize;
-}
-
-.issues-facet-box-collapsed {
-  background-color: transparent;
-
-  .issues-facet-list,
-  .issues-facet-container {
-    display: none;
-  }
-
-  .issues-facet-header {
-    color: @secondFontColor;
-    font-weight: 400;
-
-    &:hover { color: @blue; }
-  }
-}
-
-.issues-facet {
-  position: relative;
-  width: 100%;
-  margin: 0 0 1px 0;
-  border-color: transparent;
-  .box-sizing(border-box);
-  background-color: @barBackgroundColor;
-  white-space: normal;
-  overflow-x: hidden;
-
-  .facet-name {
-    white-space: nowrap;
-    background-color: @barBackgroundColor;
-    color: @baseFontColor;
-  }
-
-  .facet-stat {
-    position: absolute;
-    top: 0; right: 0;
-    padding: 4px 5px;
-    border: none;
-    background-color: @barBackgroundColor;
-
-    &:before {
-      content: " ";
-      position: absolute;
-      top: 0; bottom: 0; right: 100%;
-      width: 10px;
-      background-image: linear-gradient(to right, fade(@barBackgroundColor, 0%), @barBackgroundColor 75%);
-    }
-  }
-
-  &.active .facet-stat:before {
-    background-image: linear-gradient(to right, fade(@lightBlue, 0%), @lightBlue 75%);
   }
 }
 
-.issues-facet-half {
-  width: 45%;
-
-  &:nth-child(odd) {
-    margin-right: 10%;
-  }
-}
-
-.issues-facet-header {
-  display: block;
-  padding: 6px 10px;
-  border-bottom: none;
-  color: @baseFontColor;
-  font-weight: 500;
-}
-
-.issues-facet-list {
-  margin: 0 0 0 0;
-  padding: 0 10px 10px;
-  font-size: 0;
-}
-
-.issues-facet-list-align-right {
-
-  .facet-name {
-    float: right;
-
-    &:before {
-      content: " ";
-      position: absolute;
-      top: 0; bottom: 0; left: 0;
-      width: 10px;
-      background-image: linear-gradient(to left, fade(@barBackgroundColor, 0%), @barBackgroundColor 75%);
-    }
-  }
-
-  .facet-stat:before {
-    display: none;
-  }
-
-  .facet.active .facet-name:before {
-    background-image: linear-gradient(to left, fade(@lightBlue, 0%), @lightBlue 75%);
-  }
-
-}
-
-.issues-facet-container {
-  margin-top: 6px;
-  padding: 0 10px 16px;
-}
-
-.issues-facet-custom-value {
-  padding: 0 0 5px;
-  font-size: @baseFontSize;
-}
-
-.issues-facet-input {
-  width: @sideWidth * 0.4;
-//  .box-sizing(border-box);
-}
-
-.issues-filters {
-  position: relative;
-  .clearfix;
-  padding: 5px 10px;
-  background-color: @barBackgroundColor;
-}
-
-.issues-filters-selected {
-  margin-bottom: 5px;
-
-  .issues-filters-header {
-    float: none;
-  }
-
-  .issues-filters-actions {
-    float: none;
-    margin-top: 5px;
-  }
-}
-
-.issues-filters-list {
-  display: none;
-  position: absolute;
-  z-index: 6;
-  top: 31px;
-  left: 0;
-  right: 10px;
-  margin-bottom: 8px;
-  padding: 5px 10px;
-  border: 1px solid #e8e8e8;
-  .box-sizing(border-box);
-  line-height: 1.5;
-  background-color: #fff;
-  box-shadow: @defaultShadow;
-}
-
-.issues-filters-filter {
-
-}
-
-.issues-filters-header {
-  float: left;
-  line-height: 22px;
-}
-
-.issues-filters-name {
-  vertical-align: top;
-  font-size: @bigFontSize;
-}
-
-.issues-filters-description {
-  margin: 4px 0;
-  font-size: @smallFontSize;
-  font-style: italic;
-}
-
-.issues-filters-show-list {
-  margin-right: 4px;
-  border-bottom: none;
-  color: @baseFontColor;
-  font-size: @iconSmallFontSize;
-}
-
-.issues-filters-actions {
-  float: right;
-}
-
-.issues-filters-manage {
-  display: inline-block;
-  margin-top: 4px;
-  border-bottom: none;
-}
-
-.issues-workspace {
-  padding-left: @sideWidth;
-}
-
-.issues-header {
-  position: relative;
-  margin-bottom: 10px;
-  padding: 5px 0;
-  line-height: 22px;
-  border-bottom: 1px solid @barBorderColor;
-  background-color: @barBackgroundColor;
-  font-size: @smallFontSize;
-
-  .button-group,
-  .button-group > button,
-  .button-group > .button {
-    vertical-align: top;
-  }
-}
-
-.issues-header-component {
-  margin-left: 10px;
-  white-space: nowrap;
-}
-
-.issues-header-actions {
-  position: absolute;
-  top: 0;
-  right: 0;
-  padding: 5px 10px;
-  background-color: @barBackgroundColor;
-  font-size: 0;
-  white-space: nowrap;
-
-  &:before {
-    content: " ";
-    position: absolute;
-    top: 0; bottom: 0; right: 100%;
-    width: 10px;
-    background-image: linear-gradient(to right, fade(@barBackgroundColor, 0%), @barBackgroundColor 75%);
-  }
-}
-
-.issues-header-pagination {
-  display: inline-block;
-  vertical-align: top;
-  margin-right: 20px;
-  font-size: @smallFontSize;
-}
-
-.issues-header-buttons {
-  vertical-align: top;
-}
-
-.issues-workspace-list {
-  padding: 0 5px;
-
-  .issue {
-    max-width: none;
-  }
-}
-
-.issues-workspace-list-more {
-  margin-top: 10px;
-  padding: 5px 10px;
-  text-align: center;
-}
-
 .issues-workspace-list-component {
   line-height: 1.5;
 }
 
 .issues-extended-view {
 
-  .issues-workspace-list {
+  .search-navigator-workspace-list {
     display: none;
   }
 
 
 }
 
-.issues-no-results {
-  padding-top: 10%;
-  color: @secondFontColor;
-  text-align: center;
-}
-
 .code-issue-modern {
   outline: 1px solid @barBorderColor;
   border-left: 2px solid transparent;
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/coding_rules_old_controller.rb b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/coding_rules_old_controller.rb
new file mode 100644 (file)
index 0000000..3011a79
--- /dev/null
@@ -0,0 +1,30 @@
+#
+# SonarQube, open source software quality management tool.
+# Copyright (C) 2008-2014 SonarSource
+# mailto:contact AT sonarsource DOT com
+#
+# SonarQube is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# SonarQube is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+
+class CodingRulesOldController < ApplicationController
+
+  SECTION=Navigation::SECTION_CODING_RULES_OLD
+
+  # GET /coding_rules_old/index
+  def index
+
+  end
+
+end
index 4b690d90178c3aa238c1d26f7de9c1fd13f85c1f..fbe166a9cbbb26a591fe2c90e1f3b0d55bf24e8e 100644 (file)
@@ -36,4 +36,5 @@ class Navigation
   SECTION_QUALITY_PROFILES = Navigation.new('quality_profiles', false)
   SECTION_QUALITY_GATES = Navigation.new('quality_gates', false)
   SECTION_CODING_RULES = Navigation.new('coding_rules', false)
+  SECTION_CODING_RULES_OLD = Navigation.new('coding_rules_old', false)
 end
index 0d190ef7d3c72a23dec5687dd03c3816601881f3..3d13e30672a4713b43b092337339595713caa07e 100644 (file)
@@ -3,6 +3,4 @@
 <% end %>
 
 
-<div id="coding-rules-page-loader" class="navigator-page-loader">
-  <i class="spinner"></i>
-</div>
+<div class="coding-rules search-navigator"></div>
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/coding_rules_old/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/coding_rules_old/index.html.erb
new file mode 100644 (file)
index 0000000..116f5fa
--- /dev/null
@@ -0,0 +1,8 @@
+<% content_for :script do %>
+  <script data-main="<%= ApplicationController.root_context -%>/js/coding-rules-old/app" src="<%= ApplicationController.root_context -%>/js/require.js"></script>
+<% end %>
+
+
+<div id="coding-rules-page-loader" class="navigator-page-loader">
+  <i class="spinner"></i>
+</div>
index 3643c2080737ddadb05ce4b14095a8fc6419a9af..5d8052da4ddcc1f558fb6b5df998fe94cd95236c 100644 (file)
@@ -2,4 +2,4 @@
   <script data-main="<%= ApplicationController.root_context -%>/js/issues/app" src="<%= ApplicationController.root_context -%>/js/require.js"></script>
 <% end %>
 
-<div class="issues"></div>
+<div class="issues search-navigator"></div>
index fd4844050c6c6090670b1e8f95398ad4352ecd4c..e52d7018a1963617dab79e404f7f4bb9b7daa447 100644 (file)
           <a href="<%= ApplicationController.root_context -%>/issues/index" class="<%= 'selected' if selected_section==Navigation::SECTION_ISSUES -%>"><%= message('issues.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>
+          <a href="<%= ApplicationController.root_context -%>/coding_rules" class="<%= 'selected' if selected_section==Navigation::SECTION_CODING_RULES -%>">NEW <%= message('coding_rules.page') -%></a>
+        </li>
+        <li>
+            <a href="<%= ApplicationController.root_context -%>/coding_rules_old" class="<%= 'selected' if selected_section==Navigation::SECTION_CODING_RULES_OLD -%>"><%= message('coding_rules.page') -%></a>
         </li>
         <li>
           <a href="<%= ApplicationController.root_context -%>/profiles" class="<%= 'selected' if selected_section==Navigation::SECTION_QUALITY_PROFILES -%>"><%= message('quality_profiles.page') -%></a>
index bf32d5f404ae06a22ad339528a4aa6989d8310b3..1939732aa9870ed9f73fd7f1cb02bd605413dd41 100644 (file)
@@ -1792,6 +1792,7 @@ coding_rules.found=Found
 coding_rules.inherits="{0}" inherits from "{1}"
 coding_rules.key=Key:
 coding_rules.manual_rule=Manual Rule
+coding_rules.manual_rules=Manual Rules
 coding_rules.new_search=New Search
 coding_rules.no_results=No Coding Rules
 coding_rules.no_tags=No tags
@@ -1809,6 +1810,7 @@ coding_rules.quality_profiles.template_caption=This rule template was activated
 coding_rules.quality_profile=Quality Profile
 coding_rules.reactivate=Reactivate
 coding_rules.reactivate.help=A rule with the same key has been previously deleted. Please reactivate the existing rule or modify the key to create a new rule.
+coding_rules.return_to_list=Return to List
 coding_rules.remove_extended_description.confirm=Are you sure you want to remove the extended description?
 coding_rules.repository=Repository:
 coding_rules.revert_to_parent_definition=Revert to Parent Definition
@@ -1847,6 +1849,14 @@ coding_rules.filters.template=Templates
 coding_rules.filters.template.is_template=Show Templates Only
 coding_rules.filters.template.is_not_template=Hide Templates
 
+coding_rules.facet.languages=Language
+coding_rules.facet.repositories=Repository
+coding_rules.facet.tags=Tag
+coding_rules.facet.qprofile=Quality Profile
+coding_rules.facet.debt_characteristics=Characteristic
+coding_rules.facet.severities=Severity
+coding_rules.facet.statuses=Status
+
 coding_rules.facets.languages=Languages
 coding_rules.facets.tags=Tags
 coding_rules.facets.repositories=Repositories