]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5946 SONAR-6027 better handling of ajax errors 68/head
authorStas Vilchik <vilchiks@gmail.com>
Tue, 3 Feb 2015 14:51:57 +0000 (15:51 +0100)
committerStas Vilchik <vilchiks@gmail.com>
Tue, 3 Feb 2015 14:53:18 +0000 (15:53 +0100)
34 files changed:
server/sonar-web/.jshintrc
server/sonar-web/src/main/coffee/analysis-reports/app.coffee
server/sonar-web/src/main/coffee/common/processes.coffee [deleted file]
server/sonar-web/src/main/coffee/issue/issue-view.coffee
server/sonar-web/src/main/coffee/issue/views/assign-form-view.coffee
server/sonar-web/src/main/coffee/issue/views/comment-form-view.coffee
server/sonar-web/src/main/coffee/issue/views/plan-form-view.coffee
server/sonar-web/src/main/coffee/issue/views/set-severity-form-view.coffee
server/sonar-web/src/main/coffee/issue/views/tags-form-view.coffee
server/sonar-web/src/main/coffee/issue/views/transitions-form-view.coffee
server/sonar-web/src/main/coffee/issues/app-context.coffee
server/sonar-web/src/main/coffee/issues/app-new.coffee
server/sonar-web/src/main/coffee/issues/controller.coffee
server/sonar-web/src/main/coffee/issues/workspace-list-item-view.coffee
server/sonar-web/src/main/coffee/quality-gate/app.coffee
server/sonar-web/src/main/js/coding-rules/app.js
server/sonar-web/src/main/js/coding-rules/bulk-change-modal-view.js
server/sonar-web/src/main/js/coding-rules/controller.js
server/sonar-web/src/main/js/coding-rules/rule-details-view.js
server/sonar-web/src/main/js/coding-rules/rule/custom-rule-view.js
server/sonar-web/src/main/js/coding-rules/rule/manual-rule-creation-view.js
server/sonar-web/src/main/js/coding-rules/rule/profile-activation-view.js
server/sonar-web/src/main/js/coding-rules/rule/rule-description-view.js
server/sonar-web/src/main/js/coding-rules/rule/rule-meta-view.js
server/sonar-web/src/main/js/coding-rules/rule/rule-profile-view.js
server/sonar-web/src/main/js/coding-rules/show-app.js
server/sonar-web/src/main/js/coding-rules/workspace-list-item-view.js
server/sonar-web/src/main/js/common/processes.js [new file with mode: 0644]
server/sonar-web/src/main/js/components/navigator/controller.js
server/sonar-web/src/main/js/nav/context-navbar-view.js
server/sonar-web/src/main/js/nav/search-view.js
server/sonar-web/src/main/js/source-viewer/measures-overlay.js
server/sonar-web/src/main/js/source-viewer/viewer.js
server/sonar-web/src/main/less/ui.less

index 2d6820a4d4c973bc7f9cece721bbcc36d74d3438..5b2eb1b387bbc1be6f564e50794400d018692e3f 100644 (file)
@@ -82,7 +82,9 @@
     "baseUrl": true,
     "key": true,
     "Backbone": true,
+    "Marionette": true,
     "Handlebars": true,
+    "Templates": true,
     "t": true,
     "tp": true,
     "moment": true,
