Improved modal and added generic actions.

This commit is contained in:
Martin Edenhofer 2014-09-21 21:58:07 +02:00
parent 5b3cae547c
commit 3ed77d985e
20 changed files with 297 additions and 222 deletions

View file

@ -456,7 +456,6 @@ class App.ControllerModal extends App.Controller
@show() @show()
show: -> show: ->
console.log('M', @message, @el.length)
if @button is true if @button is true
@button = 'Submit' @button = 'Submit'

View file

@ -359,41 +359,21 @@ class App.GenericHistory extends App.ControllerModal
@head = 'History' @head = 'History'
@close = true @close = true
render: ( items, orderClass = '' ) -> render: ->
for item in items localItem = @reworkItems( @items )
item.link = ''
item.title = '???'
if item.object is 'Ticket::Article'
item.object = 'Article'
article = App.TicketArticle.find( item.o_id )
ticket = App.Ticket.find( article.ticket_id )
item.title = article.subject || ticket.title
item.link = article.uiUrl()
if App[item.object]
object = App[item.object].find( item.o_id )
item.link = object.uiUrl()
item.title = object.displayName()
item.created_by = App.User.find( item.created_by_id )
# set cache
@historyListCache = items
@html App.view('generic/history')( @html App.view('generic/history')(
items: items items: localItem
orderClass: orderClass
@historyListCache
) )
@onShow()
@el.find('a[data-type="sortorder"]').bind( @el.find('a[data-type="sortorder"]').bind(
'click', 'click',
(e) => (e) =>
e.preventDefault() e.preventDefault()
@sortorder(e) @sortorder()
) )
if !@isShown if !@isShown
@isShown = true @isShown = true
@ -404,16 +384,95 @@ class App.GenericHistory extends App.ControllerModal
@userPopups() @userPopups()
# show frontend times # show frontend times
@delay( @frontendTimeUpdate, 100, 'ui-time-update' ) @delay( @frontendTimeUpdate, 800, 'ui-time-update' )
sortorder: (e) -> sortorder: =>
e.preventDefault() @items = @items.reverse()
isDown = @el.find('[data-type="sortorder"]').hasClass('down')
if isDown @render()
@render( @historyListCache, 'up' )
else T: (name) ->
@render( @historyListCache.reverse(), 'down' ) App.i18n.translateInline(name)
reworkItems: (items) ->
newItems = []
newItem = {}
lastUserId = undefined
lastTime = undefined
items = clone(items)
for item in items
if item.object is 'Ticket::Article'
item.object = 'Article'
data = item
data.created_by = App.User.find( item.created_by_id )
currentItemTime = new Date( item.created_at )
lastItemTime = new Date( new Date( lastTime ).getTime() + (15 * 1000) )
# start new section if user or time has changed
if lastUserId isnt item.created_by_id || currentItemTime > lastItemTime
lastTime = item.created_at
lastUserId = item.created_by_id
if !_.isEmpty(newItem)
newItems.push newItem
newItem =
created_at: item.created_at
created_by: App.User.find( item.created_by_id )
records: []
# build content
content = ''
if item.type is 'notification' || item.type is 'email'
content = "#{ @T( item.type ) } #{ @T( 'sent to' ) } #{ item.value_to }"
else
content = "#{ @T( item.type ) } #{ @T(item.object) } "
if item.attribute
content += "#{ @T(item.attribute) }"
# convert time stamps
if item.object is 'User' && item.attribute is 'last_login'
if item.value_from
item.value_from = App.i18n.translateTimestamp( item.value_from )
if item.value_to
item.value_to = App.i18n.translateTimestamp( item.value_to )
if item.value_from
if item.value_to
content += " #{ @T( 'from' ) }"
content += " '#{ item.value_from }'"
if item.value_to
if item.value_from
content += " #{ @T( 'to' ) }"
content += " '#{ item.value_to }'"
newItem.records.push content
if !_.isEmpty(newItem)
newItems.push newItem
newItems
class App.ActionRow extends App.Controller
constructor: ->
super
@render()
render: ->
@html App.view('generic/actions')(
items: @items
)
for item in @items
do (item) =>
@el.find('[data-type="' + item.name + '"]').on(
'click',
(e) =>
e.preventDefault()
item.callback()
)
class App.Sidebar extends App.Controller class App.Sidebar extends App.Controller
events: events:

