Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Jérome Perrin
gitlab-ce
Commits
f28ca293
Commit
f28ca293
authored
Sep 06, 2016
by
Dmitriy Zaporozhets
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add bulk update support for merge requests list
Signed-off-by:
Dmitriy Zaporozhets
<
dmitriy.zaporozhets@gmail.com
>
parent
43d6328f
Changes
16
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
98 additions
and
81 deletions
+98
-81
app/assets/javascripts/dispatcher.js
app/assets/javascripts/dispatcher.js
+1
-4
app/assets/javascripts/issuable.js.es6
app/assets/javascripts/issuable.js.es6
+1
-1
app/assets/javascripts/issues-bulk-assignment.js
app/assets/javascripts/issues-bulk-assignment.js
+2
-2
app/assets/stylesheets/pages/issuable.scss
app/assets/stylesheets/pages/issuable.scss
+15
-0
app/assets/stylesheets/pages/issues.scss
app/assets/stylesheets/pages/issues.scss
+0
-11
app/controllers/concerns/issuable_actions.rb
app/controllers/concerns/issuable_actions.rb
+31
-0
app/controllers/projects/issues_controller.rb
app/controllers/projects/issues_controller.rb
+0
-26
app/services/issuable/bulk_update_service.rb
app/services/issuable/bulk_update_service.rb
+26
-0
app/services/issues/bulk_update_service.rb
app/services/issues/bulk_update_service.rb
+0
-25
app/views/projects/issues/_issue.html.haml
app/views/projects/issues/_issue.html.haml
+2
-2
app/views/projects/issues/index.html.haml
app/views/projects/issues/index.html.haml
+3
-1
app/views/projects/merge_requests/_merge_request.html.haml
app/views/projects/merge_requests/_merge_request.html.haml
+4
-0
app/views/projects/merge_requests/_merge_requests.html.haml
app/views/projects/merge_requests/_merge_requests.html.haml
+1
-1
app/views/projects/merge_requests/index.html.haml
app/views/projects/merge_requests/index.html.haml
+2
-0
app/views/shared/issuable/_filter.html.haml
app/views/shared/issuable/_filter.html.haml
+7
-5
spec/services/issuable/bulk_update_service_spec.rb
spec/services/issuable/bulk_update_service_spec.rb
+3
-3
No files found.
app/assets/javascripts/dispatcher.js
View file @
f28ca293
...
@@ -23,6 +23,7 @@
...
@@ -23,6 +23,7 @@
case
'
projects:boards:show
'
:
case
'
projects:boards:show
'
:
shortcut_handler
=
new
ShortcutsNavigation
();
shortcut_handler
=
new
ShortcutsNavigation
();
break
;
break
;
case
'
projects:merge_requests:index
'
:
case
'
projects:issues:index
'
:
case
'
projects:issues:index
'
:
Issuable
.
init
();
Issuable
.
init
();
new
IssuableBulkActions
();
new
IssuableBulkActions
();
...
@@ -93,10 +94,6 @@
...
@@ -93,10 +94,6 @@
break
;
break
;
case
"
projects:merge_requests:conflicts
"
:
case
"
projects:merge_requests:conflicts
"
:
window
.
mcui
=
new
MergeConflictResolver
()
window
.
mcui
=
new
MergeConflictResolver
()
case
'
projects:merge_requests:index
'
:
shortcut_handler
=
new
ShortcutsNavigation
();
Issuable
.
init
();
break
;
case
'
dashboard:activity
'
:
case
'
dashboard:activity
'
:
new
Activities
();
new
Activities
();
break
;
break
;
...
...
app/assets/javascripts/issuable.js.es6
View file @
f28ca293
...
@@ -77,7 +77,7 @@
...
@@ -77,7 +77,7 @@
},
},
checkChanged: function() {
checkChanged: function() {
const $checkedIssues = $('.selected_issue:checked');
const $checkedIssues = $('.selected_issue:checked');
const $updateIssuesIds = $('#update_issu
es
_ids');
const $updateIssuesIds = $('#update_issu
able
_ids');
const $issuesOtherFilters = $('.issues-other-filters');
const $issuesOtherFilters = $('.issues-other-filters');
const $issuesBulkUpdate = $('.issues_bulk_update');
const $issuesBulkUpdate = $('.issues_bulk_update');
...
...
app/assets/javascripts/issues-bulk-assignment.js
View file @
f28ca293
...
@@ -5,7 +5,7 @@
...
@@ -5,7 +5,7 @@
if
(
opts
==
null
)
{
if
(
opts
==
null
)
{
opts
=
{};
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
(
'
.issu
es-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
(
'
.issu
able-list > li
'
);
this
.
form
.
data
(
'
bulkActions
'
,
this
);
this
.
form
.
data
(
'
bulkActions
'
,
this
);
this
.
willUpdateLabels
=
false
;
this
.
willUpdateLabels
=
false
;
this
.
bindEvents
();
this
.
bindEvents
();
...
@@ -106,7 +106,7 @@
...
@@ -106,7 +106,7 @@
state_event
:
this
.
form
.
find
(
'
input[name="update[state_event]"]
'
).
val
(),
state_event
:
this
.
form
.
find
(
'
input[name="update[state_event]"]
'
).
val
(),
assignee_id
:
this
.
form
.
find
(
'
input[name="update[assignee_id]"]
'
).
val
(),
assignee_id
:
this
.
form
.
find
(
'
input[name="update[assignee_id]"]
'
).
val
(),
milestone_id
:
this
.
form
.
find
(
'
input[name="update[milestone_id]"]
'
).
val
(),
milestone_id
:
this
.
form
.
find
(
'
input[name="update[milestone_id]"]
'
).
val
(),
issu
es_ids
:
this
.
form
.
find
(
'
input[name="update[issues
_ids]"]
'
).
val
(),
issu
able_ids
:
this
.
form
.
find
(
'
input[name="update[issuable
_ids]"]
'
).
val
(),
subscription_event
:
this
.
form
.
find
(
'
input[name="update[subscription_event]"]
'
).
val
(),
subscription_event
:
this
.
form
.
find
(
'
input[name="update[subscription_event]"]
'
).
val
(),
add_label_ids
:
[],
add_label_ids
:
[],
remove_label_ids
:
[]
remove_label_ids
:
[]
...
...
app/assets/stylesheets/pages/issuable.scss
View file @
f28ca293
...
@@ -404,3 +404,18 @@
...
@@ -404,3 +404,18 @@
margin-bottom
:
$gl-padding
;
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
;
}
}
}
}
app/assets/stylesheets/pages/issues.scss
View file @
f28ca293
...
@@ -7,17 +7,6 @@
...
@@ -7,17 +7,6 @@
margin-bottom
:
2px
;
margin-bottom
:
2px
;
}
}
.issue-check
{
float
:
left
;
padding-right
:
16px
;
margin-bottom
:
10px
;
min-width
:
15px
;
.selected_issue
{
vertical-align
:
text-top
;
}
}
.issue-labels
{
.issue-labels
{
display
:
inline-block
;
display
:
inline-block
;
}
}
...
...
app/controllers/concerns/issuable_actions.rb
View file @
f28ca293
...
@@ -3,6 +3,7 @@ module IssuableActions
...
@@ -3,6 +3,7 @@ module IssuableActions
included
do
included
do
before_action
:authorize_destroy_issuable!
,
only: :destroy
before_action
:authorize_destroy_issuable!
,
only: :destroy
before_action
:authorize_admin_issuable!
,
only: :bulk_update
end
end
def
destroy
def
destroy
...
@@ -13,6 +14,13 @@ module IssuableActions
...
@@ -13,6 +14,13 @@ module IssuableActions
redirect_to
polymorphic_path
([
@project
.
namespace
.
becomes
(
Namespace
),
@project
,
issuable
.
class
])
redirect_to
polymorphic_path
([
@project
.
namespace
.
becomes
(
Namespace
),
@project
,
issuable
.
class
])
end
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
private
def
authorize_destroy_issuable!
def
authorize_destroy_issuable!
...
@@ -20,4 +28,27 @@ module IssuableActions
...
@@ -20,4 +28,27 @@ module IssuableActions
return
access_denied!
return
access_denied!
end
end
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
end
app/controllers/projects/issues_controller.rb
View file @
f28ca293
...
@@ -20,9 +20,6 @@ class Projects::IssuesController < Projects::ApplicationController
...
@@ -20,9 +20,6 @@ class Projects::IssuesController < Projects::ApplicationController
# Allow modify issue
# Allow modify issue
before_action
:authorize_update_issue!
,
only:
[
:edit
,
:update
]
before_action
:authorize_update_issue!
,
only:
[
:edit
,
:update
]
# Allow issues bulk update
before_action
:authorize_admin_issues!
,
only:
[
:bulk_update
]
respond_to
:html
respond_to
:html
def
index
def
index
...
@@ -168,16 +165,6 @@ class Projects::IssuesController < Projects::ApplicationController
...
@@ -168,16 +165,6 @@ class Projects::IssuesController < Projects::ApplicationController
end
end
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
protected
def
issue
def
issue
...
@@ -237,17 +224,4 @@ class Projects::IssuesController < Projects::ApplicationController
...
@@ -237,17 +224,4 @@ class Projects::IssuesController < Projects::ApplicationController
:milestone_id
,
:due_date
,
:state_event
,
:task_num
,
:lock_version
,
label_ids:
[]
:milestone_id
,
:due_date
,
:state_event
,
:task_num
,
:lock_version
,
label_ids:
[]
)
)
end
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
end
app/services/issuable/bulk_update_service.rb
0 → 100644
View file @
f28ca293
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
app/services/issues/bulk_update_service.rb
deleted
100644 → 0
View file @
43d6328f
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
app/views/projects/issues/_issue.html.haml
View file @
f28ca293
%li
{
id:
dom_id
(
issue
),
class:
issue_css_classes
(
issue
),
url:
issue_path
(
issue
),
data:
{
labels:
issue
.
label_ids
,
id:
issue
.
id
}
}
%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
.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
.issue-title.title
%span
.issue-title-text
%span
.issue-title-text
...
...
app/views/projects/issues/index.html.haml
View file @
f28ca293
-
@no_container
=
true
-
@no_container
=
true
-
@bulk_edit
=
can?
(
current_user
,
:admin_issue
,
@project
)
-
page_title
"Issues"
-
page_title
"Issues"
-
new_issue_email
=
@project
.
new_issue_address
(
current_user
)
-
new_issue_email
=
@project
.
new_issue_address
(
current_user
)
=
render
"projects/issues/head"
=
render
"projects/issues/head"
...
@@ -29,7 +31,7 @@
...
@@ -29,7 +31,7 @@
New Issue
New Issue
=
render
'shared/issuable/filter'
,
type: :issues
=
render
'shared/issuable/filter'
,
type: :issues
.issues-holder
.issues-holder
.issuable-list
=
render
'issues'
=
render
'issues'
-
if
new_issue_email
-
if
new_issue_email
=
render
'issue_by_email'
,
email:
new_issue_email
=
render
'issue_by_email'
,
email:
new_issue_email
...
...
app/views/projects/merge_requests/_merge_request.html.haml
View file @
f28ca293
%li
{
class:
mr_css_classes
(
merge_request
)
}
%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
.merge-request-title.title
%span
.merge-request-title-text
%span
.merge-request-title-text
=
link_to
merge_request
.
title
,
merge_request_path
(
merge_request
)
=
link_to
merge_request
.
title
,
merge_request_path
(
merge_request
)
...
...
app/views/projects/merge_requests/_merge_requests.html.haml
View file @
f28ca293
%ul
.content-list.mr-list
%ul
.content-list.mr-list
.issuable-list
=
render
@merge_requests
=
render
@merge_requests
-
if
@merge_requests
.
blank?
-
if
@merge_requests
.
blank?
%li
%li
...
...
app/views/projects/merge_requests/index.html.haml
View file @
f28ca293
-
@no_container
=
true
-
@no_container
=
true
-
@bulk_edit
=
can?
(
current_user
,
:admin_merge_request
,
@project
)
-
page_title
"Merge Requests"
-
page_title
"Merge Requests"
=
render
"projects/issues/head"
=
render
"projects/issues/head"
=
render
'projects/last_push'
=
render
'projects/last_push'
...
...
app/views/shared/issuable/_filter.html.haml
View file @
f28ca293
-
boards_page
=
controller
.
controller_name
==
'boards'
.issues-filters
.issues-filters
.issues-details-filters.row-content-block.second-block
.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
=
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?
-
if
params
[
:issue_search
].
present?
=
hidden_field_tag
:issue_search
,
params
[
:issue_search
]
=
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-all-holder
=
check_box_tag
"check_all_issues"
,
nil
,
false
,
=
check_box_tag
"check_all_issues"
,
nil
,
false
,
class:
"check_all_issues left"
class:
"check_all_issues left"
...
@@ -30,7 +32,7 @@
...
@@ -30,7 +32,7 @@
%a
{
href:
page_filter_path
(
without:
[
:assignee_id
,
:author_id
,
:milestone_title
,
:label_name
,
:issue_search
])}
Reset filters
%a
{
href:
page_filter_path
(
without:
[
:assignee_id
,
:author_id
,
:milestone_title
,
:label_name
,
:issue_search
])}
Reset filters
.pull-right
.pull-right
-
if
controller
.
controller_name
==
'boards'
-
if
boards_page
#js-boards-seach
.issue-boards-search
#js-boards-seach
.issue-boards-search
%input
.pull-left.form-control
{
type:
"search"
,
placeholder:
"Filter by name..."
,
"v-model"
=>
"filters.search"
,
"debounce"
=>
"250"
}
%input
.pull-left.form-control
{
type:
"search"
,
placeholder:
"Filter by name..."
,
"v-model"
=>
"filters.search"
,
"debounce"
=>
"250"
}
-
if
can?
(
current_user
,
:admin_list
,
@project
)
-
if
can?
(
current_user
,
:admin_list
,
@project
)
...
@@ -45,7 +47,7 @@
...
@@ -45,7 +47,7 @@
-
else
-
else
=
render
'shared/sort_dropdown'
=
render
'shared/sort_dropdown'
-
if
controller
.
controller_name
==
'issues'
-
if
@bulk_edit
.issues_bulk_update.hide
.issues_bulk_update.hide
=
form_tag
bulk_update_namespace_project_issues_path
(
@project
.
namespace
,
@project
),
method: :post
,
class:
'bulk-update'
do
=
form_tag
bulk_update_namespace_project_issues_path
(
@project
.
namespace
,
@project
),
method: :post
,
class:
'bulk-update'
do
.filter-item.inline
.filter-item.inline
...
@@ -70,10 +72,10 @@
...
@@ -70,10 +72,10 @@
%li
%li
%a
{
href:
"#"
,
data:
{
id:
"unsubscribe"
}}
Unsubscribe
%a
{
href:
"#"
,
data:
{
id:
"unsubscribe"
}}
Unsubscribe
=
hidden_field_tag
'update[issu
es
_ids]'
,
[]
=
hidden_field_tag
'update[issu
able
_ids]'
,
[]
=
hidden_field_tag
:state_event
,
params
[
:state_event
]
=
hidden_field_tag
:state_event
,
params
[
:state_event
]
.filter-item.inline
.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?
-
if
!
@labels
.
nil?
.row-content-block.second-block.filtered-labels
{
class:
(
"hidden"
if
!
@labels
.
any?
)
}
.row-content-block.second-block.filtered-labels
{
class:
(
"hidden"
if
!
@labels
.
any?
)
}
...
...
spec/services/issu
es
/bulk_update_service_spec.rb
→
spec/services/issu
able
/bulk_update_service_spec.rb
View file @
f28ca293
require
'spec_helper'
require
'spec_helper'
describe
Issu
es
::
BulkUpdateService
,
services:
true
do
describe
Issu
able
::
BulkUpdateService
,
services:
true
do
let
(
:user
)
{
create
(
:user
)
}
let
(
:user
)
{
create
(
:user
)
}
let
(
:project
)
{
create
(
:empty_project
,
namespace:
user
.
namespace
)
}
let
(
:project
)
{
create
(
:empty_project
,
namespace:
user
.
namespace
)
}
def
bulk_update
(
issues
,
extra_params
=
{})
def
bulk_update
(
issues
,
extra_params
=
{})
bulk_update_params
=
extra_params
bulk_update_params
=
extra_params
.
reverse_merge
(
issu
es
_ids:
Array
(
issues
).
map
(
&
:id
).
join
(
','
))
.
reverse_merge
(
issu
able
_ids:
Array
(
issues
).
map
(
&
:id
).
join
(
','
))
Issu
es
::
BulkUpdateService
.
new
(
project
,
user
,
bulk_update_params
).
execute
Issu
able
::
BulkUpdateService
.
new
(
project
,
user
,
bulk_update_params
).
execute
(
'issue'
)
end
end
describe
'close issues'
do
describe
'close issues'
do
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment