Feature: Bulk Issues update
This commit is contained in:
parent
d63706d72c
commit
00b280c3f9
10 changed files with 144 additions and 32 deletions
|
@ -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
|
* Focus search field by pressing 's' key
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -67,6 +67,10 @@ function initIssuesSearch() {
|
||||||
*/
|
*/
|
||||||
function issuesPage(){
|
function issuesPage(){
|
||||||
initIssuesSearch();
|
initIssuesSearch();
|
||||||
|
$("#update_status").chosen();
|
||||||
|
$("#update_assignee_id").chosen();
|
||||||
|
$("#update_milestone_id").chosen();
|
||||||
|
|
||||||
$("#label_name").chosen();
|
$("#label_name").chosen();
|
||||||
$("#assignee_id").chosen();
|
$("#assignee_id").chosen();
|
||||||
$("#milestone_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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,13 @@
|
||||||
.issue {
|
.issue {
|
||||||
padding:7px 10px;
|
padding:7px 10px;
|
||||||
|
|
||||||
|
.issue_check {
|
||||||
|
float:left;
|
||||||
|
padding: 8px 0;
|
||||||
|
padding-right: 8px;
|
||||||
|
min-width: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
padding-top:0;
|
padding-top:0;
|
||||||
padding-bottom:2px;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,5 +4,17 @@ class BaseContext
|
||||||
def initialize(project, user, params)
|
def initialize(project, user, params)
|
||||||
@project, @current_user, @params = project, user, params.dup
|
@project, @current_user, @params = project, user, params.dup
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
|
|
24
app/contexts/issues_bulk_update_context.rb
Normal file
24
app/contexts/issues_bulk_update_context.rb
Normal 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
|
||||||
|
|
|
@ -113,6 +113,11 @@ class IssuesController < ApplicationController
|
||||||
render :partial => 'issues'
|
render :partial => 'issues'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def bulk_update
|
||||||
|
result = IssuesBulkUpdateContext.new(project, current_user, params).execute
|
||||||
|
redirect_to :back, :notice => "#{result[:count]} issues updated"
|
||||||
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def issue
|
def issue
|
||||||
|
|
|
@ -12,3 +12,4 @@
|
||||||
- else
|
- else
|
||||||
%li
|
%li
|
||||||
%h4.nothing_here_message Nothing to show here
|
%h4.nothing_here_message Nothing to show here
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
%li.wll{ :id => dom_id(issue), :class => issue_css_classes(issue), :url => project_issue_path(issue.project, issue) }
|
%li.wll{ :id => dom_id(issue), :class => issue_css_classes(issue), :url => project_issue_path(issue.project, issue) }
|
||||||
.list_legend
|
.issue_check
|
||||||
.icon
|
= check_box_tag dom_id(issue,"selected"), nil, false, 'data-id' => issue.id, :class => "selected_issue", :disabled => !can?(current_user, :modify_issue, issue)
|
||||||
.right
|
.right
|
||||||
- issue.labels.each do |label|
|
- issue.labels.each do |label|
|
||||||
%span.label.label-issue.grouped
|
%span.label.label-issue.grouped
|
||||||
|
@ -34,4 +34,4 @@
|
||||||
|
|
||||||
|
|
||||||
- if issue.upvotes > 0
|
- if issue.upvotes > 0
|
||||||
%span.badge.badge-success= "+#{issue.upvotes}"
|
%span.badge.badge-success= "+#{issue.upvotes}"
|
||||||
|
|
|
@ -14,35 +14,51 @@
|
||||||
= search_field_tag :issue_search, nil, { :placeholder => 'Search', :class => 'issue_search span3 right neib' }
|
= search_field_tag :issue_search, nil, { :placeholder => 'Search', :class => 'issue_search span3 right neib' }
|
||||||
|
|
||||||
.clearfix
|
.clearfix
|
||||||
|
|
||||||
%div#issues-table-holder.ui-box
|
%div#issues-table-holder.ui-box
|
||||||
.title
|
.title
|
||||||
.left
|
= check_box_tag "check_all_issues", nil, false, :class => "check_all_issues 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
|
.issues_bulk_update.hide
|
||||||
= select_tag(:label_name, options_for_select(issue_tags, params[:label_name]), :prompt => "Labels")
|
= form_tag bulk_update_project_issues_path(@project), :method => :post do
|
||||||
= select_tag(:assignee_id, options_from_collection_for_select(@project.users.all, "id", "name", params[:assignee_id]), :prompt => "Assignee")
|
%span Update selected issues with
|
||||||
= select_tag(:milestone_id, options_from_collection_for_select(@project.milestones.order("id desc").all, "id", "title", params[:milestone_id]), :prompt => "Milestone")
|
|
||||||
|
= 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]
|
= 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
|
%ul#issues-table.unstyled.issues_table
|
||||||
= render "issues"
|
= render "issues"
|
||||||
|
|
||||||
|
|
||||||
:javascript
|
:javascript
|
||||||
$(function(){
|
$(function(){
|
||||||
issuesPage();
|
issuesPage();
|
||||||
})
|
})
|
||||||
|
|
|
@ -194,6 +194,7 @@ Gitlab::Application.routes.draw do
|
||||||
resources :issues do
|
resources :issues do
|
||||||
collection do
|
collection do
|
||||||
post :sort
|
post :sort
|
||||||
|
post :bulk_update
|
||||||
get :search
|
get :search
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue