From 5aaaf3103c4c921686663109350dcca052b2b582 Mon Sep 17 00:00:00 2001 From: Stas Vilchik Date: Tue, 25 Feb 2014 10:37:35 +0100 Subject: [PATCH] Some feedback on the issues page --- .../app/views/issue/_plan_form.html.erb | 3 +- .../templates/_issue_detail_inner.hbs.erb | 2 +- .../issues/templates/_issues_actions.hbs.erb | 2 +- .../app/views/resource/_index.html.erb | 27 +- .../main/webapp/javascripts/issues-extra.js | 11 +- .../webapp/javascripts/navigator/issues.js | 1219 +++++++++++++++++ .../src/main/webapp/stylesheets/navigator.css | 3 +- .../webapp/stylesheets/navigator/base.css | 3 +- .../webapp/stylesheets/navigator/base.less | 3 +- .../main/webapp/stylesheets/select2-sonar.css | 2 +- .../webapp/stylesheets/select2-sonar.less | 2 +- .../src/main/webapp/stylesheets/select2.css | 2 +- .../src/main/webapp/stylesheets/style.css | 9 +- 13 files changed, 1260 insertions(+), 28 deletions(-) create mode 100644 sonar-server/src/main/webapp/javascripts/navigator/issues.js diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/issue/_plan_form.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/issue/_plan_form.html.erb index 5c167cd23b2..73ce039b4cf 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/issue/_plan_form.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/issue/_plan_form.html.erb @@ -29,8 +29,7 @@ <%= dropdown_tag('plan', plan_options, {:show_search_box => false}, {:id => plans_select_box_id}) -%> -   - <%= link_to_function message('cancel'), 'closeIssueForm(this)' -%>  + <%= link_to_function message('cancel'), 'closeIssueForm(this)' -%> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/issues/templates/_issue_detail_inner.hbs.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/templates/_issue_detail_inner.hbs.erb index 661c0e07d9f..50575b82d4d 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/issues/templates/_issue_detail_inner.hbs.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/templates/_issue_detail_inner.hbs.erb @@ -154,7 +154,7 @@ {{#if updatable}}  <%= image_tag 'sep12.png' -%>  <%= message('edit') -%> - <%= message('delete') -%> {{/if}} diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/issues/templates/_issues_actions.hbs.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/templates/_issues_actions.hbs.erb index 2d6a7a9031f..15df36366b2 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/issues/templates/_issues_actions.hbs.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/templates/_issues_actions.hbs.erb @@ -20,7 +20,7 @@ <%= message('issues.found') -%>: {{paging.total}} {{#if appState.canBulkChange}} {{/if}} diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/resource/_index.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/resource/_index.html.erb index 624ad76e79e..fbbdcbe3c3d 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/resource/_index.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/resource/_index.html.erb @@ -16,19 +16,20 @@ <% if @lines && @lines.size>0 %> <% if has_role?('codeviewer', @resource) %> - <%= render :partial => "shared/source_display", :locals => { :display_manual_violation_form => @display_manual_violation_form, - :scm_available => @scm_available, - :display_coverage => @display_coverage, - :lines => @lines, - :expanded => @expanded, - :display_violations => @display_violations, - :display_issues => @display_issues, - :has_global_issues => @global_issues && @global_issues.size>0, - :resource => @resource, - :snapshot => @snapshot, - :review_screens_by_vid => @review_screens_by_vid, - :filtered => @filtered}%> - +
+ <%= render :partial => "shared/source_display", :locals => { :display_manual_violation_form => @display_manual_violation_form, + :scm_available => @scm_available, + :display_coverage => @display_coverage, + :lines => @lines, + :expanded => @expanded, + :display_violations => @display_violations, + :display_issues => @display_issues, + :has_global_issues => @global_issues && @global_issues.size>0, + :resource => @resource, + :snapshot => @snapshot, + :review_screens_by_vid => @review_screens_by_vid, + :filtered => @filtered}%> +
<% else %>
<%= message('code_viewer.no_source_code_displayed_due_to_security') -%>
<% end %> diff --git a/sonar-server/src/main/webapp/javascripts/issues-extra.js b/sonar-server/src/main/webapp/javascripts/issues-extra.js index 3e033eb1ec7..be28761c6b7 100644 --- a/sonar-server/src/main/webapp/javascripts/issues-extra.js +++ b/sonar-server/src/main/webapp/javascripts/issues-extra.js @@ -289,7 +289,8 @@ define( events: { 'click .navigator-actions-order': 'toggleOrderChoices', - 'click .navigator-actions-order-choices': 'sort' + 'click .navigator-actions-order-choices': 'sort', + 'click .navigator-actions-bulk': 'bulkChange' }, @@ -304,8 +305,6 @@ define( this.render(); return; } - - this.$('.open-modal').modal(); }, @@ -340,6 +339,12 @@ define( }, + bulkChange: function(e) { + e.preventDefault(); + openModalWindow(jQuery(e.currentTarget).prop('href'), {}); + }, + + serializeData: function () { var data = Marionette.ItemView.prototype.serializeData.apply(this, arguments); return _.extend(data || {}, { diff --git a/sonar-server/src/main/webapp/javascripts/navigator/issues.js b/sonar-server/src/main/webapp/javascripts/navigator/issues.js new file mode 100644 index 00000000000..847269b67e3 --- /dev/null +++ b/sonar-server/src/main/webapp/javascripts/navigator/issues.js @@ -0,0 +1,1219 @@ +/* global _:false, Backbone:false, baseUrl:false */ + +window.SS = typeof window.SS === 'object' ? window.SS : {}; + +jQuery(function() { + + var AppState = Backbone.Model.extend({ + + defaults: { + canManageFilter: false, + canBulkChange: false + }, + + + url: function() { + return baseUrl + '/api/issue_filters/page'; + } + + }); + + + + var Issue = Backbone.Model.extend({ + + url: function() { + return baseUrl + '/api/issues/show?key=' + this.get('key'); + }, + + + parse: function(r) { + return r.issue ? r.issue : r; + } + + }); + + + + var Issues = Backbone.Collection.extend({ + model: Issue, + + + url: function() { + return baseUrl + '/api/issues/search'; + }, + + + parse: function(r) { + + function find(source, key, keyField) { + var searchDict = {}; + searchDict[keyField || 'key'] = key; + return _.findWhere(source, searchDict) || key; + } + + this.paging = r.paging; + this.maxResultsReached = r.maxResultsReached; + + return r.issues.map(function(issue) { + var component = find(r.components, issue.component), + project = find(r.projects, issue.project), + rule = find(r.rules, issue.rule); + + if (component) { + _.extend(issue, { + componentLongName: component.longName, + componentQualifier: component.qualifier + }); + } + + if (project) { + _.extend(issue, { + projectLongName: project.longName + }); + } + + if (rule) { + _.extend(issue, { + ruleName: rule.name + }); + } + + return issue; + }); + + } + }); + + + + var FavoriteFilter = Backbone.Model.extend({ + + url: function() { + return baseUrl + '/api/issue_filters/show/' + this.get('id'); + }, + + + parse: function(r) { + return r.filter ? r.filter : r; + } + }); + + + + var FavoriteFilters = Backbone.Collection.extend({ + model: FavoriteFilter, + + + url: function() { + return baseUrl + '/api/issue_filters/favorites'; + }, + + + parse: function(r) { + return r.favoriteFilters; + } + }); + + + var Rule = Backbone.Model.extend({ + + url: function() { + return baseUrl + '/api/rules/show/?key=' + this.get('key'); + }, + + + parse: function(r) { + return r.rule ? r.rule : r; + } + }); + + + + var ActionPlans = Backbone.Collection.extend({ + + url: function() { + return baseUrl + '/api/action_plans/search'; + }, + + + parse: function(r) { + return r.actionPlans; + } + + }); + + + + var IssueView = Backbone.Marionette.ItemView.extend({ + template: Handlebars.compile(jQuery('#issue-template').html() || ''), + tagName: 'li', + + + ui: { + component: '.component' + }, + + + events: { + 'click': 'showDetails' + }, + + + modelEvents: { + 'change': 'render' + }, + + + showDetails: function() { + this.$el.parent().children().removeClass('active'); + this.$el.addClass('active'); + + var that = this, + app = this.options.app, + detailView = new window.SS.IssueDetailView({ + model: this.model + }), + showCallback = function() { + jQuery('.navigator-details').removeClass('navigator-fetching'); + app.detailsRegion.show(detailView); + }; + + jQuery('.navigator-details').empty().addClass('navigator-fetching'); + jQuery.when(detailView.model.fetch()).done(function() { + if (that.model.get('status') !== 'CLOSED') { + that.fetchSource(detailView, showCallback); + } else { + showCallback(); + } + + }); + }, + + + fetchSource: function (view, callback) { + var line = this.model.get('line') || 0, + from = line >= 10 ? line - 10 : 0, + to = line + 30; + + return jQuery + .ajax({ + type: 'GET', + url: baseUrl + '/api/sources/show', + data: { + key: this.model.get('component'), + from: from, + to: to, + format: 'json' + } + }) + .done(function (r) { + if (_.isObject(r) && r.source) { + view.source = r.source; + } + if (_.isObject(r) && r.scm) { + view.scm = r.scm; + } + }) + .always(callback); + }, + + + serializeData: function() { + var projectFilter = this.options.app.filters.findWhere({ property: 'componentRoots' }), + singleProject = _.isArray(projectFilter.get('value')) && projectFilter.get('value').length === 1; + + return _.extend({ + singleProject: singleProject + }, this.model.toJSON()); + } + }); + + + + var NoIssuesView = Backbone.Marionette.ItemView.extend({ + template: Handlebars.compile(jQuery('#no-issues-template').html() || '') + }); + + + + var IssuesView = Backbone.Marionette.CollectionView.extend({ + tagName: 'ol', + className: 'navigator-results-list', + itemView: IssueView, + emptyView: NoIssuesView, + + + itemViewOptions: function() { + return { + issuesView: this, + app: this.options.app + }; + }, + + + onRender: function() { + var $scrollEl = jQuery('.navigator-results'), + scrollEl = $scrollEl.get(0), + onScroll = function() { + if (scrollEl.offsetHeight + scrollEl.scrollTop >= scrollEl.scrollHeight) { + window.SS.IssuesNavigatorApp.fetchNextPage(); + } + }, + throttledScroll = _.throttle(onScroll, 300); + $scrollEl.off('scroll').on('scroll', throttledScroll); + }, + + + onAfterItemAdded: function() { + var showLimitNotes = this.collection.maxResultsReached != null && this.collection.maxResultsReached; + jQuery('.navigator').toggleClass('navigator-with-notes', showLimitNotes); + jQuery('.navigator-notes').toggle(showLimitNotes); + }, + + + close: function() { + var scrollEl = jQuery('.navigator-results'); + scrollEl.off('scroll'); + Backbone.Marionette.CollectionView.prototype.close.call(this); + } + + }); + + + + var IssuesActionsView = Backbone.Marionette.ItemView.extend({ + template: Handlebars.compile(jQuery('#issues-actions-template').html() || ''), + + + collectionEvents: { + 'sync': 'render' + }, + + + events: { + 'click .navigator-actions-order': 'toggleOrderChoices', + 'click .navigator-actions-order-choices': 'sort', + 'click .navigator-actions-bulk': 'bulkChange' + }, + + + ui: { + orderChoices: '.navigator-actions-order-choices' + }, + + + onRender: function() { + if (!this.collection.sorting.sortText) { + this.collection.sorting.sortText = this.$('[data-sort=' + this.collection.sorting.sort + ']:first').text(); + this.render(); + return; + } + }, + + + toggleOrderChoices: function(e) { + e.stopPropagation(); + this.ui.orderChoices.toggleClass('open'); + if (this.ui.orderChoices.is('.open')) { + var that = this; + jQuery('body').on('click.issues_actions', function() { + that.ui.orderChoices.removeClass('open'); + }); + } + }, + + + sort: function(e) { + e.stopPropagation(); + this.ui.orderChoices.removeClass('open'); + jQuery('body').off('click.issues_actions'); + var el = jQuery(e.target), + sort = el.data('sort'), + asc = el.data('asc'); + + if (sort != null && asc != null) { + this.collection.sorting = { + sort: sort, + sortText: el.text(), + asc: asc + }; + this.options.app.fetchFirstPage(); + } + }, + + + bulkChange: function(e) { + e.preventDefault(); + openModalWindow(jQuery(e.currentTarget).prop('href'), {}); + }, + + + serializeData: function() { + var data = Backbone.Marionette.ItemView.prototype.serializeData.apply(this, arguments); + return _.extend(data || {}, { + paging: this.collection.paging, + sorting: this.collection.sorting, + maxResultsReached: this.collection.maxResultsReached, + appState: window.SS.appState.toJSON(), + query: (Backbone.history.fragment || '').replace(/\|/g, '&') + }); + } + }); + + + + var IssuesFilterBarView = window.SS.FilterBarView.extend({ + + collectionEvents: { + 'change:enabled': 'changeEnabled' + }, + + + events: { + 'click .navigator-filter-submit': 'search' + }, + + + getQuery: function() { + var query = {}; + this.collection.each(function(filter) { + _.extend(query, filter.view.formatValue()); + }); + return query; + }, + + + onAfterItemAdded: function(itemView) { + if (itemView.model.get('type') === window.SS.FavoriteFilterView || + itemView.model.get('type') === window.SS.IssuesFavoriteFilterView) { + jQuery('.navigator-header').addClass('navigator-header-favorite'); + } + }, + + + search: function() { + this.options.app.state.set({ + query: this.options.app.getQuery(), + search: true + }); + this.options.app.fetchFirstPage(); + }, + + + fetchNextPage: function() { + this.options.app.fetchNextPage(); + } + + }); + + + + var IssuesHeaderView = Backbone.Marionette.ItemView.extend({ + template: Handlebars.compile(jQuery('#issues-header-template').html() || ''), + + + modelEvents: { + 'change': 'render' + }, + + + events: { + 'click #issues-new-search': 'newSearch', + 'click #issues-filter-save-as': 'saveAs', + 'click #issues-filter-save': 'save', + 'click #issues-filter-copy': 'copy', + 'click #issues-filter-edit': 'edit' + }, + + + initialize: function(options) { + Backbone.Marionette.ItemView.prototype.initialize.apply(this, arguments); + this.listenTo(options.app.state, 'change', this.render); + }, + + + newSearch: function() { + this.model.clear(); + this.options.app.router.navigate('statuses=OPEN,REOPENED', { trigger: true, replace: true }); + }, + + + saveAs: function() { + var url = baseUrl + '/issues/save_as_form?' + (Backbone.history.fragment || '').replace(/\|/g, '&'); + openModalWindow(url, {}); + }, + + + save: function() { + var that = this; + url = baseUrl + '/issues/save/' + this.model.id + '?' + (Backbone.history.fragment || '').replace(/\|/g, '&'); + jQuery.ajax({ + type: 'POST', + url: url + }).done(function() { + that.options.app.state.set('search', false); + }); + }, + + + copy: function() { + var url = baseUrl + '/issues/copy_form/' + this.model.id; + openModalWindow(url, {}); + }, + + + edit: function() { + var url = baseUrl + '/issues/edit_form/' + this.model.id; + openModalWindow(url, {}); + }, + + + serializeData: function() { + return _.extend({ + canSave: this.model.id && this.options.app.state.get('search'), + appState: window.SS.appState.toJSON() + }, this.model.toJSON()); + } + + }); + + + + var IssueDetailCommentFormView = Backbone.Marionette.ItemView.extend({ + template: Handlebars.compile(jQuery('#issue-detail-comment-form-template').html() || ''), + + + ui: { + textarea: '#issue-comment-text', + cancelButton: '#issue-comment-cancel', + submitButton: '#issue-comment-submit' + }, + + + events: { + 'keyup #issue-comment-text': 'toggleSubmit', + 'click #issue-comment-cancel': 'cancel', + 'click #issue-comment-submit': 'submit' + }, + + + onDomRefresh: function() { + this.ui.textarea.focus(); + }, + + + toggleSubmit: function() { + this.ui.submitButton.prop('disabled', this.ui.textarea.val().length === 0); + }, + + + cancel: function() { + this.options.detailView.updateAfterAction(false); + }, + + + submit: function() { + var that = this, + text = this.ui.textarea.val(), + update = this.model && this.model.has('key'), + url = baseUrl + '/api/issues/' + (update ? 'edit_comment' : 'add_comment'), + data = { text: text }; + + if (update) { + data.key = this.model.get('key'); + } else { + data.issue = this.options.issue.get('key'); + } + + this.options.detailView.showActionSpinner(); + + jQuery.ajax({ + type: 'POST', + url: url, + data: data + }) + .done(function() { + that.options.detailView.updateAfterAction(true); + }) + .fail(function(r) { + alert(r.responseJSON.errors ? _.pluck(r.responseJSON.errors, 'msg').join(' ') : r); + that.options.detailView.hideActionSpinner(); + }); + } + }); + + + + var IssueDetailSetSeverityFormView = Backbone.Marionette.ItemView.extend({ + template: Handlebars.compile(jQuery('#issue-detail-set-severity-form-template').html() || ''), + + + ui: { + select: '#issue-set-severity-select' + }, + + + events: { + 'click #issue-set-severity-cancel': 'cancel', + 'click #issue-set-severity-submit': 'submit' + }, + + + onRender: function() { + var format = function(state) { + if (!state.id) return state.text; // optgroup + return '' + state.text; + } + + this.ui.select.select2({ + minimumResultsForSearch: 100, + formatResult: format, + formatSelection: format, + escapeMarkup: function(m) { return m; } + }); + }, + + + cancel: function() { + this.options.detailView.updateAfterAction(false); + }, + + + submit: function() { + var that = this; + + this.options.detailView.showActionSpinner(); + + jQuery.ajax({ + type: 'POST', + url: baseUrl + '/api/issues/set_severity', + data: { + issue: this.options.issue.get('key'), + severity: this.ui.select.val() + } + }) + .done(function() { + that.options.detailView.updateAfterAction(true); + }) + .fail(function(r) { + alert(r.responseJSON.errors ? _.pluck(r.responseJSON.errors, 'msg').join(' ') : r); + that.options.detailView.hideActionSpinner(); + }); + } + }); + + + + var IssueDetailAssignFormView = Backbone.Marionette.ItemView.extend({ + template: Handlebars.compile(jQuery('#issue-detail-assign-form-template').html() || ''), + + + ui: { + select: '#issue-assignee-select' + }, + + + events: { + 'click #issue-assign-cancel': 'cancel', + 'click #issue-assign-submit': 'submit' + }, + + + onRender: function() { + var currentUser = window.SS.currentUser, + assignee = this.options.issue.get('assignee'), + additionalChoices = []; + + if (!assignee || currentUser !== assignee) { + additionalChoices.push({ + id: currentUser, + text: window.SS.phrases.assignedToMe + }); + } + + if (!!assignee) { + additionalChoices.push({ + id: '', + text: window.SS.phrases.unassigned + }); + } + + var select2Options = { + allowClear: false, + width: '250px', + formatNoMatches: function() { return window.SS.phrases.select2.noMatches; }, + formatSearching: function() { return window.SS.phrases.select2.searching; }, + formatInputTooShort: function() { return window.SS.phrases.select2.tooShort; } + }; + + if (additionalChoices.length > 0) { + select2Options.minimumInputLength = 0; + select2Options.query = function(query) { + if (query.term.length == 0) { + query.callback({ results: additionalChoices }); + } else if (query.term.length >= 2) { + jQuery.ajax({ + url: baseUrl + '/api/users/search?f=s2', + data: { s: query.term }, + dataType: 'jsonp' + }).done(function(data) { + query.callback(data); + }); + } + } + } else { + select2Options.minimumInputLength = 2; + select2Options.ajax = { + quietMillis: 300, + url: baseUrl + '/api/users/search?f=s2', + data: function (term, page) { + return {s: term, p: page} + }, + results: function (data) { + return { more: data.more, results: data.results } + } + }; + } + + this.ui.select.select2(select2Options).select2('open'); + }, + + + cancel: function() { + this.options.detailView.updateAfterAction(false); + }, + + + submit: function() { + var that = this; + + this.options.detailView.showActionSpinner(); + + jQuery.ajax({ + type: 'POST', + url: baseUrl + '/api/issues/assign', + data: { + issue: this.options.issue.get('key'), + assignee: this.ui.select.val() + } + }) + .done(function() { + that.options.detailView.updateAfterAction(true); + }) + .fail(function(r) { + alert(r.responseJSON.errors ? _.pluck(r.responseJSON.errors, 'msg').join(' ') : r); + that.options.detailView.hideActionSpinner(); + }); + } + }); + + + + var IssueDetailPlanFormView = Backbone.Marionette.ItemView.extend({ + template: Handlebars.compile(jQuery('#issue-detail-plan-form-template').html() || ''), + + + collectionEvents: { + 'reset': 'render' + }, + + + ui: { + select: '#issue-detail-plan-select' + }, + + + events: { + 'click #issue-plan-cancel': 'cancel', + 'click #issue-plan-submit': 'submit' + }, + + + onRender: function() { + this.ui.select.select2({ + width: '250px', + minimumResultsForSearch: 100 + }); + + this.$('.error a') + .prop('href', baseUrl + '/action_plans/index/' + this.options.issue.get('project')); + }, + + + cancel: function() { + this.options.detailView.updateAfterAction(false); + }, + + + submit: function() { + var that = this, + plan = this.ui.select.val(); + + this.options.detailView.showActionSpinner(); + + jQuery.ajax({ + type: 'POST', + url: baseUrl + '/api/issues/plan', + data: { + issue: this.options.issue.get('key'), + plan: plan === '#unplan' ? '' : plan + } + }) + .done(function() { + that.options.detailView.updateAfterAction(true); + }) + .fail(function(r) { + alert(r.responseJSON.errors ? _.pluck(r.responseJSON.errors, 'msg').join(' ') : r); + that.options.detailView.hideActionSpinner(); + }); + }, + + + serializeData: function() { + return { + items: this.collection.toJSON(), + issue: this.options.issue.toJSON() + } + } + }); + + + + var IssueDetailRuleView = Backbone.Marionette.ItemView.extend({ + template: Handlebars.compile(jQuery('#issue-detail-rule-template').html() || ''), + className: 'rule-desc', + modelEvents: { 'change': 'render' }, + + + serializeData: function() { + return _.extend({ + characteristic: this.options.issue.get('characteristic'), + subCharacteristic: this.options.issue.get('subCharacteristic') + }, this.model.toJSON()); + } + }); + + + + var IssueDetailView = Backbone.Marionette.Layout.extend({ + template: Handlebars.compile(jQuery('#issue-detail-template').html() || ''), + + + regions: { + formRegion: '.code-issue-form', + ruleRegion: '#tab-issue-rule' + }, + + + events: { + 'click .code-issue-toggle': 'toggleCollapsed', + + 'click [href=#tab-issue-rule]': 'fetchRule', + + 'click #issue-comment': 'comment', + 'click .issue-comment-edit': 'editComment', + 'click .issue-comment-delete': 'deleteComment', + 'click .issue-transition': 'transition', + 'click #issue-set-severity': 'setSeverity', + 'click #issue-assign': 'assign', + 'click #issue-assign-to-me': 'assignToMe', + 'click #issue-plan': 'plan', + 'click .issue-action': 'action' + }, + + + modelEvents: { + 'change': 'render' + }, + + + onRender: function() { + this.$('.code-issue-details').tabs(); + this.$('.code-issue-form').hide(); + this.rule = new Rule({ key: this.model.get('rule') }); + this.ruleRegion.show(new IssueDetailRuleView({ + model: this.rule, + issue: this.model + })); + this.initReferenceLinks(); + }, + + + initReferenceLinks: function() { + var sourcesId = 'sources_' + this.model.get('key'); + this.$('#' + sourcesId).on('click', 'span.sym', { id: sourcesId }, highlight_usages); + }, + + + onDomRefresh: function() { + var sourceTitleHeight = this.$('.source_title').outerHeight(); + jQuery('.navigator-details').css('padding-top', (sourceTitleHeight + 10) + 'px'); + }, + + + onClose: function() { + if (this.ruleRegion) { + this.ruleRegion.reset(); + } + }, + + + resetIssue: function(options) { + var key = this.model.get('key'); + this.model.clear({ silent: true }); + this.model.set({ key: key }, { silent: true }); + return this.model.fetch(options); + }, + + + toggleCollapsed: function() { + this.$('.code-issue').toggleClass('code-issue-collapsed'); + this.fetchRule(); + }, + + + fetchRule: function() { + var that = this; + if (!this.rule.has('name')) { + this.$('#tab-issue-rule').addClass('navigator-fetching'); + this.rule.fetch({ + success: function() { + that.$('#tab-issue-rule').removeClass('navigator-fetching'); + } + }); + } + }, + + + showActionView: function(view) { + this.$('.code-issue-actions').hide(); + this.$('.code-issue-form').show(); + this.formRegion.show(view); + }, + + + showActionSpinner: function() { + this.$('.code-issue-actions').addClass('navigator-fetching'); + }, + + + hideActionSpinner: function() { + this.$('.code-issue-actions').removeClass('navigator-fetching'); + }, + + + updateAfterAction: function(fetch) { + var that = this; + + that.formRegion.reset(); + that.$('.code-issue-actions').show(); + that.$('.code-issue-form').hide(); + that.$('[data-comment-key]').show(); + + if (fetch) { + jQuery.when(this.resetIssue()).done(function() { + that.hideActionSpinner(); + }); + } + }, + + + comment: function() { + var commentFormView = new IssueDetailCommentFormView({ + issue: this.model, + detailView: this + }); + this.showActionView(commentFormView); + }, + + + editComment: function(e) { + var commentEl = jQuery(e.target).closest('[data-comment-key]'), + commentKey = commentEl.data('comment-key'), + comment = _.findWhere(this.model.get('comments'), { key: commentKey }); + + commentEl.hide(); + + var commentFormView = new IssueDetailCommentFormView({ + model: new Backbone.Model(comment), + issue: this.model, + detailView: this + }); + this.showActionView(commentFormView); + }, + + + deleteComment: function(e) { + var that = this, + commentKey = jQuery(e.target).closest('[data-comment-key]').data('comment-key'), + confirmMsg = jQuery(e.target).data('confirm-msg'); + + if (confirm(confirmMsg)) { + this.showActionSpinner(); + + jQuery.ajax({ + type: "POST", + url: baseUrl + "/issue/delete_comment?id=" + commentKey + }) + .done(function() { + that.updateAfterAction(true); + }) + .fail(function(r) { + alert(r.responseJSON.errors ? _.pluck(r.responseJSON.errors, 'msg').join(' ') : r); + that.hideActionSpinner(); + }); + } + }, + + + transition: function(e) { + var that = this; + + this.showActionSpinner(); + + jQuery.ajax({ + type: 'POST', + url: baseUrl + '/api/issues/do_transition', + data: { + issue: this.model.get('key'), + transition: jQuery(e.target).data('transition') + } + }) + .done(function() { + that.resetIssue(); + }) + .fail(function(r) { + alert(r.responseJSON.errors ? _.pluck(r.responseJSON.errors, 'msg').join(' ') : r); + that.hideActionSpinner(); + }); + }, + + + setSeverity: function() { + var setSeverityFormView = new IssueDetailSetSeverityFormView({ + issue: this.model, + detailView: this + }); + this.showActionView(setSeverityFormView); + }, + + + assign: function() { + var assignFormView = new IssueDetailAssignFormView({ + issue: this.model, + detailView: this + }); + this.showActionView(assignFormView); + }, + + + assignToMe: function() { + var that = this; + + this.showActionSpinner(); + + jQuery.ajax({ + type: 'POST', + url: baseUrl + '/api/issues/assign', + data: { + issue: this.model.get('key'), + assignee: window.SS.currentUser + } + }) + .done(function() { + that.resetIssue(); + }) + .fail(function(r) { + alert(r.responseJSON.errors ? _.pluck(r.responseJSON.errors, 'msg').join(' ') : r); + that.hideActionSpinner(); + }); + }, + + + plan: function() { + var that = this, + actionPlans = new ActionPlans(), + planFormView = new IssueDetailPlanFormView({ + collection: actionPlans, + issue: this.model, + detailView: this + }); + + this.showActionSpinner(); + + actionPlans.fetch({ + reset: true, + data: { project: this.model.get('project') }, + success: function() { + that.hideActionSpinner(); + that.showActionView(planFormView); + } + }); + }, + + action: function(e) { + var that = this, + actionKey = jQuery(e.target).data('action'); + + this.showActionSpinner(); + + jQuery.ajax({ + type: 'POST', + url: baseUrl + '/api/issues/do_action', + data: { + issue: this.model.get('key'), + actionKey: actionKey + } + }) + .done(function() { + that.resetIssue(); + }) + .fail(function(r) { + alert(r.responseJSON.errors ? _.pluck(r.responseJSON.errors, 'msg').join(' ') : r); + that.hideActionSpinner(); + }); + }, + + + serializeData: function() { + return _.extend({ + source: this.source, + scm: this.scm + }, this.model.toJSON()); + } + + }); + + + + var IssuesDetailsFavoriteFilterView = window.SS.DetailsFavoriteFilterView.extend({ + template: Handlebars.compile(jQuery('#issues-details-favorite-filter-template').html() || ''), + + + applyFavorite: function(e) { + var id = $j(e.target).data('id'), + filter = new window.SS.FavoriteFilter({ id: id }), + app = this.options.filterView.options.app; + + filter.fetch({ + success: function() { + app.state.set('search', false); + app.favoriteFilter.clear({ silent: true }); + app.favoriteFilter.set(filter.toJSON()); + } + }); + + this.options.filterView.hideDetails(); + }, + + + serializeData: function() { + return _.extend({}, this.model.toJSON(), { + items: this.model.get('choices') + }); + } + }); + + + + var IssuesFavoriteFilterView = window.SS.FavoriteFilterView.extend({ + + initialize: function() { + window.SS.BaseFilterView.prototype.initialize.call(this, { + detailsView: IssuesDetailsFavoriteFilterView + }); + + this.listenTo(window.SS.appState, 'change:favorites', this.updateFavorites); + }, + + + updateFavorites: function() { + this.model.set('choices', window.SS.appState.get('favorites')); + this.render(); + } + }); + + + + var IssuesRouter = Backbone.Router.extend({ + + routes: { + '': 'emptyQuery', + ':query': 'index' + }, + + + initialize: function(options) { + this.app = options.app; + }, + + + parseQuery: function(query, separator) { + return (query || '').split(separator || '|').map(function(t) { + var tokens = t.split('='); + return { + key: tokens[0], + value: decodeURIComponent(tokens[1]) + } + }); + }, + + + emptyQuery: function() { + this.navigate('statuses=OPEN,REOPENED', { trigger: true, replace: true }); + }, + + + index: function(query) { + var params = this.parseQuery(query); + + var idObj = _.findWhere(params, { key: 'id' }); + if (idObj) { + var that = this, + f = this.app.favoriteFilter; + this.app.canSave = false; + f.set('id', idObj.value); + f.fetch({ + success: function() { + params = _.extend({}, that.parseQuery(f.get('query')), params); + that.loadResults(params); + } + }); + } else { + this.loadResults(params); + } + }, + + + loadResults: function(params) { + this.app.filterBarView.restoreFromQuery(params); + this.app.restoreSorting(params); + this.app.fetchFirstPage(); + } + + }); + + + + /* + * Export public classes + */ + + _.extend(window.SS, { + AppState: AppState, + Issue: Issue, + Issues: Issues, + FavoriteFilter: FavoriteFilter, + FavoriteFilters: FavoriteFilters, + IssueView: IssueView, + IssuesView: IssuesView, + IssuesActionsView: IssuesActionsView, + IssuesFilterBarView: IssuesFilterBarView, + IssuesHeaderView: IssuesHeaderView, + IssuesFavoriteFilterView: IssuesFavoriteFilterView, + IssueDetailView: IssueDetailView, + IssuesRouter: IssuesRouter + }); + +}); diff --git a/sonar-server/src/main/webapp/stylesheets/navigator.css b/sonar-server/src/main/webapp/stylesheets/navigator.css index 6cd6a7b994e..bacd395e248 100644 --- a/sonar-server/src/main/webapp/stylesheets/navigator.css +++ b/sonar-server/src/main/webapp/stylesheets/navigator.css @@ -276,6 +276,7 @@ } .navigator-details .scm .author { display: inline-block; + vertical-align: middle; max-width: 100px; white-space: nowrap; overflow: hidden; @@ -312,7 +313,7 @@ background-color: #fff; border-bottom: 1px solid #e1e1e1; border-right: 1px solid #e1e1e1; - overflow: scroll; + overflow: hidden; display: none; } .navigator-actions-order-choices > li { diff --git a/sonar-server/src/main/webapp/stylesheets/navigator/base.css b/sonar-server/src/main/webapp/stylesheets/navigator/base.css index c86ddfc501d..0a122c1b0e9 100644 --- a/sonar-server/src/main/webapp/stylesheets/navigator/base.css +++ b/sonar-server/src/main/webapp/stylesheets/navigator/base.css @@ -276,6 +276,7 @@ } .navigator-details .scm .author { display: inline-block; + vertical-align: middle; max-width: 100px; white-space: nowrap; overflow: hidden; @@ -312,7 +313,7 @@ background-color: #fff; border-bottom: 1px solid #e1e1e1; border-right: 1px solid #e1e1e1; - overflow: scroll; + overflow: hidden; display: none; } .navigator-actions-order-choices > li { diff --git a/sonar-server/src/main/webapp/stylesheets/navigator/base.less b/sonar-server/src/main/webapp/stylesheets/navigator/base.less index 73623b8bdc9..e0a33b005df 100644 --- a/sonar-server/src/main/webapp/stylesheets/navigator/base.less +++ b/sonar-server/src/main/webapp/stylesheets/navigator/base.less @@ -330,6 +330,7 @@ .scm .author { display: inline-block; + vertical-align: middle; max-width: 100px; white-space: nowrap; overflow: hidden; @@ -371,7 +372,7 @@ background-color: #fff; border-bottom: 1px solid @navigatorBorderLightColor; border-right: 1px solid @navigatorBorderLightColor; - overflow: scroll; + overflow: hidden; display: none; & > li { diff --git a/sonar-server/src/main/webapp/stylesheets/select2-sonar.css b/sonar-server/src/main/webapp/stylesheets/select2-sonar.css index 07019a04423..4f60dea2a4d 100644 --- a/sonar-server/src/main/webapp/stylesheets/select2-sonar.css +++ b/sonar-server/src/main/webapp/stylesheets/select2-sonar.css @@ -142,7 +142,7 @@ .select2-container-multi .select2-choices .select2-search-field input.select2-active { background-image: url('../images/spinner.gif'); } -@media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 144dpi) { +@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { .select2-search-choice-close, .select2-container .select2-choice abbr, .select2-container .select2-choice div b { diff --git a/sonar-server/src/main/webapp/stylesheets/select2-sonar.less b/sonar-server/src/main/webapp/stylesheets/select2-sonar.less index e37cd3f9014..fed92898f3d 100644 --- a/sonar-server/src/main/webapp/stylesheets/select2-sonar.less +++ b/sonar-server/src/main/webapp/stylesheets/select2-sonar.less @@ -167,7 +167,7 @@ background-image: url(@spinnerPath); } -@media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 144dpi) { +@media @retina { .select2-search-choice-close, .select2-container .select2-choice abbr, .select2-container .select2-choice div b { diff --git a/sonar-server/src/main/webapp/stylesheets/select2.css b/sonar-server/src/main/webapp/stylesheets/select2.css index 6451016022e..aae6c48ffea 100755 --- a/sonar-server/src/main/webapp/stylesheets/select2.css +++ b/sonar-server/src/main/webapp/stylesheets/select2.css @@ -523,7 +523,7 @@ disabled look for already selected choices in the results dropdown /* Retina-ize icons */ -@media only screen and (-webkit-min-device-pixel-ratio: 1.5) { +@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { .select2-search input, .select2-search-choice-close, .select2-container .select2-choice abbr, .select2-container .select2-choice div b { background-image: url(select2x2.png) !important; background-repeat: no-repeat !important; diff --git a/sonar-server/src/main/webapp/stylesheets/style.css b/sonar-server/src/main/webapp/stylesheets/style.css index 31433be3918..0ee49feb93e 100644 --- a/sonar-server/src/main/webapp/stylesheets/style.css +++ b/sonar-server/src/main/webapp/stylesheets/style.css @@ -648,6 +648,10 @@ th.operations, td.operations { white-space: nowrap; } +.sources2 tr:first-child td.revision { + border-top: none; +} + .sources2 tr.row td.plus { background-color: #EFEFEF; padding: 0; @@ -666,7 +670,6 @@ th.operations, td.operations { } .sources2 td.gray { - border-left: 1px solid #DDD; background-color: #EFEFEF; padding: 2px 0.5em 0; } @@ -864,7 +867,9 @@ th.operations, td.operations { padding: 5px 10px; } -.code-issue-form input[type=submit] { +.code-issue-form input[type=submit], +.code-issue-form input[type=button], +.code-issue-form button { vertical-align: middle; } -- 2.39.5