View file

@ -1,15 +1,18 @@
class App.TicketMerge extends App.ControllerModal class App.TicketMerge extends App.ControllerModal
constructor: -> constructor: ->
super super
@head = 'Merge'
@button = true
@cancel = true
@fetch() @fetch()
fetch: -> fetch: ->
# merge tickets # merge tickets
@ajax( @ajax(
id: 'ticket_merge_list' id: 'ticket_related'
type: 'GET' type: 'GET'
url: @apiPath + '/ticket_merge_list/' + @ticket.id url: @apiPath + '/ticket_related/' + @ticket.id
processData: true, processData: true,
success: (data, status, xhr) => success: (data, status, xhr) =>
@ -18,7 +21,6 @@ class App.TicketMerge extends App.ControllerModal
@ticket_ids_by_customer = data.ticket_ids_by_customer @ticket_ids_by_customer = data.ticket_ids_by_customer
@ticket_ids_recent_viewed = data.ticket_ids_recent_viewed @ticket_ids_recent_viewed = data.ticket_ids_recent_viewed
@render() @render()
) )

View file

@ -15,6 +15,8 @@ class App.OrganizationHistory extends App.GenericHistory
# load assets # load assets
App.Collection.loadAssets( data.assets ) App.Collection.loadAssets( data.assets )
@items = data.history
# render page # render page
@render(data.history) @render()
) )

View file

@ -64,10 +64,19 @@ class App.OrganizationZoom extends App.Controller
) )
# start action controller # start action controller
new ActionRow( showHistory = =>
el: @el.find('.action') new App.OrganizationHistory( organization_id: organization.id )
organization: organization
ui: @ actions = [
{
name: 'history'
title: 'History'
callback: showHistory
}
]
new App.ActionRow(
el: @el.find('.action')
items: actions
) )
new Sidebar( new Sidebar(
@ -168,21 +177,6 @@ class Sidebar extends App.Controller
items: items items: items
) )
class ActionRow extends App.Controller
events:
'click [data-type=history]': 'history_dialog'
constructor: ->
super
@render()
render: ->
@html App.view('user_zoom/actions')()
history_dialog: (e) ->
e.preventDefault()
new App.OrganizationHistory( organization_id: @organization.id )
class Router extends App.ControllerPermanent class Router extends App.ControllerPermanent
constructor: (params) -> constructor: (params) ->
super super

View file

@ -9,12 +9,14 @@ class App.TicketHistory extends App.GenericHistory
@ajax( @ajax(
id: 'ticket_history', id: 'ticket_history',
type: 'GET', type: 'GET',
url: @apiPath + '/ticket_history/' + @ticket.id, url: @apiPath + '/ticket_history/' + @ticket_id,
success: (data, status, xhr) => success: (data, status, xhr) =>
# load assets # load assets
App.Collection.loadAssets( data.assets ) App.Collection.loadAssets( data.assets )
@items = data.history
# render page # render page
@render(data.history) @render()
) )

View file

