Feature: Bulk Issues update

3-1-stable
randx 2012-07-28 03:35:24 +03:00
parent d63706d72c
commit 00b280c3f9
10 changed files with 144 additions and 32 deletions

View File

@ -52,14 +52,6 @@ $(document).ready(function(){
}
});
$("#issues-table .issue").live('click', function(e){
if(e.target.nodeName != "A" && e.target.nodeName != "INPUT") {
location.href = $(this).attr("url");
e.stopPropagation();
return false;
}
});
/**
* Focus search field by pressing 's' key
*/

View File

@ -67,6 +67,10 @@ function initIssuesSearch() {
*/
function issuesPage(){
initIssuesSearch();
$("#update_status").chosen();
$("#update_assignee_id").chosen();
$("#update_milestone_id").chosen();
$("#label_name").chosen();
$("#assignee_id").chosen();
$("#milestone_id").chosen();
@ -94,4 +98,29 @@ function issuesPage(){
});
});
$(".check_all_issues").click(function () {
$('.selected_issue').attr('checked', this.checked);
issuesCheckChanged();
});
$('.selected_issue').bind('change', issuesCheckChanged);
}
function issuesCheckChanged() {
var checked_issues = $('.selected_issue:checked');
if(checked_issues.length > 0) {
var ids = []
$.each(checked_issues, function(index, value) {
ids.push($(value).attr("data-id"));
})
$('#update_issues_ids').val(ids);
$('.issues_filters').hide();
$('.issues_bulk_update').show();
} else {
$('#update_issues_ids').val([]);
$('.issues_bulk_update').hide();
$('.issues_filters').show();
}
}

View File

@ -30,6 +30,13 @@
.issue {
padding:7px 10px;
.issue_check {
float:left;
padding: 8px 0;
padding-right: 8px;
min-width: 15px;
}
p {
padding-top:0;
padding-bottom:2px;
@ -41,3 +48,28 @@
}
}
}
input.check_all_issues {
float:left;
padding: 8px 0;
margin: 14px 0;
margin-right: 10px;
}
#issues-table-holder {
.issues_bulk_update {
padding: 0 5px;
margin: 0;
form {
margin:0;
padding-bottom:5px;
}
.update_selected_issues {
position:relative;
top:-2px;
margin-left:3px;
}
}
}

View File

@ -4,5 +4,17 @@ class BaseContext
def initialize(project, user, params)
@project, @current_user, @params = project, user, params.dup
end
def abilities
@abilities ||= begin
abilities = Six.new
abilities << Ability
abilities
end
end
def can?(object, action, subject)
abilities.allowed?(object, action, subject)
end
end

View File

@ -0,0 +1,24 @@
class IssuesBulkUpdateContext < BaseContext
def execute
update_data = params[:update]
issues_ids = update_data[:issues_ids].split(",")
milestone_id = update_data[:milestone_id]
assignee_id = update_data[:assignee_id]
status = update_data[:status]
opts = {}
opts[:milestone_id] = milestone_id if milestone_id.present?
opts[:assignee_id] = assignee_id if assignee_id.present?
opts[:closed] = (status == "closed") if status.present?
issues = Issue.where(:id => issues_ids).all
issues = issues.select { |issue| can?(current_user, :modify_issue, issue) }
issues.each { |issue| issue.update_attributes(opts) }
{
:count => issues.count,
:success => !issues.count.zero?
}
end
end

View File

@ -113,6 +113,11 @@ class IssuesController < ApplicationController
render :partial => 'issues'
end
def bulk_update
result = IssuesBulkUpdateContext.new(project, current_user, params).execute
redirect_to :back, :notice => "#{result[:count]} issues updated"
end
protected
def issue

View File

@ -12,3 +12,4 @@
- else
%li
%h4.nothing_here_message Nothing to show here

View File

@ -1,6 +1,6 @@
%li.wll{ :id => dom_id(issue), :class => issue_css_classes(issue), :url => project_issue_path(issue.project, issue) }
.list_legend
.icon
.issue_check
= check_box_tag dom_id(issue,"selected"), nil, false, 'data-id' => issue.id, :class => "selected_issue", :disabled => !can?(current_user, :modify_issue, issue)
.right
- issue.labels.each do |label|
%span.label.label-issue.grouped
@ -34,4 +34,4 @@
&nbsp;
- if issue.upvotes > 0
%span.badge.badge-success= "+#{issue.upvotes}"
%span.badge.badge-success= "+#{issue.upvotes}"

