From da74d65ac8398d6afb63fede473d977a8becf7fb Mon Sep 17 00:00:00 2001 From: Stas Vilchik Date: Fri, 28 Feb 2014 15:48:21 +0100 Subject: [PATCH] Quality Gates: new layout, some other improvements --- .../resources/org/sonar/l10n/core.properties | 2 + .../controllers/quality_gates_controller.rb | 2 + .../app/views/quality_gates/index.html.erb | 14 +-- .../_quality_gate_actions_template.hbs.erb | 7 ++ ...ity_gate_detail_condition_template.hbs.erb | 2 +- ...ty_gate_detail_conditions_template.hbs.erb | 4 +- ...uality_gate_detail_header_template.hbs.erb | 4 +- ...lity_gate_detail_projects_template.hbs.erb | 8 +- ...lity_gate_detail_renaming_template.hbs.erb | 10 -- .../_quality_gate_detail_template.hbs.erb | 11 +- .../_quality_gate_edit_template.hbs.erb | 22 ++++ ...ty_gate_sidebar_list_item_template.hbs.erb | 2 +- ...quality_gate_sidebar_list_template.hbs.erb | 4 - .../src/main/webapp/javascripts/issues/app.js | 2 +- .../javascripts/quality-gate/app.coffee | 26 ++++- .../webapp/javascripts/quality-gate/app.js | 23 +++- .../javascripts/quality-gate/router.coffee | 25 +++-- .../webapp/javascripts/quality-gate/router.js | 29 +++-- .../views/quality-gate-actions-view.coffee | 22 ++++ .../quality-gate-detail-condition-view.coffee | 16 ++- .../quality-gate-detail-condition-view.js | 21 +++- .../quality-gate-detail-header-view.coffee | 30 ++++-- .../views/quality-gate-detail-header-view.js | 27 ++++- .../quality-gate-detail-projects-view.coffee | 39 +++---- .../quality-gate-detail-projects-view.js | 52 ++++----- .../quality-gate-detail-renaming-view.coffee | 43 -------- .../quality-gate-detail-renaming-view.js | 60 ----------- .../views/quality-gate-detail-view.coffee | 53 ++------- .../views/quality-gate-detail-view.js | 60 ++--------- .../views/quality-gate-edit-view.coffee | 65 +++++++++++ .../views/quality-gate-edit-view.js | 101 ++++++++++++++++++ ...quality-gate-sidebar-list-item-view.coffee | 2 +- .../quality-gate-sidebar-list-item-view.js | 2 +- .../quality-gate-sidebar-list-view.coffee | 23 +--- .../views/quality-gate-sidebar-list-view.js | 26 +---- .../src/main/webapp/stylesheets/navigator.css | 4 +- .../webapp/stylesheets/navigator/base.css | 4 +- .../webapp/stylesheets/navigator/base.less | 4 +- .../main/webapp/stylesheets/quality-gates.css | 93 +++++----------- .../webapp/stylesheets/quality-gates.less | 82 ++++++-------- .../src/main/webapp/stylesheets/style.css | 4 + 41 files changed, 531 insertions(+), 499 deletions(-) create mode 100644 sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_actions_template.hbs.erb delete mode 100644 sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_detail_renaming_template.hbs.erb create mode 100644 sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_edit_template.hbs.erb delete mode 100644 sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_sidebar_list_template.hbs.erb create mode 100644 sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-actions-view.coffee delete mode 100644 sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-renaming-view.coffee delete mode 100644 sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-renaming-view.js create mode 100644 sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-edit-view.coffee create mode 100644 sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-edit-view.js diff --git a/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties b/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties index 255913424d8..b7df17c8485 100644 --- a/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties +++ b/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties @@ -1641,11 +1641,13 @@ quality_profiles.copy_new_name=New name # #------------------------------------------------------------------------------ +quality_gates.add=Add Quality Gate quality_gates.conditions=Conditions quality_gates.projects=Projects quality_gates.add_condition=Add Condition quality_gates.introduction=Only project measures are checked against thresholds. Modules, packages and classes are ignored. quality_gates.health_icons=Project health icons represent: +quality_gates.projects_for_default=You must not select specific projects for the default quality gate quality_gates.projects.with=With quality_gates.projects.without=Without quality_gates.projects.all=All diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/quality_gates_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/quality_gates_controller.rb index 3f7922b851a..c960a35c3de 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/quality_gates_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/quality_gates_controller.rb @@ -20,6 +20,8 @@ class QualityGatesController < ApplicationController + SECTION=Navigation::SECTION_QUALITY_GATES + # GET /quality_gates/index def index diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/index.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/index.html.erb index 04f2917d7f3..673ec7b1976 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/index.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/index.html.erb @@ -2,17 +2,19 @@ <% end %> -
+ - -
- -<%= render :partial => '/quality_gates/templates/quality_gate_sidebar_list_template.hbs' -%> <%= render :partial => '/quality_gates/templates/quality_gate_sidebar_list_item_template.hbs' -%> +<%= render :partial => '/quality_gates/templates/quality_gate_actions_template.hbs' -%> <%= render :partial => '/quality_gates/templates/quality_gate_new_template.hbs' -%> +<%= render :partial => '/quality_gates/templates/quality_gate_edit_template.hbs' -%> <%= render :partial => '/quality_gates/templates/quality_gate_detail_template.hbs' -%> <%= render :partial => '/quality_gates/templates/quality_gate_detail_header_template.hbs' -%> -<%= render :partial => '/quality_gates/templates/quality_gate_detail_renaming_template.hbs' -%> <%= render :partial => '/quality_gates/templates/quality_gate_detail_conditions_template.hbs' -%> <%= render :partial => '/quality_gates/templates/quality_gate_detail_condition_template.hbs' -%> <%= render :partial => '/quality_gates/templates/quality_gate_detail_projects_template.hbs' -%> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_actions_template.hbs.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_actions_template.hbs.erb new file mode 100644 index 00000000000..552d9e20573 --- /dev/null +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_actions_template.hbs.erb @@ -0,0 +1,7 @@ + diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_detail_condition_template.hbs.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_detail_condition_template.hbs.erb index 5380fe6094a..bf7f19f389b 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_detail_condition_template.hbs.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_detail_condition_template.hbs.erb @@ -25,7 +25,7 @@ {{#if id}} - + <%= message('delete') -%> {{else}} diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_detail_conditions_template.hbs.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_detail_conditions_template.hbs.erb index 9efb723be38..b3a3ae04cf3 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_detail_conditions_template.hbs.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_detail_conditions_template.hbs.erb @@ -1,4 +1,6 @@ diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_detail_renaming_template.hbs.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_detail_renaming_template.hbs.erb deleted file mode 100644 index fe09a668b4b..00000000000 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_detail_renaming_template.hbs.erb +++ /dev/null @@ -1,10 +0,0 @@ - diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_detail_template.hbs.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_detail_template.hbs.erb index 9290cc89df8..02742bf3f6b 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_detail_template.hbs.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_detail_template.hbs.erb @@ -1,11 +1,4 @@ diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_edit_template.hbs.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_edit_template.hbs.erb new file mode 100644 index 00000000000..6ebe5db1a5a --- /dev/null +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_edit_template.hbs.erb @@ -0,0 +1,22 @@ + diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_sidebar_list_item_template.hbs.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_sidebar_list_item_template.hbs.erb index 81b80c07b02..eafcd7dfd26 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_sidebar_list_item_template.hbs.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_sidebar_list_item_template.hbs.erb @@ -1,3 +1,3 @@ diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_sidebar_list_template.hbs.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_sidebar_list_template.hbs.erb deleted file mode 100644 index 484b4fdb097..00000000000 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/quality_gates/templates/_quality_gate_sidebar_list_template.hbs.erb +++ /dev/null @@ -1,4 +0,0 @@ - diff --git a/sonar-server/src/main/webapp/javascripts/issues/app.js b/sonar-server/src/main/webapp/javascripts/issues/app.js index 98faddb280e..84d6fbadfed 100644 --- a/sonar-server/src/main/webapp/javascripts/issues/app.js +++ b/sonar-server/src/main/webapp/javascripts/issues/app.js @@ -63,7 +63,7 @@ requirejs( NavigatorApp.addInitializer(function () { - jQuery('html').addClass('issues-page'); + jQuery('html').addClass('navigator-page issues-page'); this.appState = new Extra.AppState(); window.SS.appState = this.appState; diff --git a/sonar-server/src/main/webapp/javascripts/quality-gate/app.coffee b/sonar-server/src/main/webapp/javascripts/quality-gate/app.coffee index bc434b0fee9..9346cb288c0 100644 --- a/sonar-server/src/main/webapp/javascripts/quality-gate/app.coffee +++ b/sonar-server/src/main/webapp/javascripts/quality-gate/app.coffee @@ -27,6 +27,8 @@ requirejs [ 'quality-gate/collections/quality-gates', 'quality-gate/collections/metrics', 'quality-gate/views/quality-gate-sidebar-list-view', + 'quality-gate/views/quality-gate-actions-view', + 'quality-gate/views/quality-gate-edit-view', 'quality-gate/router' 'common/handlebars-extensions' ], ( @@ -34,6 +36,8 @@ requirejs [ QualityGates, Metrics, QualityGateSidebarListItemView, + QualityGateActionsView, + QualityGateEditView, QualityGateRouter ) -> @@ -45,6 +49,9 @@ requirejs [ else alert jqXHR.responseText + # Add html class to mark the page as navigator page + jQuery('html').addClass('navigator-page quality-gates-page'); + # Create a Quality Gate Application App = new Marionette.Application @@ -67,15 +74,28 @@ requirejs [ # Define page regions App.addRegions - sidebarRegion: '#sidebar' - contentRegion: '#content' + headerRegion: '.navigator-header' + actionsRegion: '.navigator-actions' + listRegion: '.navigator-results' + detailsRegion: '.navigator-details' + + # Construct actions bar + App.addInitializer -> + @qualityGateActionsView = new QualityGateActionsView + app: @ + @actionsRegion.show @qualityGateActionsView # Construct sidebar App.addInitializer -> @qualityGateSidebarListView = new QualityGateSidebarListItemView collection: @qualityGates app: @ - @sidebarRegion.show @qualityGateSidebarListView + @listRegion.show @qualityGateSidebarListView + + # Construct edit view + App.addInitializer -> + @qualityGateEditView = new QualityGateEditView app: @ + @qualityGateEditView.render() # Start router App.addInitializer -> diff --git a/sonar-server/src/main/webapp/javascripts/quality-gate/app.js b/sonar-server/src/main/webapp/javascripts/quality-gate/app.js index 0267a75dce9..98e67daedfe 100644 --- a/sonar-server/src/main/webapp/javascripts/quality-gate/app.js +++ b/sonar-server/src/main/webapp/javascripts/quality-gate/app.js @@ -29,7 +29,7 @@ } }); - requirejs(['backbone', 'backbone.marionette', 'handlebars', 'quality-gate/collections/quality-gates', 'quality-gate/collections/metrics', 'quality-gate/views/quality-gate-sidebar-list-view', 'quality-gate/router', 'common/handlebars-extensions'], function(Backbone, Marionette, Handlebars, QualityGates, Metrics, QualityGateSidebarListItemView, QualityGateRouter) { + requirejs(['backbone', 'backbone.marionette', 'handlebars', 'quality-gate/collections/quality-gates', 'quality-gate/collections/metrics', 'quality-gate/views/quality-gate-sidebar-list-view', 'quality-gate/views/quality-gate-actions-view', 'quality-gate/views/quality-gate-edit-view', 'quality-gate/router', 'common/handlebars-extensions'], function(Backbone, Marionette, Handlebars, QualityGates, Metrics, QualityGateSidebarListItemView, QualityGateActionsView, QualityGateEditView, QualityGateRouter) { var App; jQuery.ajaxSetup({ error: function(jqXHR) { @@ -41,6 +41,7 @@ } } }); + jQuery('html').addClass('navigator-page quality-gates-page'); App = new Marionette.Application; App.metrics = new Metrics; App.qualityGates = new QualityGates; @@ -65,15 +66,29 @@ }); }; App.addRegions({ - sidebarRegion: '#sidebar', - contentRegion: '#content' + headerRegion: '.navigator-header', + actionsRegion: '.navigator-actions', + listRegion: '.navigator-results', + detailsRegion: '.navigator-details' + }); + App.addInitializer(function() { + this.qualityGateActionsView = new QualityGateActionsView({ + app: this + }); + return this.actionsRegion.show(this.qualityGateActionsView); }); App.addInitializer(function() { this.qualityGateSidebarListView = new QualityGateSidebarListItemView({ collection: this.qualityGates, app: this }); - return this.sidebarRegion.show(this.qualityGateSidebarListView); + return this.listRegion.show(this.qualityGateSidebarListView); + }); + App.addInitializer(function() { + this.qualityGateEditView = new QualityGateEditView({ + app: this + }); + return this.qualityGateEditView.render(); }); App.addInitializer(function() { this.router = new QualityGateRouter({ diff --git a/sonar-server/src/main/webapp/javascripts/quality-gate/router.coffee b/sonar-server/src/main/webapp/javascripts/quality-gate/router.coffee index d4b29732854..010c084bff8 100644 --- a/sonar-server/src/main/webapp/javascripts/quality-gate/router.coffee +++ b/sonar-server/src/main/webapp/javascripts/quality-gate/router.coffee @@ -2,11 +2,13 @@ define [ 'backbone', 'quality-gate/models/quality-gate', 'quality-gate/views/quality-gate-detail-view', + 'quality-gate/views/quality-gate-detail-header-view', 'quality-gate/views/quality-gate-new-view' ], ( Backbone, QualityGate, QualityGateDetailView, + QualityGateDetailHeaderView, QualityGateNewView ) -> @@ -14,7 +16,6 @@ define [ routes: 'show/:id': 'show' - 'new': 'new' initialize: (options) -> @@ -25,17 +26,19 @@ define [ qualityGate = @app.qualityGates.get id if qualityGate @app.qualityGateSidebarListView.highlight id - qualityGateDetailView = new QualityGateDetailView + + qualityGateDetailHeaderView = new QualityGateDetailHeaderView app: @app model: qualityGate - @app.contentRegion.show qualityGateDetailView - qualityGateDetailView.$el.addClass 'navigator-fetching' - qualityGate.fetch().done -> - qualityGateDetailView.$el.removeClass 'navigator-fetching' + @app.headerRegion.show qualityGateDetailHeaderView + qualityGateDetailView = new QualityGateDetailView + app: @app + model: qualityGate + @app.detailsRegion.show qualityGateDetailView + qualityGateDetailView.$el.hide() - new: -> - qualityGateNewView = new QualityGateNewView - app: @app - model: new QualityGate - @app.contentRegion.show qualityGateNewView + qualityGateDetailHeaderView.showSpinner() + qualityGate.fetch().done -> + qualityGateDetailView.$el.show() + qualityGateDetailHeaderView.hideSpinner() diff --git a/sonar-server/src/main/webapp/javascripts/quality-gate/router.js b/sonar-server/src/main/webapp/javascripts/quality-gate/router.js index d2c1b41e6ce..881ceb6c8b6 100644 --- a/sonar-server/src/main/webapp/javascripts/quality-gate/router.js +++ b/sonar-server/src/main/webapp/javascripts/quality-gate/router.js @@ -3,7 +3,7 @@ var __hasProp = {}.hasOwnProperty, __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; - define(['backbone', 'quality-gate/models/quality-gate', 'quality-gate/views/quality-gate-detail-view', 'quality-gate/views/quality-gate-new-view'], function(Backbone, QualityGate, QualityGateDetailView, QualityGateNewView) { + define(['backbone', 'quality-gate/models/quality-gate', 'quality-gate/views/quality-gate-detail-view', 'quality-gate/views/quality-gate-detail-header-view', 'quality-gate/views/quality-gate-new-view'], function(Backbone, QualityGate, QualityGateDetailView, QualityGateDetailHeaderView, QualityGateNewView) { var QualityGateRouter, _ref; return QualityGateRouter = (function(_super) { __extends(QualityGateRouter, _super); @@ -14,8 +14,7 @@ } QualityGateRouter.prototype.routes = { - 'show/:id': 'show', - 'new': 'new' + 'show/:id': 'show' }; QualityGateRouter.prototype.initialize = function(options) { @@ -23,31 +22,29 @@ }; QualityGateRouter.prototype.show = function(id) { - var qualityGate, qualityGateDetailView; + var qualityGate, qualityGateDetailHeaderView, qualityGateDetailView; qualityGate = this.app.qualityGates.get(id); if (qualityGate) { this.app.qualityGateSidebarListView.highlight(id); + qualityGateDetailHeaderView = new QualityGateDetailHeaderView({ + app: this.app, + model: qualityGate + }); + this.app.headerRegion.show(qualityGateDetailHeaderView); qualityGateDetailView = new QualityGateDetailView({ app: this.app, model: qualityGate }); - this.app.contentRegion.show(qualityGateDetailView); - qualityGateDetailView.$el.addClass('navigator-fetching'); + this.app.detailsRegion.show(qualityGateDetailView); + qualityGateDetailView.$el.hide(); + qualityGateDetailHeaderView.showSpinner(); return qualityGate.fetch().done(function() { - return qualityGateDetailView.$el.removeClass('navigator-fetching'); + qualityGateDetailView.$el.show(); + return qualityGateDetailHeaderView.hideSpinner(); }); } }; - QualityGateRouter.prototype["new"] = function() { - var qualityGateNewView; - qualityGateNewView = new QualityGateNewView({ - app: this.app, - model: new QualityGate - }); - return this.app.contentRegion.show(qualityGateNewView); - }; - return QualityGateRouter; })(Backbone.Router); diff --git a/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-actions-view.coffee b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-actions-view.coffee new file mode 100644 index 00000000000..0210c3ed4dc --- /dev/null +++ b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-actions-view.coffee @@ -0,0 +1,22 @@ +define [ + 'backbone.marionette', + 'handlebars', + 'quality-gate/models/quality-gate' +], ( + Marionette, + Handlebars, + QualityGate +) -> + + class QualityGateActionsView extends Marionette.ItemView + template: Handlebars.compile jQuery('#quality-gate-actions-template').html() + + + events: + 'click #quality-gate-add': 'add' + + + add: -> + qualityGate = new QualityGate() + @options.app.qualityGateEditView.model = qualityGate + @options.app.qualityGateEditView.show() diff --git a/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-condition-view.coffee b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-condition-view.coffee index 5cf922fcfe0..7467feaa6e5 100644 --- a/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-condition-view.coffee +++ b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-condition-view.coffee @@ -9,6 +9,7 @@ define [ class QualityGateDetailConditionView extends Marionette.ItemView tagName: 'tr' template: Handlebars.compile jQuery('#quality-gate-detail-condition-template').html() + spinner: '' modelEvents: @@ -21,13 +22,15 @@ define [ warningInput: '[name=warning]' errorInput: '[name=error]' actionsBox: '.quality-gate-condition-actions' + updateButton: '.update-condition' events: - 'click .update-condition': 'saveCondition' + 'click @ui.updateButton': 'saveCondition' 'click .delete-condition': 'deleteCondition' 'click .add-condition': 'saveCondition' 'click .cancel-add-condition': 'cancelAddCondition' + 'change :input': 'enableUpdate' initialize: -> @@ -63,11 +66,13 @@ define [ showSpinner: -> - @ui.actionsBox.addClass 'navigator-fetching' + jQuery(@spinner).prependTo @ui.actionsBox + @ui.actionsBox.find(':not(.spinner)').hide() hideSpinner: -> - @ui.actionsBox.removeClass 'navigator-fetching' + @ui.actionsBox.find('.spinner').remove() + @ui.actionsBox.children().show() saveCondition: -> @@ -79,6 +84,7 @@ define [ error: @ui.errorInput.val() @model.save() .always => + @ui.updateButton.prop 'disabled', true @hideSpinner() .done => @options.collectionView.updateConditions() @@ -94,3 +100,7 @@ define [ cancelAddCondition: -> @close() + + + enableUpdate: -> + @ui.updateButton.prop 'disabled', false diff --git a/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-condition-view.js b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-condition-view.js index 2c61f70392f..5a15393ba6e 100644 --- a/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-condition-view.js +++ b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-condition-view.js @@ -17,6 +17,8 @@ QualityGateDetailConditionView.prototype.template = Handlebars.compile(jQuery('#quality-gate-detail-condition-template').html()); + QualityGateDetailConditionView.prototype.spinner = ''; + QualityGateDetailConditionView.prototype.modelEvents = { 'change:id': 'render' }; @@ -26,14 +28,16 @@ operatorSelect: '[name=operator]', warningInput: '[name=warning]', errorInput: '[name=error]', - actionsBox: '.quality-gate-condition-actions' + actionsBox: '.quality-gate-condition-actions', + updateButton: '.update-condition' }; QualityGateDetailConditionView.prototype.events = { - 'click .update-condition': 'saveCondition', + 'click @ui.updateButton': 'saveCondition', 'click .delete-condition': 'deleteCondition', 'click .add-condition': 'saveCondition', - 'click .cancel-add-condition': 'cancelAddCondition' + 'click .cancel-add-condition': 'cancelAddCondition', + 'change :input': 'enableUpdate' }; QualityGateDetailConditionView.prototype.initialize = function() { @@ -78,11 +82,13 @@ }; QualityGateDetailConditionView.prototype.showSpinner = function() { - return this.ui.actionsBox.addClass('navigator-fetching'); + jQuery(this.spinner).prependTo(this.ui.actionsBox); + return this.ui.actionsBox.find(':not(.spinner)').hide(); }; QualityGateDetailConditionView.prototype.hideSpinner = function() { - return this.ui.actionsBox.removeClass('navigator-fetching'); + this.ui.actionsBox.find('.spinner').remove(); + return this.ui.actionsBox.children().show(); }; QualityGateDetailConditionView.prototype.saveCondition = function() { @@ -95,6 +101,7 @@ error: this.ui.errorInput.val() }); return this.model.save().always(function() { + _this.ui.updateButton.prop('disabled', true); return _this.hideSpinner(); }).done(function() { return _this.options.collectionView.updateConditions(); @@ -116,6 +123,10 @@ return this.close(); }; + QualityGateDetailConditionView.prototype.enableUpdate = function() { + return this.ui.updateButton.prop('disabled', false); + }; + return QualityGateDetailConditionView; })(Marionette.ItemView); diff --git a/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-header-view.coffee b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-header-view.coffee index e8401a75442..6406d065420 100644 --- a/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-header-view.coffee +++ b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-header-view.coffee @@ -8,6 +8,11 @@ define [ class QualityGateDetailHeaderView extends Marionette.ItemView template: Handlebars.compile jQuery('#quality-gate-detail-header-template').html() + spinner: '' + + + modelEvents: + 'change': 'render' events: @@ -18,22 +23,25 @@ define [ renameQualityGate: -> - @options.detailView.showRenaming() + @options.app.qualityGateEditView.model = @model + @options.app.qualityGateEditView.show() deleteQualityGate: -> if confirm window.SS.phrases.areYouSure - @options.detailView.showHeaderSpinner() - jQuery.ajax({ + @showSpinner() + jQuery.ajax type: 'POST' url: "#{baseUrl}/api/qualitygates/destroy" data: id: @model.id - }).done => + .always => + @hideSpinner() + .done => @options.app.deleteQualityGate @model.id changeDefault: (set) -> - @options.detailView.showHeaderSpinner() + @showSpinner() data = if set then { id: @model.id } else {} method = if set then 'set_as_default' else 'unset_default' jQuery.ajax @@ -41,7 +49,7 @@ define [ url: "#{baseUrl}/api/qualitygates/#{method}" data: data .always => - @options.detailView.hideHeaderSpinner() + @hideSpinner() .done => @options.app.unsetDefaults @model.id @model.set 'default', !@model.get('default') @@ -53,3 +61,13 @@ define [ unsetAsDefault: -> @changeDefault false + + + showSpinner: -> + @$el.hide() + jQuery(@spinner).insertBefore @$el + + + hideSpinner: -> + @$el.prev().remove() + @$el.show() diff --git a/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-header-view.js b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-header-view.js index 760b0f487de..f60d30a04dd 100644 --- a/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-header-view.js +++ b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-header-view.js @@ -15,6 +15,12 @@ QualityGateDetailHeaderView.prototype.template = Handlebars.compile(jQuery('#quality-gate-detail-header-template').html()); + QualityGateDetailHeaderView.prototype.spinner = ''; + + QualityGateDetailHeaderView.prototype.modelEvents = { + 'change': 'render' + }; + QualityGateDetailHeaderView.prototype.events = { 'click #quality-gate-rename': 'renameQualityGate', 'click #quality-gate-delete': 'deleteQualityGate', @@ -23,19 +29,22 @@ }; QualityGateDetailHeaderView.prototype.renameQualityGate = function() { - return this.options.detailView.showRenaming(); + this.options.app.qualityGateEditView.model = this.model; + return this.options.app.qualityGateEditView.show(); }; QualityGateDetailHeaderView.prototype.deleteQualityGate = function() { var _this = this; if (confirm(window.SS.phrases.areYouSure)) { - this.options.detailView.showHeaderSpinner(); + this.showSpinner(); return jQuery.ajax({ type: 'POST', url: "" + baseUrl + "/api/qualitygates/destroy", data: { id: this.model.id } + }).always(function() { + return _this.hideSpinner(); }).done(function() { return _this.options.app.deleteQualityGate(_this.model.id); }); @@ -45,7 +54,7 @@ QualityGateDetailHeaderView.prototype.changeDefault = function(set) { var data, method, _this = this; - this.options.detailView.showHeaderSpinner(); + this.showSpinner(); data = set ? { id: this.model.id } : {}; @@ -55,7 +64,7 @@ url: "" + baseUrl + "/api/qualitygates/" + method, data: data }).always(function() { - return _this.options.detailView.hideHeaderSpinner(); + return _this.hideSpinner(); }).done(function() { _this.options.app.unsetDefaults(_this.model.id); return _this.model.set('default', !_this.model.get('default')); @@ -70,6 +79,16 @@ return this.changeDefault(false); }; + QualityGateDetailHeaderView.prototype.showSpinner = function() { + this.$el.hide(); + return jQuery(this.spinner).insertBefore(this.$el); + }; + + QualityGateDetailHeaderView.prototype.hideSpinner = function() { + this.$el.prev().remove(); + return this.$el.show(); + }; + return QualityGateDetailHeaderView; })(Marionette.ItemView); diff --git a/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-projects-view.coffee b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-projects-view.coffee index 1b8366cd55d..353074e6e3a 100644 --- a/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-projects-view.coffee +++ b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-projects-view.coffee @@ -12,22 +12,23 @@ define [ onRender: -> - @$el.css 'max-width', 600 - new SelectList - el: @$('#select-list-projects') - width: '100%' - format: (item) -> item.name - searchUrl: "#{baseUrl}/api/qualitygates/search?gateId=#{@options.gateId}" - selectUrl: "#{baseUrl}/api/qualitygates/select" - deselectUrl: "#{baseUrl}/api/qualitygates/deselect" - extra: - gateId: @options.gateId - selectParameter: 'projectId' - selectParameterValue: 'id' - labels: - selected: window.SS.phrases.projects.with - deselected: window.SS.phrases.projects.without - all: window.SS.phrases.projects.all - tooltips: - select: window.SS.phrases.projects.select_hint - deselect: window.SS.phrases.projects.deselect_hint + unless @model.get('default') + @$el.css 'max-width', 600 + new SelectList + el: @$('#select-list-projects') + width: '100%' + format: (item) -> item.name + searchUrl: "#{baseUrl}/api/qualitygates/search?gateId=#{@options.gateId}" + selectUrl: "#{baseUrl}/api/qualitygates/select" + deselectUrl: "#{baseUrl}/api/qualitygates/deselect" + extra: + gateId: @options.gateId + selectParameter: 'projectId' + selectParameterValue: 'id' + labels: + selected: window.SS.phrases.projects.with + deselected: window.SS.phrases.projects.without + all: window.SS.phrases.projects.all + tooltips: + select: window.SS.phrases.projects.select_hint + deselect: window.SS.phrases.projects.deselect_hint diff --git a/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-projects-view.js b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-projects-view.js index 008b0bbc633..ea37af52df2 100644 --- a/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-projects-view.js +++ b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-projects-view.js @@ -16,31 +16,33 @@ QualityGateDetailProjectsView.prototype.template = Handlebars.compile(jQuery('#quality-gate-detail-projects-template').html()); QualityGateDetailProjectsView.prototype.onRender = function() { - this.$el.css('max-width', 600); - return new SelectList({ - el: this.$('#select-list-projects'), - width: '100%', - format: function(item) { - return item.name; - }, - searchUrl: "" + baseUrl + "/api/qualitygates/search?gateId=" + this.options.gateId, - selectUrl: "" + baseUrl + "/api/qualitygates/select", - deselectUrl: "" + baseUrl + "/api/qualitygates/deselect", - extra: { - gateId: this.options.gateId - }, - selectParameter: 'projectId', - selectParameterValue: 'id', - labels: { - selected: window.SS.phrases.projects["with"], - deselected: window.SS.phrases.projects.without, - all: window.SS.phrases.projects.all - }, - tooltips: { - select: window.SS.phrases.projects.select_hint, - deselect: window.SS.phrases.projects.deselect_hint - } - }); + if (!this.model.get('default')) { + this.$el.css('max-width', 600); + return new SelectList({ + el: this.$('#select-list-projects'), + width: '100%', + format: function(item) { + return item.name; + }, + searchUrl: "" + baseUrl + "/api/qualitygates/search?gateId=" + this.options.gateId, + selectUrl: "" + baseUrl + "/api/qualitygates/select", + deselectUrl: "" + baseUrl + "/api/qualitygates/deselect", + extra: { + gateId: this.options.gateId + }, + selectParameter: 'projectId', + selectParameterValue: 'id', + labels: { + selected: window.SS.phrases.projects["with"], + deselected: window.SS.phrases.projects.without, + all: window.SS.phrases.projects.all + }, + tooltips: { + select: window.SS.phrases.projects.select_hint, + deselect: window.SS.phrases.projects.deselect_hint + } + }); + } }; return QualityGateDetailProjectsView; diff --git a/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-renaming-view.coffee b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-renaming-view.coffee deleted file mode 100644 index e5b77853540..00000000000 --- a/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-renaming-view.coffee +++ /dev/null @@ -1,43 +0,0 @@ -define [ - 'backbone.marionette', - 'handlebars' -], ( - Marionette, - Handlebars, -) -> - - class QualityGateDetailRenamingView extends Marionette.ItemView - template: Handlebars.compile jQuery('#quality-gate-detail-renaming-template').html() - - - ui: - input: '#quality-gate-renaming-input' - - - events: - 'click #quality-gate-rename': 'rename' - 'click #quality-gate-cancel-rename': 'cancel' - - - onDomRefresh: -> - @ui.input.focus() - - - rename: -> - @options.detailView.showHeaderSpinner() - newName = @ui.input.val() - jQuery.ajax - url: "#{baseUrl}/api/qualitygates/rename" - type: 'POST' - data: - id: @model.id - name: newName - .always => - @options.detailView.hideHeaderSpinner() - .done => - @model.set 'name', newName - @options.detailView.showHeader() - - - cancel: -> - @options.detailView.showHeader() diff --git a/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-renaming-view.js b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-renaming-view.js deleted file mode 100644 index 983f29a17a1..00000000000 --- a/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-renaming-view.js +++ /dev/null @@ -1,60 +0,0 @@ -// Generated by CoffeeScript 1.6.3 -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; - - define(['backbone.marionette', 'handlebars'], function(Marionette, Handlebars) { - var QualityGateDetailRenamingView, _ref; - return QualityGateDetailRenamingView = (function(_super) { - __extends(QualityGateDetailRenamingView, _super); - - function QualityGateDetailRenamingView() { - _ref = QualityGateDetailRenamingView.__super__.constructor.apply(this, arguments); - return _ref; - } - - QualityGateDetailRenamingView.prototype.template = Handlebars.compile(jQuery('#quality-gate-detail-renaming-template').html()); - - QualityGateDetailRenamingView.prototype.ui = { - input: '#quality-gate-renaming-input' - }; - - QualityGateDetailRenamingView.prototype.events = { - 'click #quality-gate-rename': 'rename', - 'click #quality-gate-cancel-rename': 'cancel' - }; - - QualityGateDetailRenamingView.prototype.onDomRefresh = function() { - return this.ui.input.focus(); - }; - - QualityGateDetailRenamingView.prototype.rename = function() { - var newName, - _this = this; - this.options.detailView.showHeaderSpinner(); - newName = this.ui.input.val(); - return jQuery.ajax({ - url: "" + baseUrl + "/api/qualitygates/rename", - type: 'POST', - data: { - id: this.model.id, - name: newName - } - }).always(function() { - return _this.options.detailView.hideHeaderSpinner(); - }).done(function() { - _this.model.set('name', newName); - return _this.options.detailView.showHeader(); - }); - }; - - QualityGateDetailRenamingView.prototype.cancel = function() { - return this.options.detailView.showHeader(); - }; - - return QualityGateDetailRenamingView; - - })(Marionette.ItemView); - }); - -}).call(this); diff --git a/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-view.coffee b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-view.coffee index 3f999d99576..475b25fb4e5 100644 --- a/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-view.coffee +++ b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-view.coffee @@ -3,7 +3,6 @@ define [ 'handlebars', 'quality-gate/collections/conditions', 'quality-gate/views/quality-gate-detail-header-view', - 'quality-gate/views/quality-gate-detail-renaming-view', 'quality-gate/views/quality-gate-detail-conditions-view', 'quality-gate/views/quality-gate-detail-projects-view' ], ( @@ -11,81 +10,41 @@ define [ Handlebars, Conditions, QualityGateDetailHeaderView, - QualityGateDetailRenamingView, QualityGateDetailConditionsView, QualityGateDetailProjectsView ) -> class QualityGateDetailView extends Marionette.Layout - className: 'quality-gate' template: Handlebars.compile jQuery('#quality-gate-detail-template').html() regions: - headerRegion: '.quality-gate-header' - tabRegion: '.quality-gate-details-tab' - - - ui: - tabs: '.quality-gate-tabs' - conditionsTab: '#quality-gate-tab-conditions' - projectsTab: '#quality-gate-tab-projects' + conditionsRegion: '#quality-gate-conditions' + projectsRegion: '#quality-gate-projects' modelEvents: 'change': 'render' - events: - 'click @ui.conditionsTab': 'showConditions' - 'click @ui.projectsTab': 'showProjects' - - onRender: -> - @showHeader() @showConditions() - - - showHeader: -> - view = new QualityGateDetailHeaderView - app: @options.app - detailView: @ - model: @model - @headerRegion.show view - - - showRenaming: -> - view = new QualityGateDetailRenamingView - app: @options.app - detailView: @ - model: @model - @headerRegion.show view + @showProjects() showConditions: -> - @ui.tabs.find('a').removeClass 'selected' - @ui.conditionsTab.addClass 'selected' conditions = new Conditions @model.get('conditions') view = new QualityGateDetailConditionsView app: @options.app collection: conditions gateId: @model.id qualityGate: @model - @tabRegion.show view + @conditionsRegion.show view showProjects: -> - @ui.tabs.find('a').removeClass 'selected' - @ui.projectsTab.addClass 'selected' view = new QualityGateDetailProjectsView app: @options.app + model: @model gateId: @model.id - @tabRegion.show view - - - showHeaderSpinner: -> - @$(@headerRegion.el).addClass 'navigator-fetching' - - - hideHeaderSpinner: -> - @$(@headerRegion.el).removeClass 'navigator-fetching' + @projectsRegion.show view diff --git a/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-view.js b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-view.js index e3e30f6e07e..6df657a234b 100644 --- a/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-view.js +++ b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-detail-view.js @@ -3,7 +3,7 @@ var __hasProp = {}.hasOwnProperty, __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; - define(['backbone.marionette', 'handlebars', 'quality-gate/collections/conditions', 'quality-gate/views/quality-gate-detail-header-view', 'quality-gate/views/quality-gate-detail-renaming-view', 'quality-gate/views/quality-gate-detail-conditions-view', 'quality-gate/views/quality-gate-detail-projects-view'], function(Marionette, Handlebars, Conditions, QualityGateDetailHeaderView, QualityGateDetailRenamingView, QualityGateDetailConditionsView, QualityGateDetailProjectsView) { + define(['backbone.marionette', 'handlebars', 'quality-gate/collections/conditions', 'quality-gate/views/quality-gate-detail-header-view', 'quality-gate/views/quality-gate-detail-conditions-view', 'quality-gate/views/quality-gate-detail-projects-view'], function(Marionette, Handlebars, Conditions, QualityGateDetailHeaderView, QualityGateDetailConditionsView, QualityGateDetailProjectsView) { var QualityGateDetailView, _ref; return QualityGateDetailView = (function(_super) { __extends(QualityGateDetailView, _super); @@ -13,59 +13,24 @@ return _ref; } - QualityGateDetailView.prototype.className = 'quality-gate'; - QualityGateDetailView.prototype.template = Handlebars.compile(jQuery('#quality-gate-detail-template').html()); QualityGateDetailView.prototype.regions = { - headerRegion: '.quality-gate-header', - tabRegion: '.quality-gate-details-tab' - }; - - QualityGateDetailView.prototype.ui = { - tabs: '.quality-gate-tabs', - conditionsTab: '#quality-gate-tab-conditions', - projectsTab: '#quality-gate-tab-projects' + conditionsRegion: '#quality-gate-conditions', + projectsRegion: '#quality-gate-projects' }; QualityGateDetailView.prototype.modelEvents = { 'change': 'render' }; - QualityGateDetailView.prototype.events = { - 'click @ui.conditionsTab': 'showConditions', - 'click @ui.projectsTab': 'showProjects' - }; - QualityGateDetailView.prototype.onRender = function() { - this.showHeader(); - return this.showConditions(); - }; - - QualityGateDetailView.prototype.showHeader = function() { - var view; - view = new QualityGateDetailHeaderView({ - app: this.options.app, - detailView: this, - model: this.model - }); - return this.headerRegion.show(view); - }; - - QualityGateDetailView.prototype.showRenaming = function() { - var view; - view = new QualityGateDetailRenamingView({ - app: this.options.app, - detailView: this, - model: this.model - }); - return this.headerRegion.show(view); + this.showConditions(); + return this.showProjects(); }; QualityGateDetailView.prototype.showConditions = function() { var conditions, view; - this.ui.tabs.find('a').removeClass('selected'); - this.ui.conditionsTab.addClass('selected'); conditions = new Conditions(this.model.get('conditions')); view = new QualityGateDetailConditionsView({ app: this.options.app, @@ -73,26 +38,17 @@ gateId: this.model.id, qualityGate: this.model }); - return this.tabRegion.show(view); + return this.conditionsRegion.show(view); }; QualityGateDetailView.prototype.showProjects = function() { var view; - this.ui.tabs.find('a').removeClass('selected'); - this.ui.projectsTab.addClass('selected'); view = new QualityGateDetailProjectsView({ app: this.options.app, + model: this.model, gateId: this.model.id }); - return this.tabRegion.show(view); - }; - - QualityGateDetailView.prototype.showHeaderSpinner = function() { - return this.$(this.headerRegion.el).addClass('navigator-fetching'); - }; - - QualityGateDetailView.prototype.hideHeaderSpinner = function() { - return this.$(this.headerRegion.el).removeClass('navigator-fetching'); + return this.projectsRegion.show(view); }; return QualityGateDetailView; diff --git a/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-edit-view.coffee b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-edit-view.coffee new file mode 100644 index 00000000000..34d94fef340 --- /dev/null +++ b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-edit-view.coffee @@ -0,0 +1,65 @@ +define [ + 'backbone.marionette', + 'handlebars' +], ( + Marionette, + Handlebars, +) -> + + class QualityGateEditView extends Marionette.ItemView + className: 'modal' + template: Handlebars.compile jQuery('#quality-gate-edit-template').html() + + + ui: + nameInput: '#quality-gate-edit-name' + + + events: + 'click #quality-gate-create': 'createQualityGate' + 'click #quality-gate-save': 'saveQualityGate' + 'click #quality-gate-cancel-create': 'hide' + + + onRender: -> + @$el.dialog + dialogClass: 'no-close', + width: '600px', + draggable: false, + autoOpen: false, + modal: true, + minHeight: 50, + resizable: false, + title: null + + + show: -> + @render() + @$el.dialog 'open' + @ui.nameInput.focus() + + + hide: -> + @$el.dialog 'close' + + + saveRequest: (method, data) -> + jQuery.ajax + type: 'POST' + url: "#{baseUrl}/api/qualitygates/#{method}" + data: data + .done => @hide() + + + createQualityGate: -> + data = name: @ui.nameInput.val() + @saveRequest('create', data).done (r) => + @model.set id: r.id, name: r.name + @options.app.qualityGates.add @model + @options.app.router.navigate "show/#{r.id}", trigger: true + + + saveQualityGate: -> + data = id: @model.id, name: @ui.nameInput.val() + @saveRequest('rename', data).done (r) => + @model.set name: r.name diff --git a/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-edit-view.js b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-edit-view.js new file mode 100644 index 00000000000..6b4c397c3ce --- /dev/null +++ b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-edit-view.js @@ -0,0 +1,101 @@ +// Generated by CoffeeScript 1.6.3 +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; + + define(['backbone.marionette', 'handlebars'], function(Marionette, Handlebars) { + var QualityGateEditView, _ref; + return QualityGateEditView = (function(_super) { + __extends(QualityGateEditView, _super); + + function QualityGateEditView() { + _ref = QualityGateEditView.__super__.constructor.apply(this, arguments); + return _ref; + } + + QualityGateEditView.prototype.className = 'modal'; + + QualityGateEditView.prototype.template = Handlebars.compile(jQuery('#quality-gate-edit-template').html()); + + QualityGateEditView.prototype.ui = { + nameInput: '#quality-gate-edit-name' + }; + + QualityGateEditView.prototype.events = { + 'click #quality-gate-create': 'createQualityGate', + 'click #quality-gate-save': 'saveQualityGate', + 'click #quality-gate-cancel-create': 'hide' + }; + + QualityGateEditView.prototype.onRender = function() { + return this.$el.dialog({ + dialogClass: 'no-close', + width: '600px', + draggable: false, + autoOpen: false, + modal: true, + minHeight: 50, + resizable: false, + title: null + }); + }; + + QualityGateEditView.prototype.show = function() { + this.render(); + this.$el.dialog('open'); + return this.ui.nameInput.focus(); + }; + + QualityGateEditView.prototype.hide = function() { + return this.$el.dialog('close'); + }; + + QualityGateEditView.prototype.saveRequest = function(method, data) { + var _this = this; + return jQuery.ajax({ + type: 'POST', + url: "" + baseUrl + "/api/qualitygates/" + method, + data: data + }).done(function() { + return _this.hide(); + }); + }; + + QualityGateEditView.prototype.createQualityGate = function() { + var data, + _this = this; + data = { + name: this.ui.nameInput.val() + }; + return this.saveRequest('create', data).done(function(r) { + _this.model.set({ + id: r.id, + name: r.name + }); + _this.options.app.qualityGates.add(_this.model); + return _this.options.app.router.navigate("show/" + r.id, { + trigger: true + }); + }); + }; + + QualityGateEditView.prototype.saveQualityGate = function() { + var data, + _this = this; + data = { + id: this.model.id, + name: this.ui.nameInput.val() + }; + return this.saveRequest('rename', data).done(function(r) { + return _this.model.set({ + name: r.name + }); + }); + }; + + return QualityGateEditView; + + })(Marionette.ItemView); + }); + +}).call(this); diff --git a/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-sidebar-list-item-view.coffee b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-sidebar-list-item-view.coffee index 4ddd64318df..458736751db 100644 --- a/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-sidebar-list-item-view.coffee +++ b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-sidebar-list-item-view.coffee @@ -16,7 +16,7 @@ define [ events: - 'click a': 'showQualityGate' + 'click': 'showQualityGate' onRender: -> diff --git a/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-sidebar-list-item-view.js b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-sidebar-list-item-view.js index 1ebd667ed8f..05b6798c7be 100644 --- a/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-sidebar-list-item-view.js +++ b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-sidebar-list-item-view.js @@ -22,7 +22,7 @@ }; QualityGateSidebarListItemView.prototype.events = { - 'click a': 'showQualityGate' + 'click': 'showQualityGate' }; QualityGateSidebarListItemView.prototype.onRender = function() { diff --git a/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-sidebar-list-view.coffee b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-sidebar-list-view.coffee index f8832dc8aae..e8e8cb96169 100644 --- a/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-sidebar-list-view.coffee +++ b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-sidebar-list-view.coffee @@ -10,34 +10,17 @@ define [ QualityGateSidebarListItemView ) -> - class QualityGateSidebarListView extends Marionette.CompositeView - tagName: 'ul' - className: 'sidebar blue-sidebar' - template: Handlebars.compile jQuery('#quality-gate-sidebar-list-template').html() + class QualityGateSidebarListView extends Marionette.CollectionView + tagName: 'ol' + className: 'navigator-results-list' itemView: QualityGateSidebarListItemView - ui: - spacer: '.spacer' - - - events: - 'click #quality-gate-add': 'addQualityGate' - - itemViewOptions: (model) -> app: @options.app highlighted: model.get('id') == +@highlighted - appendHtml: (compositeView, itemView) -> - itemView.$el.insertBefore @ui.spacer - - highlight: (id) -> @highlighted = id @render() - - - addQualityGate: -> - @options.app.router.navigate 'new', trigger: true diff --git a/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-sidebar-list-view.js b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-sidebar-list-view.js index 2ae45f78051..d2ac9a4393d 100644 --- a/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-sidebar-list-view.js +++ b/sonar-server/src/main/webapp/javascripts/quality-gate/views/quality-gate-sidebar-list-view.js @@ -13,22 +13,12 @@ return _ref; } - QualityGateSidebarListView.prototype.tagName = 'ul'; + QualityGateSidebarListView.prototype.tagName = 'ol'; - QualityGateSidebarListView.prototype.className = 'sidebar blue-sidebar'; - - QualityGateSidebarListView.prototype.template = Handlebars.compile(jQuery('#quality-gate-sidebar-list-template').html()); + QualityGateSidebarListView.prototype.className = 'navigator-results-list'; QualityGateSidebarListView.prototype.itemView = QualityGateSidebarListItemView; - QualityGateSidebarListView.prototype.ui = { - spacer: '.spacer' - }; - - QualityGateSidebarListView.prototype.events = { - 'click #quality-gate-add': 'addQualityGate' - }; - QualityGateSidebarListView.prototype.itemViewOptions = function(model) { return { app: this.options.app, @@ -36,24 +26,14 @@ }; }; - QualityGateSidebarListView.prototype.appendHtml = function(compositeView, itemView) { - return itemView.$el.insertBefore(this.ui.spacer); - }; - QualityGateSidebarListView.prototype.highlight = function(id) { this.highlighted = id; return this.render(); }; - QualityGateSidebarListView.prototype.addQualityGate = function() { - return this.options.app.router.navigate('new', { - trigger: true - }); - }; - return QualityGateSidebarListView; - })(Marionette.CompositeView); + })(Marionette.CollectionView); }); }).call(this); diff --git a/sonar-server/src/main/webapp/stylesheets/navigator.css b/sonar-server/src/main/webapp/stylesheets/navigator.css index c7cf3231b8e..a341ca6b615 100644 --- a/sonar-server/src/main/webapp/stylesheets/navigator.css +++ b/sonar-server/src/main/webapp/stylesheets/navigator.css @@ -346,7 +346,7 @@ font-size: 16px; text-decoration: none; } -.issues-page #footer { +.navigator-page #footer { position: fixed; z-index: 2; -moz-box-sizing: border-box; @@ -357,7 +357,7 @@ margin: 0; border-top: 1px solid #e1e1e1; } -.issues-page #ftlinks { +.navigator-page #ftlinks { margin-top: 0; } .navigator-filters { diff --git a/sonar-server/src/main/webapp/stylesheets/navigator/base.css b/sonar-server/src/main/webapp/stylesheets/navigator/base.css index a7e8f306461..4e062c3ebe6 100644 --- a/sonar-server/src/main/webapp/stylesheets/navigator/base.css +++ b/sonar-server/src/main/webapp/stylesheets/navigator/base.css @@ -346,7 +346,7 @@ font-size: 16px; text-decoration: none; } -.issues-page #footer { +.navigator-page #footer { position: fixed; z-index: 2; -moz-box-sizing: border-box; @@ -357,6 +357,6 @@ margin: 0; border-top: 1px solid #e1e1e1; } -.issues-page #ftlinks { +.navigator-page #ftlinks { margin-top: 0; } diff --git a/sonar-server/src/main/webapp/stylesheets/navigator/base.less b/sonar-server/src/main/webapp/stylesheets/navigator/base.less index e53cb36e612..2456f8a51a0 100644 --- a/sonar-server/src/main/webapp/stylesheets/navigator/base.less +++ b/sonar-server/src/main/webapp/stylesheets/navigator/base.less @@ -415,7 +415,7 @@ // Footer -.issues-page #footer { +.navigator-page #footer { .navigator-element; bottom: 0; left: @navigatorResultsWidth; @@ -424,6 +424,6 @@ border-top: 1px solid @navigatorBorderLightColor; } -.issues-page #ftlinks { +.navigator-page #ftlinks { margin-top: 0; } diff --git a/sonar-server/src/main/webapp/stylesheets/quality-gates.css b/sonar-server/src/main/webapp/stylesheets/quality-gates.css index 9dbfa1ec4e6..303502edf91 100644 --- a/sonar-server/src/main/webapp/stylesheets/quality-gates.css +++ b/sonar-server/src/main/webapp/stylesheets/quality-gates.css @@ -346,7 +346,7 @@ font-size: 16px; text-decoration: none; } -.issues-page #footer { +.navigator-page #footer { position: fixed; z-index: 2; -moz-box-sizing: border-box; @@ -357,85 +357,46 @@ margin: 0; border-top: 1px solid #e1e1e1; } -.issues-page #ftlinks { +.navigator-page #ftlinks { margin-top: 0; } -.quality-gate { - position: relative; - padding: 0 10px; - overflow: hidden; -} -.quality-gate-page-loader { - position: relative; - width: 24px; - height: 24px; -} -.quality-gate-page-loader:before { - content: " "; - position: absolute; - z-index: 3; - top: 0; - bottom: 0; - left: 0; - right: 0; - background: #ffffff url(../images/loading.gif) no-repeat 4px 4px; -} -.quality-gate-page-loader#tab-issue-rule { - position: relative; -} -.quality-gate-page-loader#tab-issue-rule:before { - z-index: 3; - background-color: #EFEFEF; +.quality-gates-navigator .navigator-header { + left: 320px; + border-bottom-color: #e1e1e1; } -.quality-gate-page-loader.code-issue-actions { - position: relative; +.quality-gates-navigator .navigator-header .spinner { + margin-top: 9px; } -.quality-gate-page-loader.code-issue-actions:before { - z-index: 3; - background-color: #E4ECF3; -} -.quality-gate-header { - position: relative; +.quality-gates-navigator .navigator-actions { + top: 30px; + height: 37px; padding: 0 10px; - border-left: 1px solid #cdcdcd; - border-right: 1px solid #cdcdcd; - border-bottom: 1px solid #cdcdcd; - background-color: #efefef; - font-size: 0; -} -.quality-gate-header.navigator-fetching:before { - background-color: #efefef; - background-position: 10px center; + border-right-color: #cdcdcd; } -.quality-gate-header-rename { - padding: 8px 0 7px; +.quality-gates-navigator .navigator-results { + top: 67px; } -.quality-gate-header-rename input { - vertical-align: middle; - width: 200px; - font-size: 13px; +.quality-gates-navigator .navigator-details { + top: 67px; + padding: 10px; } -.quality-gate-details { +.quality-gate-section + .quality-gate-section { margin-top: 10px; + padding-top: 20px; } -.quality-gate-tabs { - margin-bottom: 10px; +.quality-gate-section-empty + .quality-gate-section { + border-top: 1px solid #e1e1e1; } -.quality-gate-new-condition { - margin: 20px 0 10px; +.quality-gate-section-name { + margin-bottom: 10px; + font-weight: bold; } -.quality-gate-new-condition label { - vertical-align: middle; +.quality-gate-introduction { + margin-bottom: 20px; } -.quality-gate-conditions img, -.quality-gate-conditions input, -.quality-gate-conditions button, -.quality-gate-conditions .action { - vertical-align: middle !important; +.quality-gate-new-condition { + margin-bottom: 10px; } .quality-gate-condition-actions { position: relative; } -.quality-gate-condition-actions.navigator-fetching:before { - background-position: center left; -} diff --git a/sonar-server/src/main/webapp/stylesheets/quality-gates.less b/sonar-server/src/main/webapp/stylesheets/quality-gates.less index 15a2517806f..5bd981b3392 100644 --- a/sonar-server/src/main/webapp/stylesheets/quality-gates.less +++ b/sonar-server/src/main/webapp/stylesheets/quality-gates.less @@ -2,70 +2,58 @@ @import "mixins"; @import "navigator/base"; -.quality-gate { - position: relative; - padding: 0 10px; - overflow: hidden; -} +.quality-gates-navigator { -.quality-gate-page-loader { - position: relative; - .square(24px); - .navigator-fetching; -} + .navigator-header { + left: @navigatorResultsWidth; + border-bottom-color: @navigatorBorderLightColor; -.quality-gate-header { - position: relative; - padding: 0 10px; - border-left: 1px solid @darkGrey; - border-right: 1px solid @darkGrey; - border-bottom: 1px solid @darkGrey; - background-color: @grey; - font-size: 0; - - &.navigator-fetching:before { - background-color: @grey; - background-position: 10px center; + .spinner { margin-top: 9px; } } -} -.quality-gate-header-rename { - padding: 8px 0 7px; + .navigator-actions { + top: @navigatorTopOffset; + height: @navigatorHeaderHeight; + padding: 0 @navigatorPadding; + border-right-color: @navigatorBorderColor; + } - input { - vertical-align: middle; - width: 200px; - font-size: @baseFontSize; + .navigator-results { + top: @navigatorTopOffset + @navigatorHeaderHeight; } + + .navigator-details { + top: @navigatorTopOffset + @navigatorHeaderHeight; + padding: @navigatorPadding; + } + } -.quality-gate-details { - margin-top: 10px; + +.quality-gate-section + .quality-gate-section { + margin-top: @navigatorPadding; + padding-top: 2 * @navigatorPadding; } -.quality-gate-tabs { - margin-bottom: 10px; +.quality-gate-section-empty + .quality-gate-section { + border-top: 1px solid @navigatorBorderLightColor; } -.quality-gate-new-condition { - margin: 20px 0 10px; - - label { - vertical-align: middle; - } +.quality-gate-section-name { + margin-bottom: @navigatorPadding; + font-weight: bold; } -.quality-gate-conditions { - img, input, button, .action { - vertical-align: middle !important; - } +.quality-gate-introduction { + margin-bottom: 2 * @navigatorPadding; +} + + +.quality-gate-new-condition { + margin-bottom: @navigatorPadding; } .quality-gate-condition-actions { position: relative; - - &.navigator-fetching:before { - background-position: center left; - } } diff --git a/sonar-server/src/main/webapp/stylesheets/style.css b/sonar-server/src/main/webapp/stylesheets/style.css index 4b96a84cce7..be6f6eadeab 100644 --- a/sonar-server/src/main/webapp/stylesheets/style.css +++ b/sonar-server/src/main/webapp/stylesheets/style.css @@ -406,6 +406,10 @@ table.data th img, table.data td img { vertical-align: sub; } +table.data.zebra tr:nth-child(odd) { + background-color: #EFEFEF; +} + .data thead tr.total { background-color: #EFEFEF; font-weight: normal; -- 2.39.5