@ -162,6 +162,28 @@ class App.TicketZoom extends App.Controller
object_type: 'Ticket' object_type: 'Ticket'
object: @ticket object: @ticket
) )
el.append('<div class="action"></div>')
showHistory = =>
new App.TicketHistory( ticket_id: @ticket.id )
showMerge = =>
new App.TicketMerge( ticket: @ticket, task_key: @task_key )
actions = [
{
name: 'history'
title: 'History'
callback: showHistory
},
{
name: 'merge'
title: 'Merge'
callback: showMerge
},
]
new App.ActionRow(
el: @el.find('.action')
items: actions
)
items = [ items = [
{ {
head: 'Ticket Settings' head: 'Ticket Settings'
@ -275,7 +297,6 @@ class App.TicketZoom extends App.Controller
) )
### ###
@TicketAction()
@ArticleView() @ArticleView()
if force || !@editDone if force || !@editDone
@ -323,18 +344,6 @@ class App.TicketZoom extends App.Controller
ui: @ ui: @
) )
TicketAction: =>
# start action controller
if !@isRole('Customer')
new ActionRow(
el: @el.find('.action')
ticket: @ticket
ui: @
)
# enable user popups
@userPopups()
class TicketTitle extends App.Controller class TicketTitle extends App.Controller
events: events:
'blur .ticket-title-update': 'update' 'blur .ticket-title-update': 'update'
@ -1212,26 +1221,6 @@ class Article extends App.Controller
for attachment in @article.attachments for attachment in @article.attachments
attachment.size = @humanFileSize(attachment.size) attachment.size = @humanFileSize(attachment.size)
class ActionRow extends App.Controller
events:
'click [data-type=history]': 'history_dialog'
'click [data-type=merge]': 'merge_dialog'
constructor: ->
super
@render()
render: ->
@html App.view('ticket_zoom/actions')()
history_dialog: (e) ->
e.preventDefault()
new App.TicketHistory( ticket: @ticket )
merge_dialog: (e) ->
e.preventDefault()
new App.TicketMerge( ticket: @ticket, task_key: @ui.task_key )
class TicketZoomRouter extends App.ControllerPermanent class TicketZoomRouter extends App.ControllerPermanent
constructor: (params) -> constructor: (params) ->
super super

View file

@ -15,6 +15,8 @@ class App.UserHistory extends App.GenericHistory
# load assets # load assets
App.Collection.loadAssets( data.assets ) App.Collection.loadAssets( data.assets )
@items = data.history
# render page # render page
@render(data.history) @render()
) )

View file

@ -63,10 +63,19 @@ class App.UserZoom extends App.Controller
) )
# start action controller # start action controller
new ActionRow( showHistory = =>
el: @el.find('.action') new App.UserHistory( user_id: user.id )
user: user
ui: @ actions = [
{
name: 'history'
title: 'History'
callback: showHistory
}
]
new App.ActionRow(
el: @el.find('.action')
items: actions
) )
new Sidebar( new Sidebar(
@ -218,22 +227,6 @@ class Sidebar extends App.Controller
items: items items: items
) )
class ActionRow extends App.Controller
events:
'click [data-type=history]': 'history_dialog'
constructor: ->
super
@render()
render: ->
@html App.view('user_zoom/actions')()
history_dialog: (e) ->
e.preventDefault()
new App.UserHistory( user_id: @user.id )
class Router extends App.ControllerPermanent class Router extends App.ControllerPermanent
constructor: (params) -> constructor: (params) ->
super super

View file

