See merge request zammad/zammad!8
This commit is contained in:
commit
10007e6409
3 changed files with 185 additions and 39 deletions
|
@ -1,3 +1,47 @@
|
|||
ValidUsersForTicketSelectionMethods =
|
||||
validUsersForTicketSelection: ->
|
||||
items = $('.content.active .table-overview .table').find('[name="bulk"]:checked')
|
||||
|
||||
# we want to display all users for which we can assign the tickets directly
|
||||
# for this we need to get the groups of all selected tickets
|
||||
# after we got those we need to check which users are available in all groups
|
||||
# users that are not in all groups can't get the tickets assigned
|
||||
ticket_ids = _.map(items, (el) -> $(el).val() )
|
||||
ticket_group_ids = _.map(App.Ticket.findAll(ticket_ids), (ticket) -> ticket.group_id)
|
||||
users = @usersInGroups(ticket_group_ids)
|
||||
|
||||
# get the list of possible groups for the current user
|
||||
# from the TicketCreateCollection
|
||||
# (filled for e.g. the TicketCreation or TicketZoom assignment)
|
||||
# and order them by name
|
||||
group_ids = _.keys(@formMeta?.dependencies?.group_id)
|
||||
groups = App.Group.findAll(group_ids)
|
||||
groups_sorted = _.sortBy(groups, (group) -> group.name)
|
||||
|
||||
# get the number of visible users per group
|
||||
# from the TicketCreateCollection
|
||||
# (filled for e.g. the TicketCreation or TicketZoom assignment)
|
||||
for group in groups
|
||||
group.valid_users_count = @formMeta?.dependencies?.group_id?[group.id]?.owner_id.length || 0
|
||||
|
||||
{
|
||||
users: users
|
||||
groups: groups_sorted
|
||||
}
|
||||
|
||||
usersInGroups: (group_ids) ->
|
||||
ids_by_group = _.chain(@formMeta?.dependencies?.group_id)
|
||||
.pick(group_ids)
|
||||
.values()
|
||||
.map( (e) -> e.owner_id)
|
||||
.value()
|
||||
|
||||
# Underscore's intersection doesn't work when chained
|
||||
ids_in_all_groups = _.intersection(ids_by_group...)
|
||||
|
||||
users = App.User.findAll(ids_in_all_groups)
|
||||
_.sortBy(users, (user) -> user.firstname)
|
||||
|
||||
class App.TicketOverview extends App.Controller
|
||||
className: 'overviews'
|
||||
activeFocus: 'nav'
|
||||
|
@ -25,6 +69,8 @@ class App.TicketOverview extends App.Controller
|
|||
'mouseenter .js-batch-hover-target': 'highlightBatchEntry'
|
||||
'mouseleave .js-batch-hover-target': 'unhighlightBatchEntry'
|
||||
|
||||
@include ValidUsersForTicketSelectionMethods
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
@batchSupport = @permissionCheck('ticket.agent')
|
||||
|
@ -540,19 +586,6 @@ class App.TicketOverview extends App.Controller
|
|||
.velocity({ opacity: [0.5, 1] }, { duration: 120 })
|
||||
.velocity({ opacity: [1, 0.5] }, { duration: 60, delay: 40 })
|
||||
|
||||
usersInGroups: (group_ids) ->
|
||||
ids_by_group = _.chain(@formMeta?.dependencies?.group_id)
|
||||
.pick(group_ids)
|
||||
.values()
|
||||
.map( (e) -> e.owner_id)
|
||||
.value()
|
||||
|
||||
# Underscore's intersection doesn't work when chained
|
||||
ids_in_all_groups = _.intersection(ids_by_group...)
|
||||
|
||||
users = App.User.findAll(ids_in_all_groups)
|
||||
_.sortBy(users, (user) -> user.firstname)
|
||||
|
||||
render: ->
|
||||
elLocal = $(App.view('ticket_overview/index')())
|
||||
|
||||
|
@ -604,33 +637,8 @@ class App.TicketOverview extends App.Controller
|
|||
@renderOptionsMacros()
|
||||
|
||||
renderOptionsGroups: =>
|
||||
items = @el.find('[name="bulk"]:checked')
|
||||
|
||||
# we want to display all users for which we can assign the tickets directly
|
||||
# for this we need to get the groups of all selected tickets
|
||||
# after we got those we need to check which users are available in all groups
|
||||
# users that are not in all groups can't get the tickets assigned
|
||||
ticket_ids = _.map(items, (el) -> $(el).val() )
|
||||
ticket_group_ids = _.map(App.Ticket.findAll(ticket_ids), (ticket) -> ticket.group_id)
|
||||
users = @usersInGroups(ticket_group_ids)
|
||||
|
||||
# get the list of possible groups for the current user
|
||||
# from the TicketCreateCollection
|
||||
# (filled for e.g. the TicketCreation or TicketZoom assignment)
|
||||
# and order them by name
|
||||
group_ids = _.keys(@formMeta?.dependencies?.group_id)
|
||||
groups = App.Group.findAll(group_ids)
|
||||
groups_sorted = _.sortBy(groups, (group) -> group.name)
|
||||
|
||||
# get the number of visible users per group
|
||||
# from the TicketCreateCollection
|
||||
# (filled for e.g. the TicketCreation or TicketZoom assignment)
|
||||
for group in groups
|
||||
group.valid_users_count = @formMeta?.dependencies?.group_id?[group.id]?.owner_id.length || 0
|
||||
|
||||
@batchAssignInner.html $(App.view('ticket_overview/batch_overlay_user_group')(
|
||||
users: users
|
||||
groups: groups_sorted
|
||||
@validUsersForTicketSelection()
|
||||
))
|
||||
|
||||
renderOptionsMacros: =>
|
||||
|
@ -1089,6 +1097,7 @@ class Table extends App.Controller
|
|||
if @$('table').find('input[name="bulk"]:checked').length == 0
|
||||
@bulkForm.hide()
|
||||
else
|
||||
@bulkForm.render()
|
||||
@bulkForm.show()
|
||||
|
||||
if @lastChecked && e.shiftKey
|
||||
|
@ -1233,6 +1242,8 @@ class BulkForm extends App.Controller
|
|||
'click .js-confirm': 'confirm'
|
||||
'click .js-cancel': 'reset'
|
||||
|
||||
@include ValidUsersForTicketSelectionMethods
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
|
@ -1266,6 +1277,12 @@ class BulkForm extends App.Controller
|
|||
|
||||
handlers = @Config.get('TicketZoomFormHandler')
|
||||
|
||||
for attribute in @configure_attributes_ticket
|
||||
continue if attribute.name != 'owner_id'
|
||||
{users, groups} = @validUsersForTicketSelection()
|
||||
options = _.map(users, (user) -> {value: user.id, name: user.displayName()} )
|
||||
attribute.possible_groups_owners = options
|
||||
|
||||
new App.ControllerForm(
|
||||
el: @$('#form-ticket-bulk')
|
||||
model:
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
class OwnerFormHandlerDependencies
|
||||
|
||||
# central method, is getting called on every ticket form change
|
||||
@run: (params, attribute, attributes, classname, form, ui) ->
|
||||
return if 'group_id' not of params
|
||||
return if 'owner_id' not of params
|
||||
|
||||
owner_attribute = _.find(attributes, (o) -> o.name == 'owner_id')
|
||||
return if !owner_attribute
|
||||
return if 'possible_groups_owners' not of owner_attribute
|
||||
|
||||
# fetch contents using User relation if a Group has been selected, otherwise render possible_groups_owners
|
||||
if params.group_id
|
||||
owner_attribute.relation = 'User'
|
||||
delete owner_attribute['options']
|
||||
else
|
||||
owner_attribute.options = owner_attribute.possible_groups_owners
|
||||
delete owner_attribute['relation']
|
||||
|
||||
# replace new option list
|
||||
owner_attribute.default = params[owner_attribute.name]
|
||||
owner_attribute.newValue = params[owner_attribute.name]
|
||||
newElement = ui.formGenItem(owner_attribute, classname, form)
|
||||
form.find('select[name="owner_id"]').closest('.form-group').replaceWith(newElement)
|
||||
|
||||
App.Config.set('150-ticketFormChanges', OwnerFormHandlerDependencies, 'TicketZoomFormHandler')
|
|
@ -365,4 +365,107 @@ class AgentTicketOverviewLevel0Test < TestCase
|
|||
# cleanup
|
||||
tasks_close_all()
|
||||
end
|
||||
|
||||
# verify correct behaviour for issue #1864 - Bulk-Action: Not possible to change owner
|
||||
def test_bulk_owner_change
|
||||
@browser = browser_instance
|
||||
login(
|
||||
username: 'master@example.com',
|
||||
password: 'test',
|
||||
url: browser_url,
|
||||
)
|
||||
tasks_close_all()
|
||||
|
||||
# test bulk action
|
||||
|
||||
# create new ticket
|
||||
ticket1 = ticket_create(
|
||||
data: {
|
||||
customer: 'nico',
|
||||
group: 'Users',
|
||||
title: 'overview owner change test #1',
|
||||
body: 'overview owner change #1',
|
||||
}
|
||||
)
|
||||
ticket2 = ticket_create(
|
||||
data: {
|
||||
customer: 'nico',
|
||||
group: 'Users',
|
||||
title: 'overview owner change #2',
|
||||
body: 'overview owner change #2',
|
||||
}
|
||||
)
|
||||
|
||||
overview_open(
|
||||
link: '#ticket/view/all_unassigned',
|
||||
)
|
||||
|
||||
watch_for(
|
||||
css: '.content.active',
|
||||
value: 'overview owner change #2',
|
||||
timeout: 8,
|
||||
)
|
||||
|
||||
# remember current overview count
|
||||
overview_counter_before = overview_counter()
|
||||
|
||||
# select both via bulk action
|
||||
click(
|
||||
css: '.content.active table tr td input[value="' + ticket1[:id] + '"] + .icon-checkbox.icon-unchecked',
|
||||
fast: true,
|
||||
)
|
||||
|
||||
# scroll to reply - needed for chrome
|
||||
scroll_to(
|
||||
position: 'top',
|
||||
css: '.content.active table tr td input[value="' + ticket2[:id] + '"] + .icon-checkbox.icon-unchecked',
|
||||
)
|
||||
click(
|
||||
css: '.content.active table tr td input[value="' + ticket2[:id] + '"] + .icon-checkbox.icon-unchecked',
|
||||
fast: true,
|
||||
)
|
||||
|
||||
exists(
|
||||
css: '.content.active table tr td input[value="' + ticket1[:id] + '"][type="checkbox"]:checked',
|
||||
)
|
||||
exists(
|
||||
css: '.content.active table tr td input[value="' + ticket2[:id] + '"][type="checkbox"]:checked',
|
||||
)
|
||||
|
||||
select(
|
||||
css: '.content.active .bulkAction [name="owner_id"]',
|
||||
value: 'Test Master Agent',
|
||||
)
|
||||
|
||||
select(
|
||||
css: '.content.active .bulkAction [name="state_id"]',
|
||||
value: 'closed',
|
||||
)
|
||||
|
||||
click(
|
||||
css: '.content.active .bulkAction .js-confirm',
|
||||
)
|
||||
click(
|
||||
css: '.content.active .bulkAction .js-submit',
|
||||
)
|
||||
|
||||
watch_for_disappear(
|
||||
css: '.content.active table tr td input[value="' + ticket2[:id] + '"]',
|
||||
timeout: 12,
|
||||
)
|
||||
|
||||
exists_not(
|
||||
css: '.content.active table tr td input[value="' + ticket1[:id] + '"]',
|
||||
)
|
||||
exists_not(
|
||||
css: '.content.active table tr td input[value="' + ticket2[:id] + '"]',
|
||||
)
|
||||
|
||||
# get new overview count
|
||||
overview_counter_new = overview_counter()
|
||||
assert_equal(overview_counter_before['#ticket/view/all_unassigned'] - 2, overview_counter_new['#ticket/view/all_unassigned'])
|
||||
|
||||
# cleanup
|
||||
tasks_close_all()
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue