Improved bulk action and overview.

This commit is contained in:
Martin Edenhofer 2012-11-03 17:45:57 +01:00
parent fcb5ae524b
commit 9cc2bfd71e
9 changed files with 237 additions and 183 deletions

View file

@ -136,7 +136,7 @@ class App.Controller extends Spine.Controller
frontendTime: (timestamp) -> frontendTime: (timestamp) ->
'<span class="humanTimeFromNow" data-time="' + timestamp + '">?</span>' '<span class="humanTimeFromNow" data-time="' + timestamp + '">?</span>'
frontendTimeUpdate: -> frontendTimeUpdate: =>
update = => update = =>
ui = @ ui = @
$('.humanTimeFromNow').each( -> $('.humanTimeFromNow').each( ->

View file

@ -46,7 +46,7 @@ class Index extends App.Controller
# get meta data # get meta data
@overview = data.overview @overview = data.overview
App.Overview.refresh( @overview, options: { clear: true } ) App.Overview.refresh( @overview, { clear: true } )
App.Overview.unbind('local:rerender') App.Overview.unbind('local:rerender')
App.Overview.bind 'local:rerender', (record) => App.Overview.bind 'local:rerender', (record) =>
@ -86,6 +86,8 @@ class Index extends App.Controller
render: -> render: ->
@selected = @bulkGetSelected()
# set page title # set page title
@title @overview.meta.name @title @overview.meta.name
@ -99,23 +101,23 @@ class Index extends App.Controller
edit = false edit = false
view_modes = [ view_modes = [
{ {
name: 'S', name: 'S'
type: 's', type: 's'
class: 'active' if @view_mode is 's', class: 'active' if @view_mode is 's'
}, },
{ {
name: 'M', name: 'M'
type: 'm', type: 'm'
class: 'active' if @view_mode is 'm', class: 'active' if @view_mode is 'm'
} }
] ]
html = App.view('agent_ticket_view')( html = App.view('agent_ticket_view')(
overview: @overview, overview: @overview
view_modes: view_modes, view_modes: view_modes
pages_total: pages_total, pages_total: pages_total
start_page: @start_page, start_page: @start_page
checkbox: true, checkbox: true
edit: edit, edit: edit
) )
html = $(html) html = $(html)
# html.find('li').removeClass('active') # html.find('li').removeClass('active')
@ -127,9 +129,9 @@ class Index extends App.Controller
table = '' table = ''
if @view_mode is 'm' if @view_mode is 'm'
table = App.view('agent_ticket_view/detail')( table = App.view('agent_ticket_view/detail')(
overview: @overview, overview: @overview
objects: @ticket_list_show, objects: @ticket_list_show
checkbox: checkbox, checkbox: checkbox
) )
table = $(table) table = $(table)
table.delegate('[name="bulk_all"]', 'click', (e) -> table.delegate('[name="bulk_all"]', 'click', (e) ->
@ -141,18 +143,30 @@ class Index extends App.Controller
@el.find('.table-overview').append(table) @el.find('.table-overview').append(table)
else else
shown_all_attributes = @ticketTableAttributes( App.Overview.find( @overview.id ).view.s.overview ) shown_all_attributes = @ticketTableAttributes( App.Overview.find( @overview.id ).view.s.overview )
groupBy = undefined
if @overview.group_by
group_by =
name: @overview.group_by
id: @overview.group_by + '_id'
# remove group by attribute from show attributes list
shown_all_attributes = _.filter(
shown_all_attributes
(item) =>
return item if item.name isnt @overview.group_by
return
)
new App.ControllerTable( new App.ControllerTable(
el: @el.find('.table-overview'), el: @el.find('.table-overview')
overview_extended: shown_all_attributes, overview_extended: shown_all_attributes
model: App.Ticket, model: App.Ticket
objects: @ticket_list_show, objects: @ticket_list_show
checkbox: checkbox, checkbox: checkbox
groupBy: groupBy: group_by
display: 'roup'
data: 'group',
data_id: 'group_id',
) )
@bulkSetSelected( @selected )
# start user popups # start user popups
@userPopups() @userPopups()
@ -161,6 +175,8 @@ class Index extends App.Controller
# start bulk action observ # start bulk action observ
@el.find('.bulk-action').append( @bulk_form() ) @el.find('.bulk-action').append( @bulk_form() )
if @el.find('.table-overview').find('[name="bulk"]:checked').length isnt 0
@el.find('.bulk-action').removeClass('hide')
# show/hide bulk action # show/hide bulk action
@el.find('.table-overview').delegate('[name="bulk"], [name="bulk_all"]', 'click', (e) => @el.find('.table-overview').delegate('[name="bulk"], [name="bulk_all"]', 'click', (e) =>
@ -214,6 +230,22 @@ class Index extends App.Controller
) )
return html return html
bulkGetSelected: ->
@ticketIDs = []
@el.find('.table-overview').find('[name="bulk"]:checked').each( (index, element) =>
ticket_id = $(element).val()
@ticketIDs.push ticket_id
)
@ticketIDs
bulkSetSelected: (ticketIDs) ->
@el.find('.table-overview').find('[name="bulk"]').each( (index, element) =>
ticket_id = $(element).val()
for ticket_id_selected in ticketIDs
if ticket_id_selected is ticket_id
$(element).attr( 'checked', true )
)
bulk_submit: (e) => bulk_submit: (e) =>
@bulk_count = @el.find('.table-overview').find('[name="bulk"]:checked').length @bulk_count = @el.find('.table-overview').find('[name="bulk"]:checked').length
@bulk_count_index = 0 @bulk_count_index = 0
@ -282,81 +314,92 @@ class Settings extends App.ControllerModal
# { name: 'ticket_article_type_id', display: 'Type', tag: 'select', multiple: false, null: true, relation: 'TicketArticleType', default: '9', class: 'medium', item_class: 'keepleft' }, # { name: 'ticket_article_type_id', display: 'Type', tag: 'select', multiple: false, null: true, relation: 'TicketArticleType', default: '9', class: 'medium', item_class: 'keepleft' },
# { name: 'internal', display: 'Visability', tag: 'radio', default: false, null: true, options: { true: 'internal', false: 'public' }, class: 'medium', item_class: 'keepleft' }, # { name: 'internal', display: 'Visability', tag: 'radio', default: false, null: true, options: { true: 'internal', false: 'public' }, class: 'medium', item_class: 'keepleft' },
{ {
name: 'per_page', name: 'per_page'
display: 'Items per page', display: 'Items per page'
tag: 'select', tag: 'select'
multiple: false, multiple: false
null: false, null: false
default: @overview.view[@view_mode].per_page, default: @overview.view[@view_mode].per_page
options: { options:
15: 15, 15: 15
20: 20, 20: 20
25: 25, 25: 25
30: 30, 30: 30
35: 35, 35: 35
}, class: 'medium'
class: 'medium', # item_class: 'keepleft'
# item_class: 'keepleft',
}, },
{ {
name: 'attributes', name: 'attributes'
display: 'Attributes', display: 'Attributes'
tag: 'checkbox', tag: 'checkbox'
default: @overview.view[@view_mode].overview, default: @overview.view[@view_mode].overview
null: false, null: false
options: { options:
# true: 'internal', # true: 'internal'
# false: 'public', # false: 'public'
number: 'Number', number: 'Number'
title: 'Title', title: 'Title'
customer: 'Customer', customer: 'Customer'
ticket_state: 'State', ticket_state: 'State'
ticket_priority: 'Priority', ticket_priority: 'Priority'
group: 'Group', group: 'Group'
owner: 'Owner', owner: 'Owner'
created_at: 'Alter', created_at: 'Alter'
last_contact: 'Last Contact', last_contact: 'Last Contact'
last_contact_agent: 'Last Contact Agent', last_contact_agent: 'Last Contact Agent'
last_contact_customer: 'Last Contact Customer', last_contact_customer: 'Last Contact Customer'
first_response: 'First Response', first_response: 'First Response'
close_time: 'Close Time', close_time: 'Close Time'
}, class: 'medium'
class: 'medium',
}, },
{ {
name: 'order_by', name: 'order_by'
display: 'Order', display: 'Order'
tag: 'select', tag: 'select'
default: @overview.order.by, default: @overview.order.by
null: false, null: false
options: { options:
number: 'Number', number: 'Number'
title: 'Title', title: 'Title'
customer: 'Customer', customer: 'Customer'
ticket_state: 'State', ticket_state: 'State'
ticket_priority: 'Priority', ticket_priority: 'Priority'
group: 'Group', group: 'Group'
owner: 'Owner', owner: 'Owner'
created_at: 'Alter', created_at: 'Alter'
last_contact: 'Last Contact', last_contact: 'Last Contact'
last_contact_agent: 'Last Contact Agent', last_contact_agent: 'Last Contact Agent'
last_contact_customer: 'Last Contact Customer', last_contact_customer: 'Last Contact Customer'
first_response: 'First Response', first_response: 'First Response'
close_time: 'Close Time', close_time: 'Close Time'
}, class: 'medium'
class: 'medium',
}, },
{ {
name: 'order_by_direction', name: 'order_by_direction'
display: 'Direction', display: 'Direction'
tag: 'select', tag: 'select'
default: @overview.order.direction, default: @overview.order.direction
null: false, null: false
options: { options:
ASC: 'up', ASC: 'up'
DESC: 'down', DESC: 'down'
}, class: 'medium'
class: 'medium', },
{
name: 'group_by'
display: 'Group by'
tag: 'select'
default: @overview.group_by
null: true
nulloption: true
options:
customer: 'Customer'
ticket_state: 'State'
ticket_priority: 'Priority'
group: 'Group'
owner: 'Owner'
class: 'medium'
}, },
# { # {
# name: 'condition', # name: 'condition',
@ -372,9 +415,9 @@ class Settings extends App.ControllerModal
] ]
new App.ControllerForm( new App.ControllerForm(
el: @el.find('#form-setting'), el: @el.find('#form-setting')
model: { configure_attributes: @configure_attributes_article }, model: { configure_attributes: @configure_attributes_article }
autofocus: false, autofocus: false
) )
@modalShow() @modalShow()
@ -397,6 +440,10 @@ class Settings extends App.ControllerModal
@overview.order['direction'] = params['order_by_direction'] @overview.order['direction'] = params['order_by_direction']
@reload_needed = 1 @reload_needed = 1
if @overview['group_by'] isnt params['group_by']
@overview['group_by'] = params['group_by']
@reload_needed = 1
@overview.view[@view_mode]['overview'] = params['attributes'] @overview.view[@view_mode]['overview'] = params['attributes']
@overview.save( @overview.save(
@ -423,14 +470,13 @@ class Router extends App.Controller
@redirect() @redirect()
else else
App.Com.ajax( App.Com.ajax(
type: 'GET', type: 'GET'
url: '/api/ticket_overviews', url: '/api/ticket_overviews'
data: { data:
view: @view, view: @view
array: true, array: true
} processData: true
processData: true, success: @load
success: @load
) )
load: (data) => load: (data) =>

View file

@ -2,14 +2,14 @@ $ = jQuery.sub()
class Index extends App.Controller class Index extends App.Controller
events: events:
'click .submit': 'update', 'click .submit': 'update'
'click [data-type=reply]': 'reply', 'click [data-type=reply]': 'reply'
# 'click [data-type=reply-all]': 'replyall', # 'click [data-type=reply-all]': 'replyall'
'click [data-type=public]': 'public_internal', 'click [data-type=public]': 'public_internal'
'click [data-type=internal]': 'public_internal', 'click [data-type=internal]': 'public_internal'
'change [name="ticket_article_type_id"]': 'form_update', 'change [name="ticket_article_type_id"]': 'form_update'
'click .show_toogle': 'show_toogle', 'click .show_toogle': 'show_toogle'
'blur .title_update': 'title_update', 'blur .title_update': 'title_update'
constructor: (params) -> constructor: (params) ->
super super
@ -20,10 +20,10 @@ class Index extends App.Controller
@navupdate '#' @navupdate '#'
@edit_form = undefined @edit_form = undefined
@ticket_id = params.ticket_id @ticket_id = params.ticket_id
@article_id = params.article_id @article_id = params.article_id
@signature = undefined @signature = undefined
@signature_used = undefined @signature_used = undefined
@key = 'ticket::' + @ticket_id @key = 'ticket::' + @ticket_id
@ -36,13 +36,12 @@ class Index extends App.Controller
# get data # get data
App.Com.ajax( App.Com.ajax(
id: 'ticket_zoom', id: 'ticket_zoom'
type: 'GET', type: 'GET'
url: '/api/ticket_full/' + ticket_id, url: '/api/ticket_full/' + ticket_id
data: { data:
view: @view view: @view
} processData: true
processData: true,
success: (data, status, xhr) => success: (data, status, xhr) =>
@load(data) @load(data)
App.Store.write( @key, data ) App.Store.write( @key, data )
@ -119,30 +118,25 @@ class Index extends App.Controller
] ]
@html App.view('agent_ticket_zoom')( @html App.view('agent_ticket_zoom')(
ticket: @ticket, ticket: @ticket
articles: @articles, articles: @articles
nav: @nav, nav: @nav
) )
new App.ControllerForm( new App.ControllerForm(
el: @el.find('#form-ticket-update'), el: @el.find('#form-ticket-update')
model: { model:
configure_attributes: @configure_attributes_ticket, configure_attributes: @configure_attributes_ticket
className: 'create', className: 'create'
}, params: @ticket
params: @ticket form_data: @edit_form
form_data: @edit_form,
) )
new App.ControllerForm( new App.ControllerForm(
el: @el.find('#form-article-update'), el: @el.find('#form-article-update')
model: { model:
configure_attributes: @configure_attributes_article, configure_attributes: @configure_attributes_article
}, form_data: @edit_form
# params: {
# body: @signature.body,
# }
form_data: @edit_form,
) )
@el.find('textarea').elastic() @el.find('textarea').elastic()
@ -168,13 +162,12 @@ class Index extends App.Controller
u: => u: =>
uploader = new qq.FileUploader( uploader = new qq.FileUploader(
element: document.getElementById('file-uploader'), element: document.getElementById('file-uploader')
action: '/api/ticket_attachment_new', action: '/api/ticket_attachment_new'
params: { params:
form: 'TicketZoom', form: 'TicketZoom'
form_id: @ticket.id, form_id: @ticket.id
}, debug: false
debug: false
) )
ticket_action_row: => ticket_action_row: =>
@ -182,34 +175,33 @@ class Index extends App.Controller
# start customer info controller # start customer info controller
if !@isRole('Customer') if !@isRole('Customer')
new App.UserInfo( new App.UserInfo(
el: @el.find('#customer_info'), el: @el.find('#customer_info')
user_id: @ticket.customer_id, user_id: @ticket.customer_id
ticket: @ticket, ticket: @ticket
) )
# start action controller # start action controller
if !@isRole('Customer') if !@isRole('Customer')
new TicketActionRow( new TicketActionRow(
el: @el.find('#action_info'), el: @el.find('#action_info')
ticket: @ticket, ticket: @ticket
zoom: @, zoom: @
) )
# start link info controller # start link info controller
if !@isRole('Customer') if !@isRole('Customer')
new App.LinkInfo( new App.LinkInfo(
el: @el.find('#link_info'), el: @el.find('#link_info')
object_type: 'Ticket', object_type: 'Ticket'
object: @ticket, object: @ticket
) )
# show text module UI # show text module UI
if !@isRole('Customer') if !@isRole('Customer')
new App.TextModuleUI( new App.TextModuleUI(
el: @el.find('#text_module'), el: @el.find('#text_module')
data: { data:
ticket: @ticket, ticket: @ticket
},
) )
show_toogle: (e) -> show_toogle: (e) ->
@ -484,15 +476,15 @@ class Article extends App.Controller
if @article.internal is true if @article.internal is true
actions = [ actions = [
{ {
name: 'set to public', name: 'set to public'
type: 'public', type: 'public'
} }
] ]
else else
actions = [ actions = [
{ {
name: 'set to internal', name: 'set to internal'
type: 'internal', type: 'internal'
} }
] ]
if @article.article_type.name is 'note' if @article.article_type.name is 'note'
@ -500,19 +492,19 @@ class Article extends App.Controller
else else
if @article.article_sender.name is 'Customer' if @article.article_sender.name is 'Customer'
actions.push { actions.push {
name: 'reply', name: 'reply'
type: 'reply', type: 'reply'
href: '#', href: '#'
} }
# actions.push { # actions.push {
# name: 'reply all', # name: 'reply all'
# type: 'reply-all', # type: 'reply-all'
# href: '#', # href: '#'
# } # }
actions.push { actions.push {
name: 'split', name: 'split'
type: 'split', type: 'split'
href: '#ticket_create/' + @article.ticket_id + '/' + @article.id, href: '#ticket_create/' + @article.ticket_id + '/' + @article.id
} }
@article.actions = actions @article.actions = actions
@ -523,9 +515,9 @@ class Article extends App.Controller
class TicketActionRow extends App.Controller class TicketActionRow extends App.Controller
events: events:
'click [data-type=history]': 'history_dialog', 'click [data-type=history]': 'history_dialog'
'click [data-type=merge]': 'merge_dialog', 'click [data-type=merge]': 'merge_dialog'
'click [data-type=customer]': 'customer_dialog', 'click [data-type=customer]': 'customer_dialog'
constructor: -> constructor: ->
super super

View file

@ -1,4 +1,4 @@
class App.Overview extends Spine.Model class App.Overview extends Spine.Model
@configure 'Overview', 'name', 'meta', 'condition', 'order', 'view', 'user_id', 'group_ids' @configure 'Overview', 'name', 'meta', 'condition', 'order', 'group_by', 'view', 'user_id', 'group_ids'
@extend Spine.Model.Ajax @extend Spine.Model.Ajax
@url: '/api/overviews' @url: '/api/overviews'

View file

@ -20,9 +20,9 @@
<% groupLast = '' %> <% groupLast = '' %>
<% for object in @objects: %> <% for object in @objects: %>
<% if @groupBy: %> <% if @groupBy: %>
<% if groupLast isnt object[@groupBy.data_id]: %> <% if groupLast isnt object[@groupBy.id]: %>
<tr class=""><td colspan="<%= @overview.length + 1 %>"><b><%- @P( object[@groupBy.data] ) %></b></td></tr> <tr class=""><td colspan="<%= @overview.length + 1 %>"><b><%- @P( object[@groupBy.name] ) %></b></td></tr>
<% groupLast = object[@groupBy.data_id] %> <% groupLast = object[@groupBy.id] %>
<% end %> <% end %>
<% end %> <% end %>
<% position++ %> <% position++ %>

View file

@ -13,6 +13,7 @@ Example:
"meta":{"m_a":1,"m_b":2}, "meta":{"m_a":1,"m_b":2},
"condition":{"c_a":1,"c_b":2}, "condition":{"c_a":1,"c_b":2},
"order":{"o_a":1,"o_b":2}, "order":{"o_a":1,"o_b":2},
"group_by":"group",
"view":{"v_a":1,"v_b":2}, "view":{"v_a":1,"v_b":2},
"user_id": null, "user_id": null,
"role_id": null, "role_id": null,
@ -84,6 +85,7 @@ Payload:
"meta":{"m_a":1,"m_b":2}, "meta":{"m_a":1,"m_b":2},
"condition":{"c_a":1,"c_b":2}, "condition":{"c_a":1,"c_b":2},
"order":{"o_a":1,"o_b":2}, "order":{"o_a":1,"o_b":2},
"group_by":"group",
"view":{"v_a":1,"v_b":2}, "view":{"v_a":1,"v_b":2},
"user_id": null, "user_id": null,
"role_id": null, "role_id": null,
@ -116,6 +118,7 @@ Payload:
"meta":{"m_a":1,"m_b":2}, "meta":{"m_a":1,"m_b":2},
"condition":{"c_a":1,"c_b":2}, "condition":{"c_a":1,"c_b":2},
"order":{"o_a":1,"o_b":2}, "order":{"o_a":1,"o_b":2},
"group_by":"group",
"view":{"v_a":1,"v_b":2}, "view":{"v_a":1,"v_b":2},
"user_id": null, "user_id": null,
"role_id": null, "role_id": null,

View file

@ -259,10 +259,14 @@ class Ticket < ApplicationModel
# get result list # get result list
if data[:array] if data[:array]
order_by = overview_selected[:order][:by].to_s + ' ' + overview_selected[:order][:direction].to_s
if overview_selected.group_by && !overview_selected.group_by.empty?
order_by = overview_selected.group_by + '_id, ' + order_by
end
tickets = Ticket.select( 'id' ). tickets = Ticket.select( 'id' ).
where( :group_id => group_ids ). where( :group_id => group_ids ).
where( overview_selected.condition ). where( overview_selected.condition ).
order( 'group_id, ' + overview_selected[:order][:by].to_s + ' ' + overview_selected[:order][:direction].to_s ). order( order_by ).
limit( 500 ) limit( 500 )
ticket_ids = [] ticket_ids = []

View file

@ -152,6 +152,7 @@ class CreateTicket < ActiveRecord::Migration
t.column :meta, :string, :limit => 1000, :null => false t.column :meta, :string, :limit => 1000, :null => false
t.column :condition, :string, :limit => 2500, :null => false t.column :condition, :string, :limit => 2500, :null => false
t.column :order, :string, :limit => 2500, :null => false t.column :order, :string, :limit => 2500, :null => false
t.column :group_by, :string, :limit => 250, :null => true
t.column :view, :string, :limit => 1000, :null => false t.column :view, :string, :limit => 1000, :null => false
t.column :updated_by_id, :integer, :null => false t.column :updated_by_id, :integer, :null => false
t.column :created_by_id, :integer, :null => false t.column :created_by_id, :integer, :null => false

View file

@ -0,0 +1,8 @@
class OverviewUpdate2 < ActiveRecord::Migration
def up
add_column :overviews, :group_by, :string, :limit => 250, :null => true
end
def down
end
end