index 308a8e8ba3aeb58ec77fe407cf0e181f3ed4b444..1fb00a6eb5eb0e39a0fa569656be76bd767844aa 100644 (file)
@@ -25,7 +25,6 @@ requirejs [
 
 
   App.fetchReports = ->
-    process = window.process.addBackgroundProcess()
     fetch = if @state.get 'active' then @reports.fetchActive() else @reports.fetchHistory()
     @layout.showSpinner 'actionsRegion'
     @layout.resultsRegion.reset()
@@ -44,18 +43,14 @@ requirejs [
         collection: @reports
       @layout.actionsRegion.show @actionsView
 
-      window.process.finishBackgroundProcess process
-
 
   App.fetchNextPage = ->
-    process = window.process.addBackgroundProcess()
     @reports.fetchHistory
       data:
         p: @state.get('page') + 1
       remove: false
     .done =>
       @state.set page: @reports.paging.page
-      window.process.finishBackgroundProcess process
 
 
   App.addInitializer ->
diff --git a/server/sonar-web/src/main/coffee/common/processes.coffee b/server/sonar-web/src/main/coffee/common/processes.coffee
deleted file mode 100644 (file)
index 7f15480..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-$ = jQuery
-
-process = {}
-process.queue = {}
-process.timeout = 300
-process.fadeTimeout = 100
-
-_.extend process,
-
-  addBackgroundProcess: ->
-    uid = _.uniqueId 'process'
-    @renderSpinner uid
-    @queue[uid] = setTimeout (=> @showSpinner uid), @timeout
-    uid
-
-
-  isBackgroundProcessAlive: (uid) ->
-    @queue[uid]?
-
-
-  finishBackgroundProcess: (uid) ->
-    if @isBackgroundProcessAlive uid
-      clearInterval @queue[uid]
-      delete @queue[uid]
-      @removeSpinner uid
-
-
-  failBackgroundProcess: (uid) ->
-    if @isBackgroundProcessAlive uid
-      clearInterval @queue[uid]
-      delete @queue[uid]
-      spinner = @getSpinner uid
-      spinner.addClass 'process-spinner-failed shown'
-      spinner.text t 'process.fail'
-      close = $('<button></button>').html('<i class="icon-close"></i>').addClass 'process-spinner-close'
-      close.appendTo spinner
-      close.on 'click', => @removeSpinner uid
-
-
-  renderSpinner: (uid) ->
-    id = "spinner-#{uid}"
-    spinner = $ '<div></div>'
-    spinner.addClass 'process-spinner'
-    spinner.prop 'id', id
-    text = t 'process.still_working'
-    text = 'Still Working...' if text == 'process.still_working'
-    spinner.text text
-    spinner.appendTo $('body')
-
-
-  showSpinner: (uid) ->
-    spinner = @getSpinner(uid)
-    setTimeout (-> spinner.addClass 'shown'), @fadeTimeout
-
-
-  removeSpinner: (uid) ->
-    @getSpinner(uid).remove()
-
-
-  getSpinner: (uid) ->
-    id = "spinner-#{uid}"
-    $('#' + id)
-
-
-_.extend window, process: process
-
-
index 961832018307c7e3a22ca28140536976d91b8b8a..622ff88cd98e54763ac3a1d2bf1013d655222d53 100644 (file)
@@ -78,7 +78,7 @@ define [
       @$el.attr 'data-key', @model.get('key')
 
 
-    resetIssue: (options, p) ->
+    resetIssue: (options) ->
       key = @model.get 'key'
       componentUuid = @model.get 'componentUuid'
       @model.clear silent: true
@@ -86,9 +86,6 @@ define [
       @model.fetch(options)
       .done =>
         @trigger 'reset'
-        window.process.finishBackgroundProcess p if p?
-      .fail ->
-        window.process.failBackgroundProcess p if p?
 
 
     showChangeLog: (e) ->
@@ -131,9 +128,7 @@ define [
     updateAfterAction: (fetch) ->
       @popup.close() if @popup
       if fetch
-        p = window.process.addBackgroundProcess()
-        $.when(@resetIssue()).done =>
-          window.process.finishBackgroundProcess p
+        @resetIssue()
 
 
     comment: (e) ->
@@ -163,7 +158,6 @@ define [
 
 
     deleteComment: (e) ->
-      p = window.process.addBackgroundProcess()
       commentKey = $(e.target).closest('[data-comment-key]').data 'comment-key'
       confirmMsg = $(e.target).data 'confirm-msg'
 
@@ -173,9 +167,6 @@ define [
           url: baseUrl + "/api/issues/delete_comment?key=" + commentKey
         .done =>
           @updateAfterAction true
-          window.process.finishBackgroundProcess p
-        .fail =>
-          window.process.failBackgroundProcess p
 
 
     transition: (e) ->
@@ -216,7 +207,6 @@ define [
 
 
     plan: (e) ->
-      p = window.process.addBackgroundProcess()
       t = $(e.currentTarget)
       actionPlans = new ActionPlans()
       actionPlans.fetch
@@ -231,9 +221,6 @@ define [
           model: @model
           collection: actionPlans
         @popup.render()
-        window.process.finishBackgroundProcess p
-      .fail =>
-        window.process.failBackgroundProcess p
 
 
     showMoreActions: (e) ->
@@ -248,13 +235,9 @@ define [
 
 
     action: (action) ->
-      p = window.process.addBackgroundProcess()
       $.post "#{baseUrl}/api/issues/do_action", issue: @model.id, actionKey: action
       .done =>
-        window.process.finishBackgroundProcess p
         @resetIssue()
-      .fail =>
-        window.process.failBackgroundProcess p
 
 
     showRule: ->
@@ -277,11 +260,9 @@ define [
 
 
     changeTags: ->
-      p = window.process.addBackgroundProcess()
       jQuery.ajax
         url: "#{baseUrl}/api/issues/tags?ps=0"
       .done (r) =>
-        window.process.finishBackgroundProcess p
         if @ui.tagInput.select2
           # Prevent synchronization issue with navigation
           @ui.tagInput.select2
@@ -305,8 +286,6 @@ define [
         )
 
         @ui.tagInput.select2 'focus'
-      .fail =>
-        window.process.failBackgroundProcess p
 
 
     cancelEdit: ->
@@ -328,15 +307,12 @@ define [
       tags = @ui.tagInput.val()
       splitTags = if tags then tags.split(',') else null
 
-      p = window.process.addBackgroundProcess()
       @model.set 'tags', splitTags
       $.post "#{baseUrl}/api/issues/set_tags", key: @model.get('key'), tags: tags
       .done =>
-        window.process.finishBackgroundProcess p
         @cancelEdit()
       .fail =>
         @model.set 'tags', _tags
-        window.process.failBackgroundProcess p
       .always =>
         @render()
 
index ed4b0379058b58e2a4cf653e660be4c8cd773a57..71279c6c97c4a73042bb84b0878da16c391e0d7d 100644 (file)
@@ -69,7 +69,6 @@ define [
       _assignee = @getAssignee()
       _assigneeName = @getAssigneeName()
       return if assignee == _assignee
-      p = window.process.addBackgroundProcess()
       if assignee == ''
         @model.set assignee: null, assigneeName: null
       else
@@ -80,11 +79,8 @@ define [
         data:
           issue: @model.id
           assignee: assignee
-      .done =>
-        window.process.finishBackgroundProcess p
       .fail =>
         @model.set assignee: _assignee, assigneeName: _assigneeName
-        window.process.failBackgroundProcess p
 
 
     onInputClick: (e) ->
@@ -110,13 +106,9 @@ define [
 
     search: (query) ->
       if query.length > 1
-        p = window.process.addBackgroundProcess()
         $.get "#{baseUrl}/api/users/search", s: query
         .done (data) =>
           @resetAssignees data.users
-          window.process.finishBackgroundProcess p
-        .fail =>
-          window.process.failBackgroundProcess p
       else
         @resetAssignees []
 
index f6f1c831109dd6f0eebf4980680cb18cd7629d12..d774baf4ac2a3d7ad3cc628055eead5a58c0bb83 100644 (file)
@@ -50,7 +50,6 @@ define [
 
 
     submit: ->
-      p = window.process.addBackgroundProcess()
       text = @ui.textarea.val()
       update = @model && @model.has('key')
       method = if update then 'edit_comment' else 'add_comment'
@@ -62,7 +61,4 @@ define [
         data.issue = @options.issue.id
       $.post url, data
       .done =>
-        window.process.finishBackgroundProcess p
         @options.detailView.updateAfterAction true
-      .fail =>
-        window.process.failBackgroundProcess p
index 837ec7bd7acb6b827d45cfa5a3ce6e3d2d0deed6..c048dd3c6cfbfbb8176c1b61d7b25bb89a9980b2 100644 (file)
@@ -35,7 +35,6 @@ define [
       _actionPlan = @getActionPlan()
       _actionPlanName = @getActionPlanName()
       return if actionPlan == _actionPlan
-      p = window.process.addBackgroundProcess()
       if actionPlan == ''
         @model.set actionPlan: null, actionPlanName: null
       else
@@ -46,11 +45,8 @@ define [
         data:
           issue: @model.id
           plan: actionPlan
-      .done =>
-        window.process.finishBackgroundProcess p
       .fail =>
         @model.set assignee: _actionPlan, assigneeName: _actionPlanName
-        window.process.failBackgroundProcess p
 
 
     getActionPlans: ->
index 836ef3babaa39db4024da90e1b23bd6e8b2f4841..f5e1ff19d946b0dbb3ebcfeb74d6b613286a365f 100644 (file)
@@ -29,7 +29,6 @@ define [
     submit: (severity) ->
       _severity = @getTransition()
       return if severity == _severity
-      p = window.process.addBackgroundProcess()
       @model.set severity: severity
       $.ajax
         type: 'POST'
@@ -37,11 +36,8 @@ define [
         data:
           issue: @model.id
           severity: severity
-      .done =>
-        window.process.finishBackgroundProcess p
       .fail =>
         @model.set severity: _severity
-        window.process.failBackgroundProcess p
 
 
     serializeData: ->
index 6b32590a27063186b3e7ea02839425ebcb3cf4ab..9ab57bd59b22185d76a264f8137731a75566e35f 100644 (file)
@@ -95,18 +95,14 @@ define [
     submit: (tags) ->
       _tags = @getTags()
       @model.set tags: tags
-      p = window.process.addBackgroundProcess()
       $.ajax
         type: 'POST'
         url: "#{baseUrl}/api/issues/set_tags"
         data:
           key: @model.id
           tags: tags.join()
-      .done =>
-        window.process.finishBackgroundProcess p
       .fail =>
         @model.set tags: _tags
-        window.process.failBackgroundProcess p
 
 
     onInputClick: (e) ->
index f389cbf3c6d7ed7d131a00803ad956f2ed4e1750..6111c4884add0ec96251a771bc5c9a8bad5993bf 100644 (file)
@@ -23,7 +23,6 @@ define [
 
 
     submit: (transition) ->
-      p = window.process.addBackgroundProcess()
       $.ajax
         type: 'POST',
         url: baseUrl + '/api/issues/do_transition',
@@ -31,6 +30,4 @@ define [
           issue: @model.get('key')
           transition: transition
       .done =>
-        @options.view.resetIssue {}, p
-      .fail =>
-        window.process.failBackgroundProcess p
+        @options.view.resetIssue {}
index c1f688369b7e4737b4af1a1e4f4f652ad17510d8..f12a2fa6d39b3166b9fec937a19a3ab64ed99ddd 100644 (file)
@@ -40,7 +40,6 @@ requirejs [
 
   $ = jQuery
   App = new Marionette.Application
-  issuesAppProcess = window.process.addBackgroundProcess()
 
 
   App.getContextQuery = ->
@@ -124,7 +123,6 @@ requirejs [
       key.setScope 'list'
       @router = new Router app: @
       Backbone.history.start()
-      window.process.finishBackgroundProcess issuesAppProcess
 
 
   l10nXHR = window.requestMessages()
index 8c39a53651b17e16a8878fba4cfcc277c47f30b7..cff9066f46a7511ec3e58516d391cf64f522d7c0 100644 (file)
@@ -40,7 +40,6 @@ requirejs [
 
   $ = jQuery
   App = new Marionette.Application
-  issuesAppProcess = window.process.addBackgroundProcess()
 
   App.addInitializer ->
     @state = new State()
@@ -103,7 +102,6 @@ requirejs [
       key.setScope 'list'
       @router = new Router app: @
       Backbone.history.start()
-      window.process.finishBackgroundProcess issuesAppProcess
 
 
   l10nXHR = window.requestMessages()
index 5a2f1f313e8e316edb81badebf3a2a3d32fdc1fb..0100182024a26b5f73bc630a03d1e4915607f340 100644 (file)
@@ -33,7 +33,6 @@ define [
       _.extend data, @options.app.state.get 'query'
       _.extend data, @options.app.state.get 'contextQuery' if @options.app.state.get 'isContext'
 
-      fetchIssuesProcess = window.process.addBackgroundProcess()
       $.get "#{baseUrl}/api/issues/search", data
       .done (r) =>
         issues = @options.app.list.parseIssues r
@@ -51,11 +50,8 @@ define [
           pageSize: r.ps
           total: r.total
           maxResultsReached: r.p * r.ps >= r.total
-        window.process.finishBackgroundProcess fetchIssuesProcess
         if firstPage && @isIssuePermalink()
           @showComponentViewer @options.app.list.first()
-      .fail ->
-        window.process.failBackgroundProcess fetchIssuesProcess
 
 
     isIssuePermalink: ->
index 914cb29317fcd60d875e7bca5fe0aef97e90e264..25435c21f3b5a3ab4d7215e1bad19a715852cc8b 100644 (file)
@@ -33,7 +33,7 @@ define [
       @options.app.state.set selectedIndex: @model.get('index')
 
 
-    resetIssue: (options, p) ->
+    resetIssue: (options) ->
       key = @model.get 'key'
       componentUuid = @model.get 'componentUuid'
       index = @model.get 'index'
@@ -42,9 +42,6 @@ define [
       @model.fetch(options)
       .done =>
         @trigger 'reset'
-        window.process.finishBackgroundProcess p if p?
-      .fail ->
-        window.process.failBackgroundProcess p if p?
 
 
     openComponentViewer: ->
index 076f0dc81fff50b696c59cb8627a1511b479e3e9..28cf9daf416f7a281b6773c9137bee102dd6a493 100644 (file)
@@ -18,21 +18,6 @@ requirejs [
   QualityGateLayout
 ) ->
 
-  # 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 quality-gates-page');
 
index 1bdefde9eba9b4ac7bdc3bdb8438a0d31d998e1d..522df2e899a9913d0d3153ddd9d15564a3de822a 100644 (file)
@@ -30,8 +30,7 @@ requirejs([
               FiltersView) {
 
       var $ = jQuery,
-          App = new Marionette.Application(),
-          p = window.process.addBackgroundProcess();
+          App = new Marionette.Application();
 
       App.addInitializer(function () {
         this.layout = new Layout();
@@ -83,7 +82,6 @@ requirejs([
           app: this
         });
         Backbone.history.start();
-        window.process.finishBackgroundProcess(p);
       });
 
       App.manualRepository = function () {
index c1b0a8c32144fd18f0b734a19b5f89c674d0b53d..b75170d3bb623b9db2b0e39787ac5cfa029bf1f1 100644 (file)
@@ -47,7 +47,6 @@ define([
 
     sendRequests: function (url, options, profiles) {
       var that = this,
-          p = window.process.addBackgroundProcess(),
           looper = $.Deferred().resolve();
       profiles.forEach(function (profile) {
         var opts = _.extend({}, options, { profile_key: profile });
@@ -64,9 +63,6 @@ define([
       looper.done(function () {
         that.options.app.controller.fetchList();
         that.$(that.ui.codingRulesSubmitBulkChange.selector).hide();
-        window.process.finishBackgroundProcess(p);
-      }).fail(function () {
-        window.process.failBackgroundProcess(p);
       });
     },
 
index 038140b4e062bda98dc35b7f9788e92cf8f20492..6e0ec4bccda5619e2c580ec11d8995327ac3b351 100644 (file)
@@ -40,8 +40,7 @@ define([
 
       var that = this,
           url = baseUrl + '/api/rules/search',
-          options = _.extend(this._searchParameters(), this.app.state.get('query')),
-          p = window.process.addBackgroundProcess();
+          options = _.extend(this._searchParameters(), this.app.state.get('query'));
       return $.get(url, options).done(function (r) {
         var rules = that.app.list.parseRules(r);
         if (firstPage) {
@@ -60,12 +59,9 @@ define([
           total: r.total,
           maxResultsReached: r.p * r.ps >= r.total
         });
-        window.process.finishBackgroundProcess(p);
         if (firstPage && that.isRulePermalink()) {
           that.showDetails(that.app.list.first());
         }
-      }).fail(function () {
-        window.process.failBackgroundProcess(p);
       });
     },
 
index c6c6d75cb64bec261a26a8215399c1fc556abcbf..91cf7f8044f164417762ecd359283ef9ea094974 100644 (file)
@@ -139,14 +139,10 @@ define([
             title: t('delete'),
             html: tp('coding_rules.delete.' + ruleType + '.confirm', this.model.get('name')),
             yesHandler: function () {
-              var p = window.process.addBackgroundProcess(),
-                  url = baseUrl + '/api/rules/delete',
+              var url = baseUrl + '/api/rules/delete',
                   options = { key: that.model.id };
               $.post(url, options).done(function () {
                 that.options.app.controller.fetchList();
-                window.process.finishBackgroundProcess(p);
-              }).fail(function () {
-                window.process.failBackgroundProcess(p);
               });
             }
           });
index 346823ad9af34fb3c2dfc248d48df2db591e69c4..229c3bb2b88b14e1916020e46a14c8e6f09114dd 100644 (file)
@@ -22,15 +22,11 @@ define([
         title: t('delete'),
         html: t('are_you_sure'),
         yesHandler: function () {
-          var p = window.process.addBackgroundProcess(),
-              url = baseUrl + '/api/rules/delete',
+          var url = baseUrl + '/api/rules/delete',
               options = { key: that.model.id };
           $.post(url, options).done(function () {
             that.model.collection.remove(that.model);
             that.close();
-            window.process.finishBackgroundProcess(p);
-          }).fail(function () {
-            window.process.failBackgroundProcess(p);
           });
         }
       });
index 0bd198dafac7ce1ed4741b67d5321e1e8a115553..68cce439208d922fb9d23e3a2f2186dc32e31de5 100644 (file)
@@ -85,7 +85,6 @@ define([
       this.$('.modal-error').hide();
       this.$('.modal-warning').hide();
       var that = this,
-          p = window.process.addBackgroundProcess(),
           url = baseUrl + '/api/rules/' + action;
       return $.post(url, options).done(function (r) {
         if (typeof r === 'string') {
@@ -100,8 +99,6 @@ define([
         } else {
           that.showErrors(jqXHR.responseJSON.errors, jqXHR.responseJSON.warnings);
         }
-      }).always(function () {
-        window.process.finishBackgroundProcess(p);
       });
     },
 
index 1edcf56028e7e1e4ecc984a8347a6914a469ef14..1de7444ac85c2701239c75437fa2a398a08f9306 100644 (file)
@@ -49,7 +49,6 @@ define([
     activate: function (e) {
       e.preventDefault();
       var that = this,
-          p = window.process.addBackgroundProcess(),
           profileKey = this.ui.qualityProfileSelect.val(),
           params = this.ui.qualityProfileParameters.map(function () {
             return {
@@ -84,10 +83,8 @@ define([
         }
       }).done(function () {
         that.trigger('profileActivated', severity, params);
-        window.process.finishBackgroundProcess(p);
       }).fail(function () {
         that.trigger('profileActivationFailed');
-        window.process.failBackgroundProcess(p);
       });
     },
 
index 979f43e1afc97fadea5d60e5fbe772d235308bc8..18d4d699855d4f0e94dfd5b43ffb6ee7ae0a2133 100644 (file)
@@ -38,8 +38,7 @@ define([
     },
 
     submitExtendDescription: function () {
-      var that = this,
-          p = window.process.addBackgroundProcess();
+      var that = this;
       this.ui.extendDescriptionForm.addClass('hidden');
       return jQuery.ajax({
         type: 'POST',
@@ -55,10 +54,8 @@ define([
           mdNote: r.rule.mdNote
         });
         that.render();
-        window.process.finishBackgroundProcess(p);
       }).fail(function () {
         that.render();
-        window.process.failBackgroundProcess(p);
       });
     },
 
index bafcdbf2705dc06cf701434ea3e47bdd9721bcf4..ba3b2cdfc4378bdd85c792a072351e97588150c5 100644 (file)
@@ -65,7 +65,6 @@ define([
 
     editDone: function () {
       var that = this,
-          p = window.process.addBackgroundProcess(),
           tags = this.ui.tagInput.val();
       return jQuery.ajax({
         type: 'POST',
@@ -77,10 +76,8 @@ define([
       }).done(function (r) {
         that.model.set('tags', r.rule.tags);
         that.cancelEdit();
-        window.process.finishBackgroundProcess(p);
       }).always(function () {
         that.cancelEdit();
-        window.process.failBackgroundProcess(p);
       });
     },
 
index 4ce97d6a9270757754f261da531dcb73a5912885..68077174dbc8b4471da14b55f240da2680f2a9f6 100644 (file)
@@ -50,7 +50,6 @@ define([
         title: t('coding_rules.revert_to_parent_definition'),
         html: tp('coding_rules.revert_to_parent_definition.confirm', this.getParent().name),
         yesHandler: function () {
-          var p = window.process.addBackgroundProcess();
           return jQuery.ajax({
             type: 'POST',
             url: baseUrl + '/api/qualityprofiles/activate_rule',
@@ -60,7 +59,6 @@ define([
               reset: true
             }
           }).done(function () {
-            window.process.finishBackgroundProcess(p);
             that.options.app.controller.showDetails(that.options.rule);
           });
         }
@@ -74,7 +72,6 @@ define([
         title: t('coding_rules.deactivate'),
         html: tp('coding_rules.deactivate.confirm'),
         yesHandler: function () {
-          var p = window.process.addBackgroundProcess();
           return jQuery.ajax({
             type: 'POST',
             url: baseUrl + '/api/qualityprofiles/deactivate_rule',
@@ -83,7 +80,6 @@ define([
               rule_key: ruleKey
             }
           }).done(function () {
-            window.process.finishBackgroundProcess(p);
             that.options.app.controller.showDetails(that.options.rule);
           });
         }
index 1505c23ec51e38ce5b69f38c10a860572410b461..d6df53514c5a99a4fa013cf0417dcf52fc8b2007 100644 (file)
@@ -11,8 +11,7 @@ requirejs([
               RuleDetailsView) {
 
       var $ = jQuery,
-          App = new Marionette.Application(),
-          p = window.process.addBackgroundProcess();
+          App = new Marionette.Application();
 
       App.addInitializer(function () {
         var url = baseUrl + '/api/rules/show',
@@ -28,9 +27,6 @@ requirejs([
             actives: data.actives
           });
           this.ruleDetailsView.render().$el.appendTo($('.page'));
-          window.process.finishBackgroundProcess(p);
-        }).fail(function () {
-          window.process.failBackgroundProcess(p);
         });
       });
 
index 19810a6e5a5bf305af3addd81da019155b95904d..56937b8add95ffa033ec9f836d75a4caaf7eb25d 100644 (file)
@@ -58,7 +58,6 @@ define([
         title: t('coding_rules.deactivate'),
         html: tp('coding_rules.deactivate.confirm'),
         yesHandler: function () {
-          var p = window.process.addBackgroundProcess();
           return jQuery.ajax({
             type: 'POST',
             url: baseUrl + '/api/qualityprofiles/deactivate_rule',
@@ -67,7 +66,6 @@ define([
               rule_key: ruleKey
             }
           }).done(function () {
-            window.process.finishBackgroundProcess(p);
             that.model.unset('activation');
           });
         }
diff --git a/server/sonar-web/src/main/js/common/processes.js b/server/sonar-web/src/main/js/common/processes.js
new file mode 100644 (file)
index 0000000..d7188df
--- /dev/null
@@ -0,0 +1,163 @@
+(function ($) {
+
+  var options = {
+    queue: {},
+    timeout: 300,
+    fadeTimeout: 100
+  };
+
+  var Process = Backbone.Model.extend({
+        defaults: {
+          state: 'ok'
+        },
+
+        timeout: function () {
+          this.set({
+            state: 'timeout',
+            message: 'Still Working...'
+          });
+        },
+
+        finish: function (options) {
+          options = _.defaults(options || {}, { force: false });
+          if (this.get('state') !== 'failed' || !!options.force) {
+            this.trigger('destroy', this, this.collection, options);
+          }
+        },
+
+        fail: function (message) {
+          clearInterval(this.get('timer'));
+          this.set({
+            state: 'failed',
+            message: message || t('process.fail')
+          });
+          this.set('state', 'failed');
+        }
+      }),
+
+      Processes = Backbone.Collection.extend({
+        model: Process
+      }),
+
+      ProcessView = Marionette.ItemView.extend({
+        tagName: 'li',
+        className: 'process-spinner',
+
+        modelEvents: {
+          'change': 'render'
+        },
+
+        render: function () {
+          var that = this;
+          switch (this.model.get('state')) {
+            case 'timeout':
+              this.$el.html(this.model.get('message')).addClass('shown');
+              break;
+            case 'failed':
+              this.$el.html(this.model.get('message')).addClass('process-spinner-failed shown');
+              var close = $('<button></button>').html('<i class="icon-close"></i>').addClass('process-spinner-close');
+              close.appendTo(this.$el);
+              close.on('click', function () {
+                var a = { force: true };
+                that.model.finish(a);
+              });
+              break;
+            case 'finished':
+              this.$el.addClass('hidden');
+              break;
+          }
+          return this;
+        }
+      }),
+
+      ProcessesView = Marionette.CollectionView.extend({
+        tagName: 'ul',
+        className: 'processes-container',
+        itemView: ProcessView
+      });
+
+
+  var processes = new Processes(),
+      processesView = new ProcessesView({
+        collection: processes
+      });
+
+  /**
+   * Add background process
+   * @returns {number}
+   */
+  function addBackgroundProcess () {
+    var uid = _.uniqueId('process'),
+        process = new Process({
+          id: uid,
+          timer: setTimeout(function () {
+            process.timeout();
+          }, options.timeout)
+        });
+    processes.add(process);
+    return uid;
+  }
+
+  /**
+   * Finish background process
+   * @param {number} uid
+   */
+  function finishBackgroundProcess (uid) {
+    var process = processes.get(uid);
+    if (process != null) {
+      process.finish();
+    }
+  }
+
+  /**
+   * Fail background process
+   * @param {number} uid
+   * @param {string} message
+   */
+  function failBackgroundProcess (uid, message) {
+    var process = processes.get(uid);
+    if (process != null) {
+      process.fail(message);
+    }
+  }
+
+  /**
+   * Handle ajax error
+   * @param jqXHR
+   */
+  function handleAjaxError (jqXHR) {
+    if (jqXHR.processId != null) {
+      var message = null;
+      if (jqXHR != null && jqXHR.responseJSON != null && jqXHR.responseJSON.errors != null) {
+        message = _.pluck(jqXHR.responseJSON.errors, 'msg').join('. ');
+      }
+      failBackgroundProcess(jqXHR.processId, message);
+    }
+  }
+
+
+  $.ajaxSetup({
+    beforeSend: function (jqXHR) {
+      jqXHR.processId = addBackgroundProcess();
+    },
+    complete: function (jqXHR) {
+      if (jqXHR.processId != null) {
+        finishBackgroundProcess(jqXHR.processId);
+      }
+    },
+    statusCode: {
+      400: handleAjaxError,
+      401: handleAjaxError,
+      403: handleAjaxError,
+      500: handleAjaxError
+    }
+  });
+
+
+  $(function () {
+
+    processesView.render().$el.appendTo(document.body);
+
+  });
+
+})(window.jQuery);
index ccbee03e657acd22ec5d3751d04c530f27b15f1b..b064a6d9570e6852c52e3ce34719e6dda76748cd 100644 (file)
@@ -50,14 +50,9 @@ define(function () {
       if (facet.has('values') || this.options.app.state.get('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);
             });
       }
     },
index 8a7935c89190154dcefe9fa5ce85038323b54579..f045a2f770a00e39cc3a5c2438bc13d756f1c75c 100644 (file)
@@ -23,15 +23,11 @@ define([
 
     onFavoriteClick: function () {
       var that = this,
-          p = window.process.addBackgroundProcess(),
           url = baseUrl + '/favourites/toggle/' + this.model.get('contextId'),
           isContextFavorite = this.model.get('isContextFavorite');
       this.model.set({ isContextFavorite: !isContextFavorite });
-      return $.post(url).done(function () {
-        window.process.finishBackgroundProcess(p);
-      }).fail(function () {
+      return $.post(url).fail(function () {
         that.model.set({ isContextFavorite: isContextFavorite });
-        window.process.failBackgroundProcess(p);
       });
     },
 
index e3258e61477050b8029f2ef04cc703b452e480bc..243fef610f4eabb4791f3465a959697b0530fa4e 100644 (file)
@@ -130,8 +130,7 @@ define([
       }
       var that = this,
           url = baseUrl + '/api/components/suggestions',
-          options = { s: q },
-          p = window.process.addBackgroundProcess();
+          options = { s: q };
       return $.get(url, options).done(function (r) {
         var collection = [];
         r.results.forEach(function (domain) {
@@ -144,9 +143,6 @@ define([
           });
         });
         that.results.reset(collection);
-        window.process.finishBackgroundProcess(p);
-      }).fail(function() {
-        window.process.failBackgroundProcess(p);
       });
     }
   });
index 3a1cc491d9a027247572d075da2d3fbb0c7850f2..6418f6e0e96364d87481f62bbe03811cfbdad4ba 100644 (file)
@@ -12,7 +12,6 @@ define([
 
     initialize: function () {
       var that = this,
-          p = window.process.addBackgroundProcess(),
           requests = [this.requestMeasures(), this.requestIssues()];
       if (this.model.get('isUnitTest')) {
         requests.push(this.requestTests());
@@ -20,9 +19,6 @@ define([
       this.testsScroll = 0;
       $.when.apply($, requests).done(function () {
         that.render();
-        window.process.finishBackgroundProcess(p);
-      }).fail(function () {
-        window.process.failBackgroundProcess(p);
       });
     },
 
@@ -203,7 +199,6 @@ define([
 
     showTest: function (e) {
       var that = this,
-          p = window.process.addBackgroundProcess(),
           name = $(e.currentTarget).data('name'),
           url = baseUrl + '/api/tests/covered_files',
           options = {
@@ -215,7 +210,6 @@ define([
         that.coveredFiles = data.files;
         that.selectedTest = _.findWhere(that.model.get('tests'), { name: name });
         that.render();
-        window.process.finishBackgroundProcess(p);
       });
     },
 
index a4a6575c6327af7f0bd7234b663d592508146b77..a8ee471090dd4458e15ba1306b155308f6cb047a 100644 (file)
@@ -97,11 +97,9 @@ define([
 
         open: function (id) {
           var that = this,
-              r = window.process.addBackgroundProcess(),
               finalize = function () {
                 that.requestIssues().done(function () {
                   that.render();
-                  window.process.finishBackgroundProcess(r);
                   that.trigger('loaded');
                 });
               };
@@ -343,8 +341,7 @@ define([
         showCoveragePopup: function (e) {
           e.stopPropagation();
           $('body').click();
-          var r = window.process.addBackgroundProcess(),
-              line = $(e.currentTarget).data('line-number'),
+          var line = $(e.currentTarget).data('line-number'),
               row = _.findWhere(this.model.get('source'), {line: line}),
               url = baseUrl + '/api/tests/test_cases',
               options = {
@@ -358,9 +355,6 @@ define([
               triggerEl: $(e.currentTarget)
             });
             popup.render();
-            window.process.finishBackgroundProcess(r);
-          }).fail(function () {
-            window.process.failBackgroundProcess(r);
           });
         },
 
index f51a4b7c319ce1a38e4a29f192d421635f9bb2d6..eec3b654e7052ac509cc9726f6890ab12dfeaf39 100644 (file)
@@ -352,18 +352,21 @@ input[type=button] {
 }
 
 
+.processes-container {
+  position: fixed;
+  z-index: 9999;
+  top: 0;
+  left: 50%;
+  width: 350px;
+  margin-left: -175px;
+}
 
 .process-spinner {
-  position: fixed;
-  z-index: 2000;
-  top: 0; left: 50%;
-  min-width: 300px;
-  max-width: 900px;
-  margin-left: -150px;
   padding: 0 10px;
   line-height: @formControlHeight;
-  background-color: #f0e8ac;
   border-radius: 0 0 3px 3px;
+  .box-sizing(border-box);
+  background-color: #f0e8ac;
   text-align: center;
   opacity: 0;
   .trans;
@@ -371,14 +374,21 @@ input[type=button] {
   &.shown { opacity: 1; }
 }
 
+.process-spinner + .process-spinner {
+  margin-top: 5px;
+  border-radius: 3px;
+}
+
 .process-spinner-failed {
+  padding-right: 30px;
   background-color: @red;
   color: @white;
 }
 
 .process-spinner-close {
-  float: right;
-  margin-right: 5px;
+  position: absolute;
+  top: 0;
+  right: 0;
   padding: 3px;
   background: none !important;
   border: none !important;