View File

@ -14,35 +14,51 @@
= search_field_tag :issue_search, nil, { :placeholder => 'Search', :class => 'issue_search span3 right neib' }
.clearfix
%div#issues-table-holder.ui-box
.title
.left
%ul.nav.nav-pills.left
%li{:class => ("active" if (params[:f] == issues_filter[:open] || !params[:f]))}
= link_to project_issues_path(@project, :f => issues_filter[:open], :milestone_id => params[:milestone_id]) do
Open
%li{:class => ("active" if params[:f] == issues_filter[:closed])}
= link_to project_issues_path(@project, :f => issues_filter[:closed], :milestone_id => params[:milestone_id]) do
Closed
%li{:class => ("active" if params[:f] == issues_filter[:to_me])}
= link_to project_issues_path(@project, :f => issues_filter[:to_me], :milestone_id => params[:milestone_id]) do
To Me
%li{:class => ("active" if params[:f] == issues_filter[:all])}
= link_to project_issues_path(@project, :f => issues_filter[:all], :milestone_id => params[:milestone_id]) do
All
= check_box_tag "check_all_issues", nil, false, :class => "check_all_issues left"
.right
= form_tag project_issues_path(@project), :method => :get, :class => :right do
= select_tag(:label_name, options_for_select(issue_tags, params[:label_name]), :prompt => "Labels")
= select_tag(:assignee_id, options_from_collection_for_select(@project.users.all, "id", "name", params[:assignee_id]), :prompt => "Assignee")
= select_tag(:milestone_id, options_from_collection_for_select(@project.milestones.order("id desc").all, "id", "title", params[:milestone_id]), :prompt => "Milestone")
.issues_bulk_update.hide
= form_tag bulk_update_project_issues_path(@project), :method => :post do
%span Update selected issues with
&nbsp;
= select_tag('update[status]', options_for_select(['open', 'closed']), :prompt => "Status")
= select_tag('update[assignee_id]', options_from_collection_for_select(@project.users.all, "id", "name", params[:assignee_id]), :prompt => "Assignee")
= select_tag('update[milestone_id]', options_from_collection_for_select(@project.milestones.order("id desc").all, "id", "title", params[:milestone_id]), :prompt => "Milestone")
= hidden_field_tag 'update[issues_ids]', []
= hidden_field_tag :f, params[:f]
.clearfix
= button_tag "Save", :class => "btn update_selected_issues"
.issues_filters
.left
%ul.nav.nav-pills.left
%li{:class => ("active" if (params[:f] == issues_filter[:open] || !params[:f]))}
= link_to project_issues_path(@project, :f => issues_filter[:open], :milestone_id => params[:milestone_id]) do
Open
%li{:class => ("active" if params[:f] == issues_filter[:closed])}
= link_to project_issues_path(@project, :f => issues_filter[:closed], :milestone_id => params[:milestone_id]) do
Closed
%li{:class => ("active" if params[:f] == issues_filter[:to_me])}
= link_to project_issues_path(@project, :f => issues_filter[:to_me], :milestone_id => params[:milestone_id]) do
To Me
%li{:class => ("active" if params[:f] == issues_filter[:all])}
= link_to project_issues_path(@project, :f => issues_filter[:all], :milestone_id => params[:milestone_id]) do
All
.right
= form_tag project_issues_path(@project), :method => :get, :class => :right do
= select_tag(:label_name, options_for_select(issue_tags, params[:label_name]), :prompt => "Labels")
= select_tag(:assignee_id, options_from_collection_for_select(@project.users.all, "id", "name", params[:assignee_id]), :prompt => "Assignee")
= select_tag(:milestone_id, options_from_collection_for_select(@project.milestones.order("id desc").all, "id", "title", params[:milestone_id]), :prompt => "Milestone")
= hidden_field_tag :f, params[:f]
.clearfix
%ul#issues-table.unstyled.issues_table
= render "issues"
:javascript
$(function(){
issuesPage();
})
})

View File

@ -194,6 +194,7 @@ Gitlab::Application.routes.draw do
resources :issues do
collection do
post :sort
post :bulk_update
get :search
end
end