@ -74,10 +74,10 @@ class App.WidgetLink extends App.Controller
add: (e) => add: (e) =>
e.preventDefault() e.preventDefault()
new App.LinkAdd( new App.LinkAdd(
link_object: @object_type, link_object: @object_type
link_object_id: @object.id, link_object_id: @object.id
object: @object, object: @object
parent: @, parent: @
) )
class App.LinkAdd extends App.ControllerModal class App.LinkAdd extends App.ControllerModal
@ -87,17 +87,86 @@ class App.LinkAdd extends App.ControllerModal
@button = true @button = true
@cancel = true @cancel = true
@ticket = @object
@fetch()
fetch: ->
# merge tickets
@ajax(
id: 'ticket_related'
type: 'GET'
url: @apiPath + '/ticket_related/' + @ticket.id
processData: true,
success: (data, status, xhr) =>
# load assets
App.Collection.loadAssets( data.assets )
@ticket_ids_by_customer = data.ticket_ids_by_customer
@ticket_ids_recent_viewed = data.ticket_ids_recent_viewed
@render()
)
render: ->
@html App.view('link/add')( @html App.view('link/add')(
link_object: @link_object, link_object: @link_object,
link_object_id: @link_object_id, link_object_id: @link_object_id,
object: @object, object: @object,
) )
list = []
for ticket_id in @ticket_ids_by_customer
if ticket_id isnt @ticket.id
ticketItem = App.Ticket.fullLocal( ticket_id )
list.push ticketItem
new App.ControllerTable(
el: @el.find('#ticket-merge-customer-tickets'),
overview: [ 'number', 'title', 'state', 'group', 'created_at' ]
model: App.Ticket,
objects: list,
radio: true,
)
list = []
for ticket_id in @ticket_ids_recent_viewed
if ticket_id isnt @ticket.id
ticketItem = App.Ticket.fullLocal( ticket_id )
list.push ticketItem
new App.ControllerTable(
el: @el.find('#ticket-merge-recent-tickets'),
overview: [ 'number', 'title', 'state', 'group', 'created_at' ]
model: App.Ticket,
objects: list,
radio: true,
)
@el.delegate('[name="ticket_number"]', 'focus', (e) ->
$(e.target).parents().find('[name="radio"]').prop( 'checked', false )
)
@el.delegate('[name="radio"]', 'click', (e) ->
if $(e.target).prop('checked')
ticket_id = $(e.target).val()
ticket = App.Ticket.fullLocal( ticket_id )
$(e.target).parents().find('[name="ticket_number"]').val( ticket.number )
)
@show() @show()
onSubmit: (e) => onSubmit: (e) =>
e.preventDefault() e.preventDefault()
params = @formParam(e.target) params = @formParam(e.target)
if !params['ticket_number']
alert('Ticket# is needed!')
return
if !params['link_type']
alert('Link type is needed!')
return
# get data # get data
@ajax( @ajax(
id: 'links_add_' + @object.id + '_' + @object_type, id: 'links_add_' + @object.id + '_' + @object_type,

View file

@ -1,26 +1,10 @@
<form class="form-horizontal"> <div>
<div class="modal-dialog"> <h4><%- @T( 'Merge to Ticket#' ) %></h4>
<div class="modal-content"> <input type="text" name="master_ticket_number" class="form-control" value=""/>
<div class="modal-header"> <hr>
<div class="modal-close js-close"> <h4><%- @T( 'Recent Customer Tickets' ) %></h4>
<div class="close icon"></div> <div id="ticket-merge-customer-tickets"></div>
</div> <hr>
<h1 class="modal-title"><%- @T( 'Merge' ) %></h1> <h4><%- @T( 'Recent viewed Tickets' ) %></h4>
</div> <div id="ticket-merge-recent-tickets"></div>
<div class="modal-body"> </div>
<h4><%- @T( 'Merge to Ticket#' ) %></h4>
<input type="text" name="master_ticket_number" class="form-control" value=""/>
<hr>
<h4><%- @T( 'Recent Customer Tickets' ) %></h4>
<div id="ticket-merge-customer-tickets"></div>
<hr>
<h4><%- @T( 'Recent Views Tickets' ) %></h4>
<div id="ticket-merge-recent-tickets"></div>
</div>
<div class="modal-footer horizontal">
<a class="subtle-link standalone js-cancel" href="#/"><%- @T( 'Cancel & Go Back' ) %></a>
<button type="submit" class="btn btn--create js-submit align-right"><%- @T( 'Submit' ) %></button>
</div>
</div>
</div>
</form>

View file

@ -1,6 +1,8 @@
<div class="dropdown dropup actions"> <div class="dropdown dropup actions">
<button class="btn" data-toggle="dropdown"><%- @T('Action') %> <span class="caret"></span></button> <button class="btn" data-toggle="dropdown"><%- @T('Action') %> <span class="caret"></span></button>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a href="#" data-type="history"><%- @T( 'History' ) %></a></li> <% for item in @items: %>
<li><a href="#" data-type="<%= item.name %>"><%- @T( item.title ) %></a></li>
<% end %>
</ul> </ul>
</div> </div>

View file

@ -1,49 +1,17 @@
<div> <div>
<a href="#" data-type="sortorder" class="<%= @orderClass %>"><%- @T( 'Change order' ) %></a> <a href="#" data-type="sortorder"><%- @T( 'Change order' ) %></a>
<hr> <hr>
<% open = false %>
<% for item in @items: %> <% for item in @items: %>
<% if lasttime isnt item['created_at'] || last_user isnt item['created_by_id']: %> <span class="user-popover" data-id="<%= item.created_by.id %>"><%= item.created_by.displayName() %></span> -
<% if open: %> <span class="humanTimeFromNow" data-time="<%- item.created_at %>">?</span>
</ul> <ul>
<hr> <% for content in item.records: %>
<li><%- content %></li>
<% end %> <% end %>
<% open = true %>
<% last_user = item['created_by_id'] %>
<% lasttime = item['created_at'] %>
<span class="user-popover" data-id="<%= item.created_by.id %>"><%= item.created_by.displayName() %></span> -
<span class="humanTimeFromNow" data-time="<%- item.created_at %>">?</span>
<ul>
<% end %>
<li>
<% if ( item['type'] is 'notification' || item['type'] is 'email' ): %>
<%- @T( item['type'] ) %>
<% if item['value_from']: %>
"<%= item['value_from'] %>" <%- @T( 'sent to' ) %>
<% end %>
<% if item['value_to']: %>
"<%= item['value_to'] %>"
<% end %>
<% else: %>
<%- @T( item['type'] ) %> <%= item['object'] %> <% if item['attribute']: %>"<%= item['attribute'] %>"<% end %>
<% if item['value_from']: %>
<% if item['value_to']: %>
<%- @T( 'from' ) %>
<% end %>
"<%= item['value_from'] %>"
<% end %>
<% if item['value_to']: %>
<% if item['value_from']: %>
<%- @T( 'to' ) %>
<% end %>
"<%= item['value_to'] %>"
<% end %>
<% end %>
</li>
<% end %>
<% if open: %>
</ul> </ul>
<hr>
<% end %> <% end %>
</div> </div>

View file

@ -12,11 +12,11 @@
<%- @T( 'of' ) %> <%- @T( 'of' ) %>
Ticket# Ticket#
<%= @object.number %>. <%= @object.number %>.
<!--
<ul> <hr>
<li>Ticket#</li> <h4><%- @T( 'Recent Customer Tickets' ) %></h4>
<li>Recent Views Tickets</li> <div id="ticket-merge-customer-tickets"></div>
<li>Recent Customer Tickets</li> <hr>
</ul> <h4><%- @T( 'Recent viewed Tickets' ) %></h4>
--> <div id="ticket-merge-recent-tickets"></div>
</fieldset> </fieldset>

View file

@ -1,12 +1,18 @@
<div class="main flex tabsSidebarSpace"> <div class="flex vertical">
<div class="organizationZoom"> <div class="flex u-positionOrigin horizontal">
<div class="page-header"> <div class="main flex tabsSidebarSpace">
<h1><%- @T( @head ) %></h1> <div class="organizationZoom">
<div class="page-header">
<h1><%- @T( @head ) %></h1>
</div>
<div class="main-overviews" id="sortable"></div>
</div>
</div> </div>
<div class="main-overviews" id="sortable"></div> <div class="tabsSidebar vertical"></div>
</div> </div>
</div> <form class="bottom-form form-inline horizontal" role="form">
<div class="action"></div>
<div class="tabsSidebar vertical"></div> </form>
</div>

View file

@ -1,8 +0,0 @@
<div class="btn-group dropup">
<button type="button" class="btn btn-default dropdown-toggle actions" data-toggle="dropdown"><%- @T('Action') %> <span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><a href="#" data-type="history"><%- @T( 'History' ) %></a></li>
<li><a href="#" data-type="merge"><%- @T( 'Merge' ) %></a></li>
</ul>
</div>

View file

@ -7,7 +7,6 @@
</div> </div>
<div class="main-overviews" id="sortable"></div> <div class="main-overviews" id="sortable"></div>
</div> </div>
</div> </div>

View file

@ -137,17 +137,24 @@ class TicketsController < ApplicationController
render :json => history render :json => history
end end
# GET /api/v1/ticket_merge_list/1 # GET /api/v1/ticket_related/1
def ticket_merge_list def ticket_related
ticket = Ticket.find( params[:ticket_id] ) ticket = Ticket.find( params[:ticket_id] )
assets = ticket.assets({}) assets = ticket.assets({})
# open tickets by customer # open tickets by customer
group_ids = Group.select( 'groups.id' ).joins(:users).
where( 'groups_users.user_id = ?', current_user.id ).
where( 'groups.active = ?', true ).
map( &:id )
access_condition = [ 'group_id IN (?)', group_ids ]
ticket_list = Ticket.where( ticket_list = Ticket.where(
:customer_id => ticket.customer_id, :customer_id => ticket.customer_id,
:state_id => Ticket::State.by_category( 'open' ) :state_id => Ticket::State.by_category( 'open' )
) )
.where(access_condition)
.where( 'id != ?', [ ticket.id ] ) .where( 'id != ?', [ ticket.id ] )
.order('created_at DESC') .order('created_at DESC')
.limit(6) .limit(6)
@ -161,9 +168,9 @@ class TicketsController < ApplicationController
ticket_ids_recent_viewed = [] ticket_ids_recent_viewed = []
ticket_recent_view = RecentView.list( current_user, 8 ) ticket_recent_view = RecentView.list( current_user, 8, 'Ticket' )
ticket_recent_view.each {|item| ticket_recent_view.each {|item|
if item['recent_view_object'] == 'Ticket' if item['object'] == 'Ticket'
ticket_ids_recent_viewed.push item['o_id'] ticket_ids_recent_viewed.push item['o_id']
ticket = Ticket.find( item['o_id'] ) ticket = Ticket.find( item['o_id'] )
assets = ticket.assets(assets) assets = ticket.assets(assets)

View file

@ -32,10 +32,16 @@ class RecentView < ApplicationModel
RecentView.where( :created_by_id => user.id ).destroy_all RecentView.where( :created_by_id => user.id ).destroy_all
end end
def self.list( user, limit = 10 ) def self.list( user, limit = 10, type = nil )
recent_views = RecentView.where( :created_by_id => user.id ). if !type
order('created_at DESC, id DESC'). recent_views = RecentView.where( :created_by_id => user.id ).
limit(limit) order('created_at DESC, id DESC').
limit(limit)
else
recent_views = RecentView.select('DISTINCT(o_id), recent_view_object_id').where( :created_by_id => user.id, :recent_view_object_id => ObjectLookup.by_name(type) ) .
order('created_at DESC, id DESC').
limit(limit)
end
list = [] list = []
recent_views.each { |item| recent_views.each { |item|

View file

@ -11,7 +11,7 @@ Zammad::Application.routes.draw do
match api_path + '/ticket_full/:id', :to => 'tickets#ticket_full', :via => :get match api_path + '/ticket_full/:id', :to => 'tickets#ticket_full', :via => :get
match api_path + '/ticket_history/:id', :to => 'tickets#ticket_history', :via => :get match api_path + '/ticket_history/:id', :to => 'tickets#ticket_history', :via => :get
match api_path + '/ticket_customer', :to => 'tickets#ticket_customer', :via => :get match api_path + '/ticket_customer', :to => 'tickets#ticket_customer', :via => :get
match api_path + '/ticket_merge_list/:ticket_id', :to => 'tickets#ticket_merge_list', :via => :get match api_path + '/ticket_related/:ticket_id', :to => 'tickets#ticket_related', :via => :get
match api_path + '/ticket_merge/:slave_ticket_id/:master_ticket_number', :to => 'tickets#ticket_merge', :via => :get match api_path + '/ticket_merge/:slave_ticket_id/:master_ticket_number', :to => 'tickets#ticket_merge', :via => :get
# ticket overviews # ticket overviews