Skip to content
Snippets Groups Projects
Commit f28ca293 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets
Browse files

Add bulk update support for merge requests list

parent 43d6328f
No related branches found
No related tags found
No related merge requests found
Showing
with 98 additions and 81 deletions
Loading
Loading
@@ -23,6 +23,7 @@
case 'projects:boards:show':
shortcut_handler = new ShortcutsNavigation();
break;
case 'projects:merge_requests:index':
case 'projects:issues:index':
Issuable.init();
new IssuableBulkActions();
Loading
Loading
@@ -93,10 +94,6 @@
break;
case "projects:merge_requests:conflicts":
window.mcui = new MergeConflictResolver()
case 'projects:merge_requests:index':
shortcut_handler = new ShortcutsNavigation();
Issuable.init();
break;
case 'dashboard:activity':
new Activities();
break;
Loading
Loading
Loading
Loading
@@ -77,7 +77,7 @@
},
checkChanged: function() {
const $checkedIssues = $('.selected_issue:checked');
const $updateIssuesIds = $('#update_issues_ids');
const $updateIssuesIds = $('#update_issuable_ids');
const $issuesOtherFilters = $('.issues-other-filters');
const $issuesBulkUpdate = $('.issues_bulk_update');
 
Loading
Loading
Loading
Loading
@@ -5,7 +5,7 @@
if (opts == null) {
opts = {};
}
this.container = (ref = opts.container) != null ? ref : $('.content'), this.form = (ref1 = opts.form) != null ? ref1 : this.getElement('.bulk-update'), this.issues = (ref2 = opts.issues) != null ? ref2 : this.getElement('.issues-list .issue');
this.container = (ref = opts.container) != null ? ref : $('.content'), this.form = (ref1 = opts.form) != null ? ref1 : this.getElement('.bulk-update'), this.issues = (ref2 = opts.issues) != null ? ref2 : this.getElement('.issuable-list > li');
this.form.data('bulkActions', this);
this.willUpdateLabels = false;
this.bindEvents();
Loading
Loading
@@ -106,7 +106,7 @@
state_event: this.form.find('input[name="update[state_event]"]').val(),
assignee_id: this.form.find('input[name="update[assignee_id]"]').val(),
milestone_id: this.form.find('input[name="update[milestone_id]"]').val(),
issues_ids: this.form.find('input[name="update[issues_ids]"]').val(),
issuable_ids: this.form.find('input[name="update[issuable_ids]"]').val(),
subscription_event: this.form.find('input[name="update[subscription_event]"]').val(),
add_label_ids: [],
remove_label_ids: []
Loading
Loading
Loading
Loading
@@ -404,3 +404,18 @@
margin-bottom: $gl-padding;
}
}
.issuable-list {
li {
.issue-check {
float: left;
padding-right: 16px;
margin-bottom: 10px;
min-width: 15px;
.selected_issue {
vertical-align: text-top;
}
}
}
}
Loading
Loading
@@ -7,17 +7,6 @@
margin-bottom: 2px;
}
 
.issue-check {
float: left;
padding-right: 16px;
margin-bottom: 10px;
min-width: 15px;
.selected_issue {
vertical-align: text-top;
}
}
.issue-labels {
display: inline-block;
}
Loading
Loading
Loading
Loading
@@ -3,6 +3,7 @@ module IssuableActions
 
included do
before_action :authorize_destroy_issuable!, only: :destroy
before_action :authorize_admin_issuable!, only: :bulk_update
end
 
def destroy
Loading
Loading
@@ -13,6 +14,13 @@ module IssuableActions
redirect_to polymorphic_path([@project.namespace.becomes(Namespace), @project, issuable.class])
end
 
def bulk_update
result = Issuable::BulkUpdateService.new(project, current_user, bulk_update_params).execute(resource_name)
quantity = result[:count]
render json: { notice: "#{quantity} #{resource_name.pluralize(quantity)} updated" }
end
private
 
def authorize_destroy_issuable!
Loading
Loading
@@ -20,4 +28,27 @@ module IssuableActions
return access_denied!
end
end
def authorize_admin_issuable!
unless current_user.can?(:"admin_#{resource_name}", @project)
return access_denied!
end
end
def bulk_update_params
params.require(:update).permit(
:issuable_ids,
:assignee_id,
:milestone_id,
:state_event,
:subscription_event,
label_ids: [],
add_label_ids: [],
remove_label_ids: []
)
end
def resource_name
@resource_name ||= controller_name.singularize
end
end
Loading
Loading
@@ -20,9 +20,6 @@ class Projects::IssuesController < Projects::ApplicationController
# Allow modify issue
before_action :authorize_update_issue!, only: [:edit, :update]
 
# Allow issues bulk update
before_action :authorize_admin_issues!, only: [:bulk_update]
respond_to :html
 
def index
Loading
Loading
@@ -168,16 +165,6 @@ class Projects::IssuesController < Projects::ApplicationController
end
end
 
def bulk_update
result = Issues::BulkUpdateService.new(project, current_user, bulk_update_params).execute
respond_to do |format|
format.json do
render json: { notice: "#{result[:count]} issues updated" }
end
end
end
protected
 
