From 00b280c3f9521f3e001b2ffc8a8a52f2a93a69d9 Mon Sep 17 00:00:00 2001 From: randx Date: Sat, 28 Jul 2012 03:35:24 +0300 Subject: [PATCH] Feature: Bulk Issues update --- app/assets/javascripts/application.js | 8 --- app/assets/javascripts/issues.js | 29 +++++++++++ app/assets/stylesheets/sections/issues.scss | 32 ++++++++++++ app/contexts/base_context.rb | 12 +++++ app/contexts/issues_bulk_update_context.rb | 24 +++++++++ app/controllers/issues_controller.rb | 5 ++ app/views/issues/_issues.html.haml | 1 + app/views/issues/_show.html.haml | 6 +-- app/views/issues/index.html.haml | 58 +++++++++++++-------- config/routes.rb | 1 + 10 files changed, 144 insertions(+), 32 deletions(-) create mode 100644 app/contexts/issues_bulk_update_context.rb diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 527b5c79..56e26a06 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -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 */ diff --git a/app/assets/javascripts/issues.js b/app/assets/javascripts/issues.js index 0acf9ec8..bc056965 100644 --- a/app/assets/javascripts/issues.js +++ b/app/assets/javascripts/issues.js @@ -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(); + } } diff --git a/app/assets/stylesheets/sections/issues.scss b/app/assets/stylesheets/sections/issues.scss index 12926d3f..82f180c5 100644 --- a/app/assets/stylesheets/sections/issues.scss +++ b/app/assets/stylesheets/sections/issues.scss @@ -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; + } + + + } +} diff --git a/app/contexts/base_context.rb b/app/contexts/base_context.rb index 6eb8ee46..101be50d 100644 --- a/app/contexts/base_context.rb +++ b/app/contexts/base_context.rb @@ -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 diff --git a/app/contexts/issues_bulk_update_context.rb b/app/contexts/issues_bulk_update_context.rb new file mode 100644 index 00000000..0ba779de --- /dev/null +++ b/app/contexts/issues_bulk_update_context.rb @@ -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 + diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index c36258c8..85333b85 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -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 diff --git a/app/views/issues/_issues.html.haml b/app/views/issues/_issues.html.haml index 17141cc4..fc515ec3 100644 --- a/app/views/issues/_issues.html.haml +++ b/app/views/issues/_issues.html.haml @@ -12,3 +12,4 @@ - else %li %h4.nothing_here_message Nothing to show here + diff --git a/app/views/issues/_show.html.haml b/app/views/issues/_show.html.haml index 18294af4..574777be 100644 --- a/app/views/issues/_show.html.haml +++ b/app/views/issues/_show.html.haml @@ -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 @@   - if issue.upvotes > 0 - %span.badge.badge-success= "+#{issue.upvotes}" \ No newline at end of file + %span.badge.badge-success= "+#{issue.upvotes}" diff --git a/app/views/issues/index.html.haml b/app/views/issues/index.html.haml index fb8b9f8e..f033536e 100644 --- a/app/views/issues/index.html.haml +++ b/app/views/issues/index.html.haml @@ -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 +   + = 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(); - }) \ No newline at end of file + }) diff --git a/config/routes.rb b/config/routes.rb index dea4df46..664f4649 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -194,6 +194,7 @@ Gitlab::Application.routes.draw do resources :issues do collection do post :sort + post :bulk_update get :search end end