def issue
Loading
Loading
@@ -237,17 +224,4 @@ class Projects::IssuesController < Projects::ApplicationController
:milestone_id, :due_date, :state_event, :task_num, :lock_version, label_ids: []
)
end
def bulk_update_params
params.require(:update).permit(
:issues_ids,
:assignee_id,
:milestone_id,
:state_event,
:subscription_event,
label_ids: [],
add_label_ids: [],
remove_label_ids: []
)
end
end
module Issuable
class BulkUpdateService < IssuableBaseService
def execute(type)
model_class = type.classify.constantize
update_class = type.classify.pluralize.constantize::UpdateService
ids = params.delete(:issuable_ids).split(",")
items = model_class.where(id: ids)
%i(state_event milestone_id assignee_id add_label_ids remove_label_ids subscription_event).each do |key|
params.delete(key) unless params[key].present?
end
items.each do |issuable|
next unless can?(current_user, :"update_#{type}", issuable)
update_class.new(issuable.project, current_user, params).execute(issuable)
end
{
count: items.count,
success: !items.count.zero?
}
end
end
end
module Issues
class BulkUpdateService < BaseService
def execute
issues_ids = params.delete(:issues_ids).split(",")
issue_params = params
%i(state_event milestone_id assignee_id add_label_ids remove_label_ids subscription_event).each do |key|
issue_params.delete(key) unless issue_params[key].present?
end
issues = Issue.where(id: issues_ids)
issues.each do |issue|
next unless can?(current_user, :update_issue, issue)
Issues::UpdateService.new(issue.project, current_user, issue_params).execute(issue)
end
{
count: issues.count,
success: !issues.count.zero?
}
end
end
end
%li{ id: dom_id(issue), class: issue_css_classes(issue), url: issue_path(issue), data: { labels: issue.label_ids, id: issue.id } }
- if controller.controller_name == 'issues' && can?(current_user, :admin_issue, @project)
- if @bulk_edit
.issue-check
= check_box_tag dom_id(issue,"selected"), nil, false, 'data-id' => issue.id, class: "selected_issue"
= check_box_tag dom_id(issue, "selected"), nil, false, 'data-id' => issue.id, class: "selected_issue"
 
.issue-title.title
%span.issue-title-text
Loading
Loading
- @no_container = true
- @bulk_edit = can?(current_user, :admin_issue, @project)
- page_title "Issues"
- new_issue_email = @project.new_issue_address(current_user)
= render "projects/issues/head"
Loading
Loading
@@ -29,7 +31,7 @@
New Issue
= render 'shared/issuable/filter', type: :issues
 
.issues-holder
.issues-holder.issuable-list
= render 'issues'
- if new_issue_email
= render 'issue_by_email', email: new_issue_email
Loading
Loading
%li{ class: mr_css_classes(merge_request) }
- if @bulk_edit
.issue-check
= check_box_tag dom_id(merge_request, "selected"), nil, false, 'data-id' => merge_request.id, class: "selected_issue"
.merge-request-title.title
%span.merge-request-title-text
= link_to merge_request.title, merge_request_path(merge_request)
Loading
Loading
%ul.content-list.mr-list
%ul.content-list.mr-list.issuable-list
= render @merge_requests
- if @merge_requests.blank?
%li
Loading
Loading
- @no_container = true
- @bulk_edit = can?(current_user, :admin_merge_request, @project)
- page_title "Merge Requests"
= render "projects/issues/head"
= render 'projects/last_push'
Loading
Loading
- boards_page = controller.controller_name == 'boards'
.issues-filters
.issues-details-filters.row-content-block.second-block
= form_tag page_filter_path(without: [:assignee_id, :author_id, :milestone_title, :label_name, :issue_search]), method: :get, class: 'filter-form js-filter-form' do
- if params[:issue_search].present?
= hidden_field_tag :issue_search, params[:issue_search]
- if controller.controller_name == 'issues' && can?(current_user, :admin_issue, @project)
- if @bulk_edit
.check-all-holder
= check_box_tag "check_all_issues", nil, false,
class: "check_all_issues left"
Loading
Loading
@@ -30,7 +32,7 @@
%a{href: page_filter_path(without: [:assignee_id, :author_id, :milestone_title, :label_name, :issue_search])} Reset filters
 
.pull-right
- if controller.controller_name == 'boards'
- if boards_page
#js-boards-seach.issue-boards-search
%input.pull-left.form-control{ type: "search", placeholder: "Filter by name...", "v-model" => "filters.search", "debounce" => "250" }
- if can?(current_user, :admin_list, @project)
Loading
Loading
@@ -45,7 +47,7 @@
- else
= render 'shared/sort_dropdown'
 
- if controller.controller_name == 'issues'
- if @bulk_edit
.issues_bulk_update.hide
= form_tag bulk_update_namespace_project_issues_path(@project.namespace, @project), method: :post, class: 'bulk-update' do
.filter-item.inline
Loading
Loading
@@ -70,10 +72,10 @@
%li
%a{href: "#", data: {id: "unsubscribe"}} Unsubscribe
 
= hidden_field_tag 'update[issues_ids]', []
= hidden_field_tag 'update[issuable_ids]', []
= hidden_field_tag :state_event, params[:state_event]
.filter-item.inline
= button_tag "Update issues", class: "btn update_selected_issues btn-save"
= button_tag "Update #{type.to_s.humanize(capitalize: false)}", class: "btn update_selected_issues btn-save"
 
- if !@labels.nil?
.row-content-block.second-block.filtered-labels{ class: ("hidden" if !@labels.any?) }
Loading
Loading
require 'spec_helper'
 
describe Issues::BulkUpdateService, services: true do
describe Issuable::BulkUpdateService, services: true do
let(:user) { create(:user) }
let(:project) { create(:empty_project, namespace: user.namespace) }
 
def bulk_update(issues, extra_params = {})
bulk_update_params = extra_params
.reverse_merge(issues_ids: Array(issues).map(&:id).join(','))
.reverse_merge(issuable_ids: Array(issues).map(&:id).join(','))
 
Issues::BulkUpdateService.new(project, user, bulk_update_params).execute
Issuable::BulkUpdateService.new(project, user, bulk_update_params).execute('issue')
end
 
describe 'close issues' do
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment