Moved to new table api.
This commit is contained in:
parent
7a0e95014c
commit
e417001822
19 changed files with 687 additions and 555 deletions
|
@ -169,20 +169,14 @@ class App.ControllerGenericIndex extends App.Controller
|
||||||
objects: objects
|
objects: objects
|
||||||
overview: overview
|
overview: overview
|
||||||
attributes: attributes
|
attributes: attributes
|
||||||
groupBy: 'state'
|
bindRow:
|
||||||
|
events:
|
||||||
|
'click': @edit
|
||||||
)
|
)
|
||||||
|
|
||||||
binds = {}
|
edit: (id, e) =>
|
||||||
for item in attributes
|
|
||||||
if item.dataType
|
|
||||||
if !binds[item.dataType]
|
|
||||||
callback = item.callback || @edit
|
|
||||||
@el.on( 'click', "[data-type=#{item.dataType}]", callback )
|
|
||||||
binds[item.dataType] = true
|
|
||||||
|
|
||||||
edit: (e) =>
|
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
item = $(e.target).item( App[ @genericObject ] )
|
item = App[ @genericObject ].find(id)
|
||||||
|
|
||||||
if @editCallback
|
if @editCallback
|
||||||
@editCallback(item)
|
@editCallback(item)
|
||||||
|
|
|
@ -4,48 +4,64 @@ class App.ControllerTable extends App.Controller
|
||||||
@[key] = value
|
@[key] = value
|
||||||
|
|
||||||
@table = @tableGen(params)
|
@table = @tableGen(params)
|
||||||
|
|
||||||
if @el
|
if @el
|
||||||
@el.append( @table )
|
@el.append( @table )
|
||||||
|
|
||||||
###
|
###
|
||||||
|
|
||||||
|
# table simple based on model
|
||||||
|
|
||||||
|
rowClick = -> (id, e)
|
||||||
|
e.preventDefault()
|
||||||
|
console.log('rowClick', id)
|
||||||
|
rowMouseover = -> (id, e)
|
||||||
|
e.preventDefault()
|
||||||
|
console.log('rowMouseover', id)
|
||||||
|
rowMouseout = -> (id, e)
|
||||||
|
e.preventDefault()
|
||||||
|
console.log('rowMouseout', id)
|
||||||
|
rowDblClick = -> (id, e)
|
||||||
|
e.preventDefault()
|
||||||
|
console.log('rowDblClick', id)
|
||||||
|
|
||||||
|
colClick = -> (id, e)
|
||||||
|
e.preventDefault()
|
||||||
|
console.log('colClick', e.target)
|
||||||
|
|
||||||
|
checkboxClick = -> (id, e)
|
||||||
|
e.preventDefault()
|
||||||
|
console.log('checkboxClick', e.target)
|
||||||
|
|
||||||
new App.ControllerTable(
|
new App.ControllerTable(
|
||||||
header: ['Host', 'User', 'Adapter', 'Active']
|
|
||||||
overview: ['host', 'user', 'adapter', 'active']
|
overview: ['host', 'user', 'adapter', 'active']
|
||||||
model: App.Channel
|
model: App.Channel
|
||||||
objects: data
|
objects: data
|
||||||
|
groupBy: 'group'
|
||||||
checkbox: false
|
checkbox: false
|
||||||
radio: false
|
radio: false
|
||||||
|
bindRow:
|
||||||
|
events:
|
||||||
|
'click': rowClick
|
||||||
|
'mouseover': rowMouseover
|
||||||
|
'mouseout': rowMouseout
|
||||||
|
'dblclick': rowDblClick
|
||||||
|
bindCol:
|
||||||
|
host:
|
||||||
|
events:
|
||||||
|
'click': colEvent
|
||||||
|
bindCheckbox:
|
||||||
|
events:
|
||||||
|
'click': rowClick
|
||||||
|
'mouseover': rowMouseover
|
||||||
|
'mouseout': rowMouseout
|
||||||
|
'dblclick': rowDblClick
|
||||||
)
|
)
|
||||||
|
|
||||||
new App.ControllerTable(
|
|
||||||
overview_extended: [
|
|
||||||
{ name: 'number', link: true }
|
|
||||||
{ name: 'title', link: true }
|
|
||||||
{ name: 'customer', class: 'user-popover', data: { id: true } }
|
|
||||||
{ name: 'state', translate: true }
|
|
||||||
{ name: 'priority', translate: true }
|
|
||||||
{ name: 'group' },
|
|
||||||
{ name: 'owner', class: 'user-popover', data: { id: true } }
|
|
||||||
{ name: 'created_at', callback: @frontendTime }
|
|
||||||
{ name: 'last_contact', callback: @frontendTime }
|
|
||||||
{ name: 'last_contact_agent', callback: @frontendTime }
|
|
||||||
{ name: 'last_contact_customer', callback: @frontendTime }
|
|
||||||
{ name: 'first_response', callback: @frontendTime }
|
|
||||||
{ name: 'close_time', callback: @frontendTime }
|
|
||||||
],
|
|
||||||
model: App.Ticket
|
|
||||||
objects: tickets
|
|
||||||
checkbox: false
|
|
||||||
radio: false
|
|
||||||
)
|
|
||||||
|
|
||||||
###
|
###
|
||||||
|
|
||||||
tableGen: (data) ->
|
tableGen: (data) ->
|
||||||
overview = data.overview || data.model.configure_overview || []
|
overview = data.overview || data.model.configure_overview || []
|
||||||
attributes = data.attributes || data.model.configure_attributes || {}
|
attributes = data.attributes || data.model.configure_attributes || {}
|
||||||
header = data.header
|
|
||||||
destroy = data.model.configure_delete
|
destroy = data.model.configure_delete
|
||||||
|
|
||||||
# check if table is empty
|
# check if table is empty
|
||||||
|
@ -53,108 +69,132 @@ class App.ControllerTable extends App.Controller
|
||||||
table = '<p>-' + App.i18n.translateContent( 'none' ) + '-</p>'
|
table = '<p>-' + App.i18n.translateContent( 'none' ) + '-</p>'
|
||||||
return $(table)
|
return $(table)
|
||||||
|
|
||||||
# define table header
|
# group by
|
||||||
if header
|
if data.groupBy
|
||||||
header_new = []
|
|
||||||
for key in header
|
|
||||||
header_new.push {
|
|
||||||
display: key
|
|
||||||
}
|
|
||||||
header = header_new
|
|
||||||
else if !data.overview_extended
|
|
||||||
header = []
|
|
||||||
for row in overview
|
|
||||||
found = false
|
|
||||||
if attributes
|
|
||||||
for attribute in attributes
|
|
||||||
if row is attribute.name
|
|
||||||
found = true
|
|
||||||
header.push attribute
|
|
||||||
else
|
|
||||||
rowWithoutId = row + '_id'
|
|
||||||
if rowWithoutId is attribute.name
|
|
||||||
found = true
|
|
||||||
header.push attribute
|
|
||||||
if !found
|
|
||||||
header.push {
|
|
||||||
name: row
|
|
||||||
display: row
|
|
||||||
}
|
|
||||||
|
|
||||||
# collect data of col. types
|
# remove group by attribute from header
|
||||||
dataTypesForCols = []
|
overview = _.filter(
|
||||||
for row in overview
|
overview
|
||||||
|
(item) =>
|
||||||
|
return item if item isnt data.groupBy
|
||||||
|
return
|
||||||
|
)
|
||||||
|
|
||||||
if !_.isEmpty(attributes)
|
# get new order
|
||||||
for attribute in attributes
|
groupObjects = _.groupBy(
|
||||||
found = false
|
data.objects
|
||||||
if row is attribute.name
|
(item) =>
|
||||||
found = true
|
return '' if !item[data.groupBy]
|
||||||
dataTypesAttribute = _.clone(attribute)
|
return item[data.groupBy].displayName() if item[data.groupBy].displayName
|
||||||
else if row + '_id' is attribute.name
|
item[data.groupBy]
|
||||||
found = true
|
)
|
||||||
dataTypesAttribute = _.clone(attribute)
|
groupOrder = []
|
||||||
dataTypesAttribute['name'] = row
|
for group, value of groupObjects
|
||||||
if found
|
groupOrder.push group
|
||||||
dataTypesAttribute['type'] = 'link'
|
|
||||||
if !dataTypesAttribute['dataType']
|
|
||||||
dataTypesAttribute['dataType'] = 'edit'
|
|
||||||
dataTypesForCols.push dataTypesAttribute
|
|
||||||
else
|
|
||||||
dataTypesForCols.push {
|
|
||||||
name: row
|
|
||||||
type: 'link'
|
|
||||||
dataType: 'edit'
|
|
||||||
}
|
|
||||||
|
|
||||||
# extended table format
|
# sort new groups
|
||||||
if data.overview_extended
|
groupOrder = _.sortBy(
|
||||||
if !header
|
groupOrder
|
||||||
header = []
|
(item) =>
|
||||||
for row in data.overview_extended
|
item
|
||||||
for attribute in attributes
|
)
|
||||||
if row.name is attribute.name
|
|
||||||
header.push attribute
|
|
||||||
else
|
|
||||||
rowWithoutId = row.name + '_id'
|
|
||||||
if rowWithoutId is attribute.name
|
|
||||||
header.push attribute
|
|
||||||
|
|
||||||
dataTypesForCols = data.overview_extended
|
# create new data array
|
||||||
|
data.objects = []
|
||||||
|
for group in groupOrder
|
||||||
|
data.objects = data.objects.concat groupObjects[group]
|
||||||
|
groupObjects[group] = [] # release old array
|
||||||
|
|
||||||
# generate content data
|
# get header data
|
||||||
for object in data.objects
|
header = []
|
||||||
|
for item in overview
|
||||||
|
headerFound = false
|
||||||
|
for attribute in attributes
|
||||||
|
if attribute.name is item
|
||||||
|
headerFound = true
|
||||||
|
header.push attribute
|
||||||
|
else
|
||||||
|
rowWithoutId = item + '_id'
|
||||||
|
if attribute.name is rowWithoutId
|
||||||
|
headerFound = true
|
||||||
|
header.push attribute
|
||||||
|
|
||||||
# check if info for each col. is already there
|
# get content
|
||||||
for row in dataTypesForCols
|
@log 'debug', 'table', 'header', header, 'overview', 'objects', data.objects
|
||||||
|
|
||||||
# lookup relation
|
|
||||||
if !object[row.name]
|
|
||||||
rowWithoutId = row.name + '_id'
|
|
||||||
for attribute in attributes
|
|
||||||
if rowWithoutId is attribute.name
|
|
||||||
if attribute.relation && App[ attribute.relation ]
|
|
||||||
if App[ attribute.relation ].exists( object[rowWithoutId] )
|
|
||||||
record = App[ attribute.relation ].find( object[rowWithoutId] )
|
|
||||||
object[row.name] = record.name
|
|
||||||
|
|
||||||
@log 'debug', 'table', 'header', header, 'overview', dataTypesForCols, 'objects', data.objects
|
|
||||||
table = App.view('generic/table')(
|
table = App.view('generic/table')(
|
||||||
header: header
|
header: header
|
||||||
overview: dataTypesForCols
|
|
||||||
objects: data.objects
|
objects: data.objects
|
||||||
checkbox: data.checkbox
|
checkbox: data.checkbox
|
||||||
radio: data.radio
|
radio: data.radio
|
||||||
groupBy: data.groupBy
|
groupBy: data.groupBy
|
||||||
destroy: destroy
|
destroy: destroy
|
||||||
|
callbacks: data.callbackAttributes
|
||||||
)
|
)
|
||||||
|
|
||||||
# convert to jquery object
|
# convert to jquery object
|
||||||
table = $(table)
|
table = $(table)
|
||||||
|
|
||||||
|
cursorMap =
|
||||||
|
click: 'pointer'
|
||||||
|
dblclick: 'pointer'
|
||||||
|
#mouseover: 'alias'
|
||||||
|
|
||||||
|
# bind col.
|
||||||
|
if data.bindCol
|
||||||
|
for name, item of data.bindCol
|
||||||
|
if item.events
|
||||||
|
position = 0
|
||||||
|
if data.checkbox
|
||||||
|
position += 1
|
||||||
|
hit = false
|
||||||
|
|
||||||
|
for headerName in header
|
||||||
|
if !hit
|
||||||
|
position += 1
|
||||||
|
if headerName.name is name || headerName.name is "#{name}_id"
|
||||||
|
hit = true
|
||||||
|
|
||||||
|
if hit
|
||||||
|
for event, callback of item.events
|
||||||
|
do (table, event, callback) =>
|
||||||
|
if cursorMap[event]
|
||||||
|
table.find("tbody > tr > td:nth-child(#{position}) > span").css( 'cursor', cursorMap[event] )
|
||||||
|
table.on( event, "tbody > tr > td:nth-child(#{position}) > span",
|
||||||
|
(e) =>
|
||||||
|
e.stopPropagation()
|
||||||
|
id = $(e.target).parents('tr').data('id')
|
||||||
|
callback(id, e)
|
||||||
|
)
|
||||||
|
|
||||||
|
# bind row
|
||||||
|
if data.bindRow
|
||||||
|
if data.bindRow.events
|
||||||
|
for event, callback of data.bindRow.events
|
||||||
|
do (table, event, callback) =>
|
||||||
|
if cursorMap[event]
|
||||||
|
table.find('tbody > tr').css( 'cursor', cursorMap[event] )
|
||||||
|
table.on( event, 'tbody > tr',
|
||||||
|
(e) =>
|
||||||
|
id = $(e.target).parents('tr').data('id')
|
||||||
|
callback(id, e)
|
||||||
|
)
|
||||||
|
|
||||||
|
# bind bindCheckbox
|
||||||
|
if data.bindCheckbox
|
||||||
|
if data.bindCheckbox.events
|
||||||
|
for event, callback of data.bindCheckbox.events
|
||||||
|
do (table, event, callback) =>
|
||||||
|
table.delegate('input[name="bulk"]', event, (e) ->
|
||||||
|
e.stopPropagation()
|
||||||
|
id = $(e.target).parents('tr').data('id')
|
||||||
|
checked = $(e.target).prop('checked')
|
||||||
|
callback(id, checked, e)
|
||||||
|
)
|
||||||
|
|
||||||
# bind on delete dialog
|
# bind on delete dialog
|
||||||
if data.model && destroy
|
if data.model && destroy
|
||||||
table.delegate('[data-type="destroy"]', 'click', (e) ->
|
table.delegate('[data-type="destroy"]', 'click', (e) ->
|
||||||
|
e.stopPropagation()
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
itemId = $(e.target).parents('tr').data('id')
|
itemId = $(e.target).parents('tr').data('id')
|
||||||
item = data.model.find(itemId)
|
item = data.model.find(itemId)
|
||||||
|
@ -165,11 +205,24 @@ class App.ControllerTable extends App.Controller
|
||||||
|
|
||||||
# enable checkbox bulk selection
|
# enable checkbox bulk selection
|
||||||
if data.checkbox
|
if data.checkbox
|
||||||
table.delegate('[name="bulk_all"]', 'click', (e) ->
|
table.delegate('input[name="bulk_all"]', 'click', (e) ->
|
||||||
|
e.stopPropagation()
|
||||||
if $(e.target).prop('checked')
|
if $(e.target).prop('checked')
|
||||||
$(e.target).parents().find('[name="bulk"]').prop( 'checked', true );
|
$(e.target).parents('table').find('[name="bulk"]').each( ->
|
||||||
|
if !$(@).prop('checked')
|
||||||
|
#$(@).prop('checked', true)
|
||||||
|
$(@).trigger('click')
|
||||||
|
)
|
||||||
else
|
else
|
||||||
$(e.target).parents().find('[name="bulk"]').prop( 'checked', false );
|
$(e.target).parents('table').find('[name="bulk"]').each( ->
|
||||||
|
if $(@).prop('checked')
|
||||||
|
#$(@).prop('checked', false)
|
||||||
|
$(@).trigger('click')
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
return table
|
time = =>
|
||||||
|
@frontendTimeUpdate()
|
||||||
|
@delay(time, 80)
|
||||||
|
|
||||||
|
table
|
||||||
|
|
|
@ -1,8 +1,3 @@
|
||||||
$.fn.item = (genericObject) ->
|
|
||||||
elementID = $(@).data('id')
|
|
||||||
elementID or= $(@).parents('[data-id]').data('id')
|
|
||||||
genericObject.find(elementID)
|
|
||||||
|
|
||||||
class App.ChannelEmail extends App.ControllerTabs
|
class App.ChannelEmail extends App.ControllerTabs
|
||||||
constructor: ->
|
constructor: ->
|
||||||
super
|
super
|
||||||
|
@ -46,7 +41,6 @@ class App.ChannelEmail extends App.ControllerTabs
|
||||||
class App.ChannelEmailFilter extends App.Controller
|
class App.ChannelEmailFilter extends App.Controller
|
||||||
events:
|
events:
|
||||||
'click [data-type=new]': 'new'
|
'click [data-type=new]': 'new'
|
||||||
'click [data-type=edit]': 'edit'
|
|
||||||
|
|
||||||
constructor: ->
|
constructor: ->
|
||||||
super
|
super
|
||||||
|
@ -59,9 +53,12 @@ class App.ChannelEmailFilter extends App.Controller
|
||||||
template = $( '<div><div class="overview"></div><a data-type="new" class="btn btn-default">' + App.i18n.translateContent('New') + '</a></div>' )
|
template = $( '<div><div class="overview"></div><a data-type="new" class="btn btn-default">' + App.i18n.translateContent('New') + '</a></div>' )
|
||||||
|
|
||||||
new App.ControllerTable(
|
new App.ControllerTable(
|
||||||
el: template.find('.overview'),
|
el: template.find('.overview')
|
||||||
model: App.PostmasterFilter,
|
model: App.PostmasterFilter
|
||||||
objects: data,
|
objects: data
|
||||||
|
bindRow:
|
||||||
|
events:
|
||||||
|
'click': @edit
|
||||||
)
|
)
|
||||||
@html template
|
@html template
|
||||||
|
|
||||||
|
@ -69,10 +66,9 @@ class App.ChannelEmailFilter extends App.Controller
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
new App.ChannelEmailFilterEdit( {} )
|
new App.ChannelEmailFilterEdit( {} )
|
||||||
|
|
||||||
edit: (e) =>
|
edit: (id, e) =>
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
item = $(e.target).item( App.PostmasterFilter )
|
new App.ChannelEmailFilterEdit( object: App.PostmasterFilter.find(id) )
|
||||||
new App.ChannelEmailFilterEdit( object: item )
|
|
||||||
|
|
||||||
class App.ChannelEmailFilterEdit extends App.ControllerModal
|
class App.ChannelEmailFilterEdit extends App.ControllerModal
|
||||||
constructor: ->
|
constructor: ->
|
||||||
|
@ -135,7 +131,6 @@ class App.ChannelEmailFilterEdit extends App.ControllerModal
|
||||||
class App.ChannelEmailAddress extends App.Controller
|
class App.ChannelEmailAddress extends App.Controller
|
||||||
events:
|
events:
|
||||||
'click [data-type=new]': 'new'
|
'click [data-type=new]': 'new'
|
||||||
'click [data-type=edit]': 'edit'
|
|
||||||
|
|
||||||
constructor: ->
|
constructor: ->
|
||||||
super
|
super
|
||||||
|
@ -151,6 +146,9 @@ class App.ChannelEmailAddress extends App.Controller
|
||||||
el: template.find('.overview')
|
el: template.find('.overview')
|
||||||
model: App.EmailAddress
|
model: App.EmailAddress
|
||||||
objects: data
|
objects: data
|
||||||
|
bindRow:
|
||||||
|
events:
|
||||||
|
'click': @edit
|
||||||
)
|
)
|
||||||
|
|
||||||
@html template
|
@html template
|
||||||
|
@ -159,9 +157,9 @@ class App.ChannelEmailAddress extends App.Controller
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
new App.ChannelEmailAddressEdit( {} )
|
new App.ChannelEmailAddressEdit( {} )
|
||||||
|
|
||||||
edit: (e) =>
|
edit: (id, e) =>
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
item = $(e.target).item( App.EmailAddress )
|
item = App.EmailAddress.find(id)
|
||||||
new App.ChannelEmailAddressEdit( object: item )
|
new App.ChannelEmailAddressEdit( object: item )
|
||||||
|
|
||||||
class App.ChannelEmailAddressEdit extends App.ControllerModal
|
class App.ChannelEmailAddressEdit extends App.ControllerModal
|
||||||
|
@ -223,7 +221,6 @@ class App.ChannelEmailAddressEdit extends App.ControllerModal
|
||||||
class App.ChannelEmailSignature extends App.Controller
|
class App.ChannelEmailSignature extends App.Controller
|
||||||
events:
|
events:
|
||||||
'click [data-type=new]': 'new'
|
'click [data-type=new]': 'new'
|
||||||
'click [data-type=edit]': 'edit'
|
|
||||||
|
|
||||||
constructor: ->
|
constructor: ->
|
||||||
super
|
super
|
||||||
|
@ -238,17 +235,19 @@ class App.ChannelEmailSignature extends App.Controller
|
||||||
el: template.find('.overview')
|
el: template.find('.overview')
|
||||||
model: App.Signature
|
model: App.Signature
|
||||||
objects: data
|
objects: data
|
||||||
|
bindRow:
|
||||||
|
events:
|
||||||
|
'click': @edit
|
||||||
)
|
)
|
||||||
|
|
||||||
@html template
|
@html template
|
||||||
|
|
||||||
new: (e) =>
|
new: (e) =>
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
new App.ChannelEmailSignatureEdit( {} )
|
new App.ChannelEmailSignatureEdit( {} )
|
||||||
|
|
||||||
edit: (e) =>
|
edit: (id, e) =>
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
item = $(e.target).item( App.Signature )
|
item = App.Signature.find(id)
|
||||||
new App.ChannelEmailSignatureEdit( object: item )
|
new App.ChannelEmailSignatureEdit( object: item )
|
||||||
|
|
||||||
class App.ChannelEmailSignatureEdit extends App.ControllerModal
|
class App.ChannelEmailSignatureEdit extends App.ControllerModal
|
||||||
|
@ -310,31 +309,23 @@ class App.ChannelEmailSignatureEdit extends App.ControllerModal
|
||||||
class App.ChannelEmailInbound extends App.Controller
|
class App.ChannelEmailInbound extends App.Controller
|
||||||
events:
|
events:
|
||||||
'click [data-type=new]': 'new'
|
'click [data-type=new]': 'new'
|
||||||
'click [data-type=edit]': 'edit'
|
|
||||||
|
|
||||||
constructor: ->
|
constructor: ->
|
||||||
super
|
super
|
||||||
|
|
||||||
App.Channel.subscribe( @render, initFetch: true )
|
App.Channel.subscribe( @render, initFetch: true )
|
||||||
|
|
||||||
render: =>
|
render: =>
|
||||||
channels = App.Channel.all()
|
channels = App.Channel.search( filter: { area: 'Email::Inbound' } )
|
||||||
|
|
||||||
data = []
|
|
||||||
for channel in channels
|
|
||||||
if channel.area is 'Email::Inbound'
|
|
||||||
channel.host = channel.options['host']
|
|
||||||
channel.user = channel.options['user']
|
|
||||||
data.push channel
|
|
||||||
|
|
||||||
template = $( '<div><div class="overview"></div><a data-type="new" class="btn btn-default">' + App.i18n.translateContent('New') + '</a></div>' )
|
template = $( '<div><div class="overview"></div><a data-type="new" class="btn btn-default">' + App.i18n.translateContent('New') + '</a></div>' )
|
||||||
|
|
||||||
new App.ControllerTable(
|
new App.ControllerTable(
|
||||||
el: template.find('.overview'),
|
el: template.find('.overview')
|
||||||
header: ['Host', 'User', 'Adapter', 'Active'],
|
model: App.Channel
|
||||||
overview: ['host', 'user', 'adapter', 'active'],
|
objects: channels
|
||||||
model: App.Channel,
|
bindRow:
|
||||||
objects: data,
|
events:
|
||||||
|
'click': @edit
|
||||||
)
|
)
|
||||||
@html template
|
@html template
|
||||||
|
|
||||||
|
@ -342,9 +333,9 @@ class App.ChannelEmailInbound extends App.Controller
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
new App.ChannelEmailInboundEdit( {} )
|
new App.ChannelEmailInboundEdit( {} )
|
||||||
|
|
||||||
edit: (e) =>
|
edit: (id, e) =>
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
item = $(e.target).item( App.Channel )
|
item = App.Channel.find(id)
|
||||||
new App.ChannelEmailInboundEdit( object: item )
|
new App.ChannelEmailInboundEdit( object: item )
|
||||||
|
|
||||||
|
|
||||||
|
@ -354,29 +345,13 @@ class App.ChannelEmailInboundEdit extends App.ControllerModal
|
||||||
@render(@object)
|
@render(@object)
|
||||||
|
|
||||||
render: (data = {}) ->
|
render: (data = {}) ->
|
||||||
|
|
||||||
if !data['options']
|
|
||||||
data['options'] = {}
|
|
||||||
data['options']['ssl'] = true
|
|
||||||
data['active'] = true
|
|
||||||
|
|
||||||
configure_attributes = [
|
|
||||||
{ name: 'adapter', display: 'Type', tag: 'select', multiple: false, null: false, options: { IMAP: 'IMAP', POP3: 'POP3' } , class: 'span4', default: data['adapter'] },
|
|
||||||
{ name: 'host', display: 'Host', tag: 'input', type: 'text', limit: 120, null: false, class: 'span4', autocapitalize: false, default: (data['options']&&data['options']['host']) },
|
|
||||||
{ name: 'user', display: 'User', tag: 'input', type: 'text', limit: 120, null: false, class: 'span4', autocapitalize: false, default: (data['options']&&data['options']['user']) },
|
|
||||||
{ name: 'password', display: 'Password', tag: 'input', type: 'password', limit: 120, null: false, class: 'span4', autocapitalize: false, default: (data['options']&&data['options']['password']) },
|
|
||||||
{ name: 'ssl', display: 'SSL', tag: 'select', multiple: false, null: false, options: { true: 'yes', false: 'no' }, translate: true, class: 'span4', default: (data['options']&&data['options']['ssl']) },
|
|
||||||
{ name: 'folder', display: 'Folder', tag: 'input', type: 'text', limit: 120, null: true, class: 'span4', autocapitalize: false, default: (data['options']&&data['options']['folder']) },
|
|
||||||
{ name: 'group_id', display: 'Group', tag: 'select', multiple: false, null: false, filter: @edit_form, nulloption: false, relation: 'Group', class: 'span4', default: data['group_id'] },
|
|
||||||
{ name: 'active', display: 'Active', tag: 'select', multiple: false, null: false, options: { true: 'yes', false: 'no' } , translate: true, class: 'span4', default: data['active'] },
|
|
||||||
]
|
|
||||||
if @object
|
if @object
|
||||||
@html App.view('generic/admin/edit')(
|
@html App.view('generic/admin/edit')(
|
||||||
head: 'Email Channel'
|
head: 'Email Channel'
|
||||||
)
|
)
|
||||||
@form = new App.ControllerForm(
|
@form = new App.ControllerForm(
|
||||||
el: @el.find('#object_edit')
|
el: @el.find('#object_edit')
|
||||||
model: { configure_attributes: configure_attributes, className: '' }
|
model: App.Channel
|
||||||
autofocus: true
|
autofocus: true
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
|
@ -385,7 +360,7 @@ class App.ChannelEmailInboundEdit extends App.ControllerModal
|
||||||
)
|
)
|
||||||
@form = new App.ControllerForm(
|
@form = new App.ControllerForm(
|
||||||
el: @el.find('#object_new')
|
el: @el.find('#object_new')
|
||||||
model: { configure_attributes: configure_attributes, className: '' }
|
model: App.Channel
|
||||||
autofocus: true
|
autofocus: true
|
||||||
)
|
)
|
||||||
@modalShow()
|
@modalShow()
|
||||||
|
@ -395,21 +370,10 @@ class App.ChannelEmailInboundEdit extends App.ControllerModal
|
||||||
|
|
||||||
# get params
|
# get params
|
||||||
params = @formParam(e.target)
|
params = @formParam(e.target)
|
||||||
|
params['area'] = 'Email::Inbound'
|
||||||
|
|
||||||
object = @object || new App.Channel
|
object = @object || new App.Channel
|
||||||
object.load(
|
object.load(params)
|
||||||
area: 'Email::Inbound'
|
|
||||||
adapter: params['adapter']
|
|
||||||
group_id: params['group_id']
|
|
||||||
options: {
|
|
||||||
host: params['host']
|
|
||||||
user: params['user']
|
|
||||||
password: params['password']
|
|
||||||
ssl: params['ssl']
|
|
||||||
folder: params['folder']
|
|
||||||
},
|
|
||||||
active: params['active']
|
|
||||||
)
|
|
||||||
|
|
||||||
# validate form
|
# validate form
|
||||||
errors = @form.validate( params )
|
errors = @form.validate( params )
|
||||||
|
@ -463,7 +427,7 @@ class App.ChannelEmailOutbound extends App.Controller
|
||||||
channel_used = channel
|
channel_used = channel
|
||||||
|
|
||||||
configure_attributes = [
|
configure_attributes = [
|
||||||
{ name: 'adapter', display: 'Send Mails via', tag: 'select', multiple: false, null: false, options: adapters , class: 'span4', default: adapter_used },
|
{ name: 'adapter', display: 'Send Mails via', tag: 'select', multiple: false, null: false, options: adapters , default: adapter_used },
|
||||||
]
|
]
|
||||||
new App.ControllerForm(
|
new App.ControllerForm(
|
||||||
el: @el.find('#form-email-adapter'),
|
el: @el.find('#form-email-adapter'),
|
||||||
|
@ -476,10 +440,10 @@ class App.ChannelEmailOutbound extends App.Controller
|
||||||
|
|
||||||
if adapter_used is 'SMTP'
|
if adapter_used is 'SMTP'
|
||||||
configure_attributes = [
|
configure_attributes = [
|
||||||
{ name: 'host', display: 'Host', tag: 'input', type: 'text', limit: 120, null: false, class: 'span4', autocapitalize: false, default: (channel_used['options']&&channel_used['options']['host']) },
|
{ name: 'host', display: 'Host', tag: 'input', type: 'text', limit: 120, null: false, autocapitalize: false, default: (channel_used['options']&&channel_used['options']['host']) },
|
||||||
{ name: 'user', display: 'User', tag: 'input', type: 'text', limit: 120, null: true, class: 'span4', autocapitalize: false, default: (channel_used['options']&&channel_used['options']['user']) },
|
{ name: 'user', display: 'User', tag: 'input', type: 'text', limit: 120, null: true, autocapitalize: false, default: (channel_used['options']&&channel_used['options']['user']) },
|
||||||
{ name: 'password', display: 'Password', tag: 'input', type: 'password', limit: 120, null: true, class: 'span4', autocapitalize: false, default: (channel_used['options']&&channel_used['options']['password']) },
|
{ name: 'password', display: 'Password', tag: 'input', type: 'password', limit: 120, null: true, autocapitalize: false, default: (channel_used['options']&&channel_used['options']['password']) },
|
||||||
{ name: 'ssl', display: 'SSL', tag: 'select', multiple: false, null: false, options: { true: 'yes', false: 'no' } , class: 'span4', translate: true, default: (channel_used['options']&&channel_used['options']['ssl']) },
|
{ name: 'ssl', display: 'SSL', tag: 'select', multiple: false, null: false, options: { true: 'yes', false: 'no' } , translate: true, default: (channel_used['options']&&channel_used['options']['ssl']) },
|
||||||
{ name: 'port', display: 'Port', tag: 'input', type: 'text', limit: 5, null: false, class: 'span1', autocapitalize: false, default: ((channel_used['options']&&channel_used['options']['port']) || 25) },
|
{ name: 'port', display: 'Port', tag: 'input', type: 'text', limit: 5, null: false, class: 'span1', autocapitalize: false, default: ((channel_used['options']&&channel_used['options']['port']) || 25) },
|
||||||
]
|
]
|
||||||
@form = new App.ControllerForm(
|
@form = new App.ControllerForm(
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
class App.DashboardTicket extends App.Controller
|
class App.DashboardTicket extends App.Controller
|
||||||
events:
|
events:
|
||||||
'click [data-type=edit]': 'zoom'
|
|
||||||
'click [data-type=settings]': 'settings'
|
'click [data-type=settings]': 'settings'
|
||||||
'click [data-type=page]': 'page'
|
'click [data-type=page]': 'page'
|
||||||
|
|
||||||
|
@ -18,11 +17,11 @@ class App.DashboardTicket extends App.Controller
|
||||||
# render
|
# render
|
||||||
@fetch()
|
@fetch()
|
||||||
|
|
||||||
fetch: =>
|
fetch: (force) =>
|
||||||
|
|
||||||
# use cache of first page
|
# use cache of first page
|
||||||
cache = App.Store.get( @key )
|
cache = App.Store.get( @key )
|
||||||
if cache
|
if !force && cache
|
||||||
@load( cache )
|
@load( cache )
|
||||||
|
|
||||||
# init fetch via ajax, all other updates on time via websockets
|
# init fetch via ajax, all other updates on time via websockets
|
||||||
|
@ -55,12 +54,13 @@ class App.DashboardTicket extends App.Controller
|
||||||
App.Overview.unbind('local:rerender')
|
App.Overview.unbind('local:rerender')
|
||||||
App.Overview.bind 'local:rerender', (record) =>
|
App.Overview.bind 'local:rerender', (record) =>
|
||||||
@log 'notice', 'rerender...', record
|
@log 'notice', 'rerender...', record
|
||||||
|
data.overview = record
|
||||||
@render(data)
|
@render(data)
|
||||||
|
|
||||||
App.Overview.unbind('local:refetch')
|
App.Overview.unbind('local:refetch')
|
||||||
App.Overview.bind 'local:refetch', (record) =>
|
App.Overview.bind 'local:refetch', (record) =>
|
||||||
@log 'notice', 'refetch...', record
|
@log 'notice', 'refetch...', record
|
||||||
@fetch()
|
@fetch(true)
|
||||||
|
|
||||||
@render( data )
|
@render( data )
|
||||||
|
|
||||||
|
@ -72,8 +72,8 @@ class App.DashboardTicket extends App.Controller
|
||||||
@overview = data.overview
|
@overview = data.overview
|
||||||
@tickets_count = data.tickets_count
|
@tickets_count = data.tickets_count
|
||||||
@ticket_ids = data.ticket_ids
|
@ticket_ids = data.ticket_ids
|
||||||
# FIXME 10
|
per_page = @overview.view.per_page || 10
|
||||||
pages_total = parseInt( ( @tickets_count / 10 ) + 0.99999 ) || 1
|
pages_total = parseInt( ( @tickets_count / per_page ) + 0.99999 ) || 1
|
||||||
html = App.view('dashboard/ticket')(
|
html = App.view('dashboard/ticket')(
|
||||||
overview: @overview,
|
overview: @overview,
|
||||||
pages_total: pages_total,
|
pages_total: pages_total,
|
||||||
|
@ -92,13 +92,39 @@ class App.DashboardTicket extends App.Controller
|
||||||
if @ticket_ids[ i - 1 ]
|
if @ticket_ids[ i - 1 ]
|
||||||
@tickets_in_table.push App.Ticket.retrieve( @ticket_ids[ i - 1 ] )
|
@tickets_in_table.push App.Ticket.retrieve( @ticket_ids[ i - 1 ] )
|
||||||
|
|
||||||
shown_all_attributes = @ticketTableAttributes( App.Overview.find(@overview.id).view.d )
|
openTicket = (id,e) =>
|
||||||
|
ticket = App.Ticket.retrieve(id)
|
||||||
|
@navigate ticket.uiUrl()
|
||||||
|
callbackTicketTitleAdd = (value, object, attribute, attributes, refObject) =>
|
||||||
|
attribute.title = object.title
|
||||||
|
callbackLinkToTicket = (value, object, attribute, attributes, refObject) =>
|
||||||
|
attribute.link = object.uiUrl()
|
||||||
|
callbackResetLink = (value, object, attribute, attributes, refObject) =>
|
||||||
|
attribute.link = undefined
|
||||||
|
callbackUserPopover = (value, object, attribute, attributes, refObject) =>
|
||||||
|
attribute.class = 'user-popover'
|
||||||
|
attribute.data =
|
||||||
|
id: refObject.id
|
||||||
|
|
||||||
new App.ControllerTable(
|
new App.ControllerTable(
|
||||||
|
overview: @overview.view.d
|
||||||
el: html.find('.table-overview'),
|
el: html.find('.table-overview'),
|
||||||
overview_extended: shown_all_attributes,
|
model: App.Ticket
|
||||||
model: App.Ticket,
|
|
||||||
objects: @tickets_in_table,
|
objects: @tickets_in_table,
|
||||||
checkbox: false,
|
checkbox: false
|
||||||
|
groupBy: @overview.group_by
|
||||||
|
bindRow:
|
||||||
|
events:
|
||||||
|
'click': openTicket
|
||||||
|
callbackAttributes:
|
||||||
|
customer_id:
|
||||||
|
[ callbackResetLink, callbackUserPopover ]
|
||||||
|
owner_id:
|
||||||
|
[ callbackResetLink, callbackUserPopover ]
|
||||||
|
title:
|
||||||
|
[ callbackLinkToTicket, callbackTicketTitleAdd ]
|
||||||
|
number:
|
||||||
|
[ callbackLinkToTicket, callbackTicketTitleAdd ]
|
||||||
)
|
)
|
||||||
|
|
||||||
@html html
|
@html html
|
||||||
|
@ -122,8 +148,9 @@ class App.DashboardTicket extends App.Controller
|
||||||
|
|
||||||
settings: (e) =>
|
settings: (e) =>
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
new Settings(
|
new App.OverviewSettings(
|
||||||
overview: App.Overview.find(@overview.id)
|
overview_id: @overview.id
|
||||||
|
view_mode: 'd'
|
||||||
)
|
)
|
||||||
|
|
||||||
page: (e) =>
|
page: (e) =>
|
||||||
|
@ -132,139 +159,3 @@ class App.DashboardTicket extends App.Controller
|
||||||
@start_page = id
|
@start_page = id
|
||||||
@fetch()
|
@fetch()
|
||||||
|
|
||||||
class Settings extends App.ControllerModal
|
|
||||||
constructor: ->
|
|
||||||
super
|
|
||||||
@render()
|
|
||||||
|
|
||||||
render: ->
|
|
||||||
|
|
||||||
@html App.view('dashboard/ticket_settings')(
|
|
||||||
overview: @overview,
|
|
||||||
)
|
|
||||||
@configure_attributes_article = [
|
|
||||||
# { name: 'from', display: 'From', tag: 'input', type: 'text', limit: 100, null: false, class: 'span8', },
|
|
||||||
# { name: 'to', display: 'To', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide' },
|
|
||||||
# { name: 'type_id', display: 'Type', tag: 'select', multiple: false, null: true, relation: 'TicketArticleType', default: '9', class: 'medium', item_class: 'pull-left' },
|
|
||||||
# { name: 'internal', display: 'Visibility', tag: 'radio', default: false, null: true, options: { true: 'internal', false: 'public' }, class: 'medium', item_class: 'pull-left' },
|
|
||||||
{
|
|
||||||
name: 'per_page',
|
|
||||||
display: 'Items per page',
|
|
||||||
tag: 'select',
|
|
||||||
multiple: false,
|
|
||||||
null: false,
|
|
||||||
# default: @overview.view.d.per_page,
|
|
||||||
options: {
|
|
||||||
5: 5,
|
|
||||||
10: 10,
|
|
||||||
15: 15,
|
|
||||||
20: 20,
|
|
||||||
},
|
|
||||||
class: 'medium',
|
|
||||||
# item_class: 'pull-left',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'attributes',
|
|
||||||
display: 'Attributes',
|
|
||||||
tag: 'checkbox',
|
|
||||||
default: @overview.view.d,
|
|
||||||
null: false,
|
|
||||||
translate: true
|
|
||||||
options: {
|
|
||||||
number: 'Number'
|
|
||||||
title: 'Title'
|
|
||||||
customer: 'Customer'
|
|
||||||
state: 'State'
|
|
||||||
priority: 'Priority'
|
|
||||||
group: 'Group'
|
|
||||||
owner: 'Owner'
|
|
||||||
created_at: 'Age'
|
|
||||||
last_contact: 'Last Contact'
|
|
||||||
last_contact_agent: 'Last Contact Agent'
|
|
||||||
last_contact_customer: 'Last Contact Customer'
|
|
||||||
first_response: 'First Response'
|
|
||||||
close_time: 'Close Time'
|
|
||||||
escalation_time: 'Escalation in'
|
|
||||||
article_count: 'Article Count'
|
|
||||||
},
|
|
||||||
class: 'medium',
|
|
||||||
# item_class: 'pull-left',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'order_by',
|
|
||||||
display: 'Order',
|
|
||||||
tag: 'select',
|
|
||||||
default: @overview.order.by,
|
|
||||||
null: false,
|
|
||||||
translate: true
|
|
||||||
options: {
|
|
||||||
number: 'Number'
|
|
||||||
title: 'Title'
|
|
||||||
customer: 'Customer'
|
|
||||||
state: 'State'
|
|
||||||
priority: 'Priority'
|
|
||||||
group: 'Group'
|
|
||||||
owner: 'Owner'
|
|
||||||
created_at: 'Age'
|
|
||||||
last_contact: 'Last Contact'
|
|
||||||
last_contact_agent: 'Last Contact Agent'
|
|
||||||
last_contact_customer: 'Last Contact Customer'
|
|
||||||
first_response: 'First Response'
|
|
||||||
close_time: 'Close Time'
|
|
||||||
escalation_time: 'Escalation in'
|
|
||||||
article_count: 'Article Count'
|
|
||||||
},
|
|
||||||
class: 'medium',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'order_by_direction',
|
|
||||||
display: 'Direction',
|
|
||||||
tag: 'select',
|
|
||||||
default: @overview.order.direction,
|
|
||||||
null: false,
|
|
||||||
translate: true
|
|
||||||
options: {
|
|
||||||
ASC: 'up',
|
|
||||||
DESC: 'down',
|
|
||||||
},
|
|
||||||
class: 'medium',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
new App.ControllerForm(
|
|
||||||
el: @el.find('#form-setting'),
|
|
||||||
model: { configure_attributes: @configure_attributes_article },
|
|
||||||
autofocus: false,
|
|
||||||
)
|
|
||||||
|
|
||||||
@modalShow()
|
|
||||||
|
|
||||||
submit: (e) =>
|
|
||||||
e.preventDefault()
|
|
||||||
params = @formParam(e.target)
|
|
||||||
|
|
||||||
# check if refetch is needed
|
|
||||||
@reload_needed = 0
|
|
||||||
if @overview.view['d']['per_page'] isnt params['per_page']
|
|
||||||
@overview.view['d']['per_page'] = params['per_page']
|
|
||||||
@reload_needed = 1
|
|
||||||
|
|
||||||
if @overview.order['by'] isnt params['order_by']
|
|
||||||
@overview.order['by'] = params['order_by']
|
|
||||||
@reload_needed = 1
|
|
||||||
|
|
||||||
if @overview.order['direction'] isnt params['order_by_direction']
|
|
||||||
@overview.order['direction'] = params['order_by_direction']
|
|
||||||
@reload_needed = 1
|
|
||||||
|
|
||||||
@overview.view['d'] = params['attributes']
|
|
||||||
|
|
||||||
@overview.save(
|
|
||||||
done: =>
|
|
||||||
if @reload_needed
|
|
||||||
@overview.trigger('local:refetch')
|
|
||||||
else
|
|
||||||
@overview.trigger('local:rerender')
|
|
||||||
)
|
|
||||||
|
|
||||||
@modalHide()
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
class Index extends App.Controller
|
class Index extends App.Controller
|
||||||
constructor: ->
|
constructor: ->
|
||||||
super
|
super
|
||||||
|
|
||||||
@render()
|
@render()
|
||||||
|
|
||||||
render: ->
|
render: ->
|
||||||
|
@ -55,11 +54,11 @@ class Table extends App.ControllerContent
|
||||||
# render
|
# render
|
||||||
@fetch()
|
@fetch()
|
||||||
|
|
||||||
fetch: =>
|
fetch: (force) =>
|
||||||
|
|
||||||
# use cache of first page
|
# use cache of first page
|
||||||
cache = App.Store.get( @key )
|
cache = App.Store.get( @key )
|
||||||
if cache
|
if !force && cache
|
||||||
@load(cache)
|
@load(cache)
|
||||||
|
|
||||||
# init fetch via ajax, all other updates on time via websockets
|
# init fetch via ajax, all other updates on time via websockets
|
||||||
|
@ -106,7 +105,7 @@ class Table extends App.ControllerContent
|
||||||
App.Overview.unbind('local:refetch')
|
App.Overview.unbind('local:refetch')
|
||||||
App.Overview.bind 'local:refetch', (record) =>
|
App.Overview.bind 'local:refetch', (record) =>
|
||||||
@log 'notice', 'refetch...', record
|
@log 'notice', 'refetch...', record
|
||||||
@fetch()
|
@fetch(true)
|
||||||
|
|
||||||
@ticket_list_show = []
|
@ticket_list_show = []
|
||||||
for ticket_id in @ticket_ids
|
for ticket_id in @ticket_ids
|
||||||
|
@ -123,6 +122,8 @@ class Table extends App.ControllerContent
|
||||||
|
|
||||||
render: ->
|
render: ->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# if customer and no ticket exists, show the following message only
|
# if customer and no ticket exists, show the following message only
|
||||||
if !@ticket_list_show[0] && @isRole('Customer')
|
if !@ticket_list_show[0] && @isRole('Customer')
|
||||||
@html App.view('customer_not_ticket_exists')()
|
@html App.view('customer_not_ticket_exists')()
|
||||||
|
@ -131,6 +132,7 @@ class Table extends App.ControllerContent
|
||||||
@selected = @bulkGetSelected()
|
@selected = @bulkGetSelected()
|
||||||
|
|
||||||
# set page title
|
# set page title
|
||||||
|
@overview = App.Overview.find( @overview.id )
|
||||||
@title @overview.name
|
@title @overview.name
|
||||||
|
|
||||||
# render init page
|
# render init page
|
||||||
|
@ -182,27 +184,51 @@ class Table extends App.ControllerContent
|
||||||
)
|
)
|
||||||
@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 )
|
openTicket = (id,e) =>
|
||||||
groupBy = undefined
|
ticket = App.Ticket.retrieve(id)
|
||||||
if @overview.group_by
|
@navigate ticket.uiUrl()
|
||||||
group_by =
|
callbackTicketTitleAdd = (value, object, attribute, attributes, refObject) =>
|
||||||
name: @overview.group_by
|
attribute.title = object.title
|
||||||
id: @overview.group_by + '_id'
|
callbackLinkToTicket = (value, object, attribute, attributes, refObject) =>
|
||||||
|
attribute.link = object.uiUrl()
|
||||||
|
callbackResetLink = (value, object, attribute, attributes, refObject) =>
|
||||||
|
attribute.link = undefined
|
||||||
|
callbackUserPopover = (value, object, attribute, attributes, refObject) =>
|
||||||
|
attribute.class = 'user-popover'
|
||||||
|
attribute.data =
|
||||||
|
id: refObject.id
|
||||||
|
callbackCheckbox = (id, checked, e) =>
|
||||||
|
if @el.find('table').find('input[name="bulk"]:checked').length == 0
|
||||||
|
@el.find('.bulk-action').addClass('hide')
|
||||||
|
else
|
||||||
|
@el.find('.bulk-action').removeClass('hide')
|
||||||
|
|
||||||
# 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')
|
overview: @overview.view.s
|
||||||
overview_extended: shown_all_attributes
|
el: @el.find('.table-overview')
|
||||||
model: App.Ticket
|
model: App.Ticket
|
||||||
objects: @ticket_list_show
|
objects: @ticket_list_show
|
||||||
checkbox: checkbox
|
checkbox: checkbox
|
||||||
groupBy: group_by
|
groupBy: @overview.group_by
|
||||||
|
bindRow:
|
||||||
|
events:
|
||||||
|
'click': openTicket
|
||||||
|
#bindCol:
|
||||||
|
# customer_id:
|
||||||
|
# events:
|
||||||
|
# 'mouseover': popOver
|
||||||
|
callbackAttributes:
|
||||||
|
customer_id:
|
||||||
|
[ callbackResetLink, callbackUserPopover ]
|
||||||
|
owner_id:
|
||||||
|
[ callbackResetLink, callbackUserPopover ]
|
||||||
|
title:
|
||||||
|
[ callbackLinkToTicket, callbackTicketTitleAdd ]
|
||||||
|
number:
|
||||||
|
[ callbackLinkToTicket, callbackTicketTitleAdd ]
|
||||||
|
bindCheckbox:
|
||||||
|
events:
|
||||||
|
'click': callbackCheckbox
|
||||||
)
|
)
|
||||||
|
|
||||||
@bulkSetSelected( @selected )
|
@bulkSetSelected( @selected )
|
||||||
|
@ -215,12 +241,13 @@ class Table extends App.ControllerContent
|
||||||
|
|
||||||
# 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
|
if @el.find('.table-overview').find('input[name="bulk"]:checked').length isnt 0
|
||||||
@el.find('.bulk-action').removeClass('hide')
|
@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('input[name="bulk"], input[name="bulk_all"]', 'click', (e) =>
|
||||||
if @el.find('.table-overview').find('[name="bulk"]:checked').length == 0
|
console.log('YES')
|
||||||
|
if @el.find('.table-overview').find('input[name="bulk"]:checked').length == 0
|
||||||
|
|
||||||
# hide
|
# hide
|
||||||
@el.find('.bulk-action').addClass('hide')
|
@el.find('.bulk-action').addClass('hide')
|
||||||
|
@ -324,6 +351,7 @@ class Table extends App.ControllerContent
|
||||||
@fetch()
|
@fetch()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@el.find('.table-overview').find('[name="bulk"]:checked').prop('checked', false)
|
||||||
App.Event.trigger 'notify', {
|
App.Event.trigger 'notify', {
|
||||||
type: 'success'
|
type: 'success'
|
||||||
msg: App.i18n.translateContent('Bulk-Action executed!')
|
msg: App.i18n.translateContent('Bulk-Action executed!')
|
||||||
|
@ -343,14 +371,15 @@ class Table extends App.ControllerContent
|
||||||
|
|
||||||
settings: (e) =>
|
settings: (e) =>
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
new Settings(
|
new App.OverviewSettings(
|
||||||
overview: App.Overview.find(@overview.id),
|
overview_id: @overview.id
|
||||||
view_mode: @view_mode,
|
view_mode: @view_mode
|
||||||
)
|
)
|
||||||
|
|
||||||
class Settings extends App.ControllerModal
|
class App.OverviewSettings extends App.ControllerModal
|
||||||
constructor: ->
|
constructor: ->
|
||||||
super
|
super
|
||||||
|
@overview = App.Overview.find(@overview_id)
|
||||||
@render()
|
@render()
|
||||||
|
|
||||||
render: ->
|
render: ->
|
||||||
|
@ -358,119 +387,154 @@ class Settings extends App.ControllerModal
|
||||||
@html App.view('dashboard/ticket_settings')(
|
@html App.view('dashboard/ticket_settings')(
|
||||||
overview: @overview,
|
overview: @overview,
|
||||||
)
|
)
|
||||||
@configure_attributes_article = [
|
@configure_attributes_article = []
|
||||||
# { name: 'from', display: 'From', tag: 'input', type: 'text', limit: 100, null: false, class: 'span8', },
|
if @view_mode is 'd'
|
||||||
# { name: 'to', display: 'To', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide' },
|
@configure_attributes_article.push({
|
||||||
# { name: 'type_id', display: 'Type', tag: 'select', multiple: false, null: true, relation: 'TicketArticleType', default: '9', class: 'medium', item_class: 'pull-left' },
|
name: 'view::per_page',
|
||||||
# { name: 'internal', display: 'Visibility', tag: 'radio', default: false, null: true, options: { true: 'internal', false: 'public' }, class: 'medium', item_class: 'pull-left' },
|
display: 'Items per page',
|
||||||
{
|
tag: 'select',
|
||||||
name: 'per_page'
|
multiple: false,
|
||||||
display: 'Items per page'
|
null: false,
|
||||||
tag: 'select'
|
default: @overview.view.per_page
|
||||||
multiple: false
|
options: {
|
||||||
null: false
|
5: ' 5'
|
||||||
# default: @overview.view[@view_mode].per_page
|
10: '10'
|
||||||
options:
|
15: '15'
|
||||||
15: 15
|
20: '20'
|
||||||
20: 20
|
25: '25'
|
||||||
25: 25
|
},
|
||||||
30: 30
|
class: 'medium',
|
||||||
35: 35
|
})
|
||||||
class: 'medium'
|
@configure_attributes_article.push({
|
||||||
# item_class: 'pull-left'
|
name: "view::#{@view_mode}"
|
||||||
},
|
display: 'Attributes'
|
||||||
{
|
tag: 'checkbox'
|
||||||
name: 'attributes'
|
default: @overview.view[@view_mode]
|
||||||
display: 'Attributes'
|
null: false
|
||||||
tag: 'checkbox'
|
translate: true
|
||||||
default: @overview.view[@view_mode]
|
options: [
|
||||||
null: false
|
{
|
||||||
translate: true
|
value: 'number'
|
||||||
options:
|
name: 'Number'
|
||||||
# true: 'internal'
|
},
|
||||||
# false: 'public'
|
{
|
||||||
number: 'Number'
|
value: 'title'
|
||||||
title: 'Title'
|
name: 'Title'
|
||||||
customer: 'Customer'
|
},
|
||||||
state: 'State'
|
{
|
||||||
priority: 'Priority'
|
value: 'customer'
|
||||||
group: 'Group'
|
name: 'Customer'
|
||||||
owner: 'Owner'
|
},
|
||||||
created_at: 'Age'
|
{
|
||||||
last_contact: 'Last Contact'
|
value: 'organization'
|
||||||
last_contact_agent: 'Last Contact Agent'
|
name: 'Organization'
|
||||||
last_contact_customer: 'Last Contact Customer'
|
},
|
||||||
first_response: 'First Response'
|
{
|
||||||
close_time: 'Close Time'
|
value: 'state'
|
||||||
escalation_time: 'Escalation in'
|
name: 'State'
|
||||||
article_count: 'Article Count'
|
},
|
||||||
class: 'medium'
|
{
|
||||||
},
|
value: 'priority'
|
||||||
{
|
name: 'Priority'
|
||||||
name: 'order_by'
|
},
|
||||||
display: 'Order'
|
{
|
||||||
tag: 'select'
|
value: 'group'
|
||||||
default: @overview.order.by
|
name: 'Group'
|
||||||
null: false
|
},
|
||||||
translate: true
|
{
|
||||||
options:
|
value: 'owner'
|
||||||
number: 'Number'
|
name: 'Owner'
|
||||||
title: 'Title'
|
},
|
||||||
customer: 'Customer'
|
{
|
||||||
state: 'State'
|
value: 'created_at'
|
||||||
priority: 'Priority'
|
name: 'Age'
|
||||||
group: 'Group'
|
},
|
||||||
owner: 'Owner'
|
{
|
||||||
created_at: 'Age'
|
value: 'last_contact'
|
||||||
last_contact: 'Last Contact'
|
name: 'Last Contact'
|
||||||
last_contact_agent: 'Last Contact Agent'
|
},
|
||||||
last_contact_customer: 'Last Contact Customer'
|
{
|
||||||
first_response: 'First Response'
|
value: 'last_contact_agent'
|
||||||
close_time: 'Close Time'
|
name: 'Last Contact Agent'
|
||||||
escalation_time: 'Escalation in'
|
},
|
||||||
article_count: 'Article Count'
|
{
|
||||||
class: 'medium'
|
value: 'last_contact_customer'
|
||||||
},
|
name: 'Last Contact Customer'
|
||||||
{
|
},
|
||||||
name: 'order_by_direction'
|
{
|
||||||
display: 'Direction'
|
value: 'first_response'
|
||||||
tag: 'select'
|
name: 'First Response'
|
||||||
default: @overview.order.direction
|
},
|
||||||
null: false
|
{
|
||||||
translate: true
|
value: 'close_time'
|
||||||
options:
|
name: 'Close Time'
|
||||||
ASC: 'up'
|
},
|
||||||
DESC: 'down'
|
{
|
||||||
class: 'medium'
|
value: 'escalation_time'
|
||||||
},
|
name: 'Escalation in'
|
||||||
{
|
},
|
||||||
name: 'group_by'
|
{
|
||||||
display: 'Group by'
|
value: 'article_count'
|
||||||
tag: 'select'
|
name: 'Article Count'
|
||||||
default: @overview.group_by
|
},
|
||||||
null: true
|
]
|
||||||
nulloption: true
|
class: 'medium'
|
||||||
translate: true
|
},
|
||||||
options:
|
{
|
||||||
customer: 'Customer'
|
name: 'order::by'
|
||||||
state: 'State'
|
display: 'Order'
|
||||||
priority: 'Priority'
|
tag: 'select'
|
||||||
group: 'Group'
|
default: @overview.order.by
|
||||||
owner: 'Owner'
|
null: false
|
||||||
class: 'medium'
|
translate: true
|
||||||
},
|
options:
|
||||||
# {
|
number: 'Number'
|
||||||
# name: 'condition',
|
title: 'Title'
|
||||||
# display: 'Conditions',
|
customer: 'Customer'
|
||||||
# tag: 'select',
|
organization: 'Organization'
|
||||||
# multiple: false,
|
state: 'State'
|
||||||
# null: false,
|
priority: 'Priority'
|
||||||
# relation: 'TicketArticleType',
|
group: 'Group'
|
||||||
# default: '9',
|
owner: 'Owner'
|
||||||
# class: 'medium',
|
created_at: 'Age'
|
||||||
# item_class: 'pull-left',
|
last_contact: 'Last Contact'
|
||||||
# },
|
last_contact_agent: 'Last Contact Agent'
|
||||||
]
|
last_contact_customer: 'Last Contact Customer'
|
||||||
|
first_response: 'First Response'
|
||||||
|
close_time: 'Close Time'
|
||||||
|
escalation_time: 'Escalation in'
|
||||||
|
article_count: 'Article Count'
|
||||||
|
class: 'medium'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'order::direction'
|
||||||
|
display: 'Direction'
|
||||||
|
tag: 'select'
|
||||||
|
default: @overview.order.direction
|
||||||
|
null: false
|
||||||
|
translate: true
|
||||||
|
options:
|
||||||
|
ASC: 'up'
|
||||||
|
DESC: 'down'
|
||||||
|
class: 'medium'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'group_by'
|
||||||
|
display: 'Group by'
|
||||||
|
tag: 'select'
|
||||||
|
default: @overview.group_by
|
||||||
|
null: true
|
||||||
|
nulloption: true
|
||||||
|
translate: true
|
||||||
|
options:
|
||||||
|
customer: 'Customer'
|
||||||
|
organization: 'Organization'
|
||||||
|
state: 'State'
|
||||||
|
priority: 'Priority'
|
||||||
|
group: 'Group'
|
||||||
|
owner: 'Owner'
|
||||||
|
class: 'medium'
|
||||||
|
})
|
||||||
|
|
||||||
new App.ControllerForm(
|
new App.ControllerForm(
|
||||||
el: @el.find('#form-setting')
|
el: @el.find('#form-setting')
|
||||||
|
@ -486,19 +550,18 @@ class Settings extends App.ControllerModal
|
||||||
|
|
||||||
# check if refetch is needed
|
# check if refetch is needed
|
||||||
@reload_needed = 0
|
@reload_needed = 0
|
||||||
if @overview.order['by'] isnt params['order_by']
|
if @overview.order.by isnt params.order.by
|
||||||
@overview.order['by'] = params['order_by']
|
@overview.order.by = params.order.by
|
||||||
@reload_needed = 1
|
@reload_needed = 1
|
||||||
|
|
||||||
if @overview.order['direction'] isnt params['order_by_direction']
|
if @overview.order.direction isnt params.order.direction
|
||||||
@overview.order['direction'] = params['order_by_direction']
|
@overview.order.direction = params.order.direction
|
||||||
@reload_needed = 1
|
@reload_needed = 1
|
||||||
|
|
||||||
if @overview['group_by'] isnt params['group_by']
|
for key, value of params.view
|
||||||
@overview['group_by'] = params['group_by']
|
@overview.view[key] = value
|
||||||
@reload_needed = 1
|
|
||||||
|
|
||||||
@overview.view[@view_mode] = params['attributes']
|
@overview.group_by = params.group_by
|
||||||
|
|
||||||
@overview.save(
|
@overview.save(
|
||||||
done: =>
|
done: =>
|
||||||
|
|
|
@ -144,7 +144,10 @@ class _i18nSingleton extends Spine.Module
|
||||||
translate: ( string, args... ) =>
|
translate: ( string, args... ) =>
|
||||||
|
|
||||||
# return '' on undefined
|
# return '' on undefined
|
||||||
|
if typeof string is 'boolean'
|
||||||
|
string = string.toString()
|
||||||
return '' if string is undefined
|
return '' if string is undefined
|
||||||
|
return '' if string is ''
|
||||||
|
|
||||||
# return translation
|
# return translation
|
||||||
if @map[string] isnt undefined
|
if @map[string] isnt undefined
|
||||||
|
|
|
@ -16,6 +16,9 @@ class App.Model extends Spine.Model
|
||||||
uiUrl: ->
|
uiUrl: ->
|
||||||
'#'
|
'#'
|
||||||
|
|
||||||
|
translate: ->
|
||||||
|
App[ @constructor.className ].configure_translate
|
||||||
|
|
||||||
objectDisplayName: ->
|
objectDisplayName: ->
|
||||||
@constructor.className
|
@constructor.className
|
||||||
|
|
||||||
|
@ -69,9 +72,22 @@ class App.Model extends Spine.Model
|
||||||
# check required // if null is defined && null is false
|
# check required // if null is defined && null is false
|
||||||
if 'null' of attribute && !attribute[null]
|
if 'null' of attribute && !attribute[null]
|
||||||
|
|
||||||
# key exists not in hash || value is '' || value is undefined
|
# check :: fields
|
||||||
if !( attribute.name of data['params'] ) || data['params'][attribute.name] is '' || data['params'][attribute.name] is undefined
|
parts = attribute.name.split '::'
|
||||||
errors[attribute.name] = 'is required'
|
if parts[0] && !parts[1]
|
||||||
|
|
||||||
|
# key exists not in hash || value is '' || value is undefined
|
||||||
|
if !( attribute.name of data['params'] ) || data['params'][attribute.name] is '' || data['params'][attribute.name] is undefined
|
||||||
|
errors[attribute.name] = 'is required'
|
||||||
|
|
||||||
|
else if parts[0] && parts[1] && !parts[2]
|
||||||
|
|
||||||
|
# key exists not in hash || value is '' || value is undefined
|
||||||
|
if !data.params[parts[0]] || !( parts[1] of data.params[parts[0]] ) || data.params[parts[0]][parts[1]] is '' || data.params[parts[0]][parts[1]] is undefined
|
||||||
|
errors[attribute.name] = 'is required'
|
||||||
|
|
||||||
|
else
|
||||||
|
throw "can't parse '#{attribute.name}'"
|
||||||
|
|
||||||
# check confirm password
|
# check confirm password
|
||||||
if attribute.type is 'password' && data['params'][attribute.name] && "#{attribute.name}_confirm" of data['params']
|
if attribute.type is 'password' && data['params'][attribute.name] && "#{attribute.name}_confirm" of data['params']
|
||||||
|
@ -82,7 +98,9 @@ class App.Model extends Spine.Model
|
||||||
errors["#{attribute.name}_confirm"] = ''
|
errors["#{attribute.name}_confirm"] = ''
|
||||||
|
|
||||||
# return error object
|
# return error object
|
||||||
return errors if !_.isEmpty(errors)
|
if !_.isEmpty(errors)
|
||||||
|
console.log 'error', 'validation vailed', errors
|
||||||
|
return errors
|
||||||
|
|
||||||
# return no errors
|
# return no errors
|
||||||
return
|
return
|
||||||
|
@ -327,5 +345,3 @@ class App.Model extends Spine.Model
|
||||||
return
|
return
|
||||||
)
|
)
|
||||||
collection
|
collection
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,3 +3,24 @@ class App.Channel extends App.Model
|
||||||
@extend Spine.Model.Ajax
|
@extend Spine.Model.Ajax
|
||||||
@url: @apiPath + '/channels'
|
@url: @apiPath + '/channels'
|
||||||
@configure_delete = true
|
@configure_delete = true
|
||||||
|
|
||||||
|
@configure_attributes = [
|
||||||
|
{ name: 'adapter', display: 'Type', tag: 'select', multiple: false, null: false, options: { IMAP: 'IMAP', POP3: 'POP3' } },
|
||||||
|
{ name: 'options::host', display: 'Host', tag: 'input', type: 'text', limit: 120, null: false, autocapitalize: false },
|
||||||
|
{ name: 'options::user', display: 'User', tag: 'input', type: 'text', limit: 120, null: false, autocapitalize: false },
|
||||||
|
{ name: 'options::password', display: 'Password', tag: 'input', type: 'password', limit: 120, null: false, autocapitalize: false },
|
||||||
|
{ name: 'options::ssl', display: 'SSL', tag: 'select', multiple: false, null: false, options: { true: 'yes', false: 'no' }, translate: true, default: true},
|
||||||
|
{ name: 'options::folder', display: 'Folder', tag: 'input', type: 'text', limit: 120, null: true, autocapitalize: false },
|
||||||
|
{ name: 'group_id', display: 'Group', tag: 'select', multiple: false, null: false, nulloption: true, relation: 'Group' },
|
||||||
|
{ name: 'active', display: 'Active', tag: 'select', multiple: false, null: false, options: { true: 'yes', false: 'no' }, translate: true, default: true },
|
||||||
|
]
|
||||||
|
@configure_overview = [
|
||||||
|
'adapter', 'options::host', 'options::user', 'group'
|
||||||
|
]
|
||||||
|
|
||||||
|
@_fillUp: (data) ->
|
||||||
|
|
||||||
|
# group
|
||||||
|
data.group = App.Group.find( data.group_id )
|
||||||
|
|
||||||
|
data
|
|
@ -18,21 +18,64 @@ class App.Overview extends App.Model
|
||||||
default: ['number', 'title', 'state', 'created_at']
|
default: ['number', 'title', 'state', 'created_at']
|
||||||
null: false
|
null: false
|
||||||
translate: true
|
translate: true
|
||||||
options:
|
options: [
|
||||||
number: 'Number'
|
{
|
||||||
title: 'Title'
|
value: 'number'
|
||||||
customer: 'Customer'
|
name: 'Number'
|
||||||
state: 'State'
|
},
|
||||||
priority: 'Priority'
|
{
|
||||||
group: 'Group'
|
value: 'title'
|
||||||
owner: 'Owner'
|
name: 'Title'
|
||||||
created_at: 'Age'
|
},
|
||||||
last_contact: 'Last Contact'
|
{
|
||||||
last_contact_agent: 'Last Contact Agent'
|
value: 'customer'
|
||||||
last_contact_customer: 'Last Contact Customer'
|
name: 'Customer'
|
||||||
first_response: 'First Response'
|
},
|
||||||
close_time: 'Close Time'
|
{
|
||||||
article_count: 'Article Count'
|
value: 'state'
|
||||||
|
name: 'State'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'priority'
|
||||||
|
name: 'Priority'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'group'
|
||||||
|
name: 'Group'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'owner'
|
||||||
|
name: 'Owner'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'created_at'
|
||||||
|
name: 'Age'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'last_contact'
|
||||||
|
name: 'Last Contact'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'last_contact_agent'
|
||||||
|
name: 'Last Contact Agent'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'last_contact_customer'
|
||||||
|
name: 'Last Contact Customer'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'first_response'
|
||||||
|
name: 'First Response'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'close_time'
|
||||||
|
name: 'Close Time'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'article_count'
|
||||||
|
name: 'Article Count'
|
||||||
|
},
|
||||||
|
]
|
||||||
class: 'medium'
|
class: 'medium'
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -5,19 +5,21 @@ class App.Ticket extends App.Model
|
||||||
@configure_attributes = [
|
@configure_attributes = [
|
||||||
{ name: 'number', display: '#', tag: 'input', type: 'text', limit: 100, null: true, read_only: true, style: 'width: 8%' },
|
{ name: 'number', display: '#', tag: 'input', type: 'text', limit: 100, null: true, read_only: true, style: 'width: 8%' },
|
||||||
{ name: 'customer_id', display: 'Customer', tag: 'input', type: 'text', limit: 100, null: false, class: 'span8', autocapitalize: false, help: 'Select the customer of the Ticket or create one.', link: '<a href="" class="customer_new">»</a>' },
|
{ name: 'customer_id', display: 'Customer', tag: 'input', type: 'text', limit: 100, null: false, class: 'span8', autocapitalize: false, help: 'Select the customer of the Ticket or create one.', link: '<a href="" class="customer_new">»</a>' },
|
||||||
|
{ name: 'organization_id', display: 'Organization', tagreadonly: 1 },
|
||||||
{ name: 'group_id', display: 'Group', tag: 'select', multiple: false, limit: 100, null: false, class: 'span8', relation: 'Group', style: 'width: 10%' },
|
{ name: 'group_id', display: 'Group', tag: 'select', multiple: false, limit: 100, null: false, class: 'span8', relation: 'Group', style: 'width: 10%' },
|
||||||
{ name: 'owner_id', display: 'Owner', tag: 'select', multiple: false, limit: 100, null: true, class: 'span8', relation: 'User', style: 'width: 12%' },
|
{ name: 'owner_id', display: 'Owner', tag: 'select', multiple: false, limit: 100, null: true, class: 'span8', relation: 'User', style: 'width: 12%' },
|
||||||
{ name: 'title', display: 'Title', tag: 'input', type: 'text', limit: 100, null: false, class: 'span8' },
|
{ name: 'title', display: 'Title', tag: 'input', type: 'text', limit: 100, null: false, class: 'span8' },
|
||||||
{ name: 'state_id', display: 'State', tag: 'select', multiple: false, null: false, relation: 'TicketState', default: 'new', class: 'medium', style: 'width: 12%' },
|
{ name: 'state_id', display: 'State', tag: 'select', multiple: false, null: false, relation: 'TicketState', default: 'new', class: 'medium', style: 'width: 12%' },
|
||||||
{ name: 'priority_id', display: 'Priority', tag: 'select', multiple: false, null: false, relation: 'TicketPriority', default: '2 normal', class: 'medium', style: 'width: 12%' },
|
{ name: 'priority_id', display: 'Priority', tag: 'select', multiple: false, null: false, relation: 'TicketPriority', default: '2 normal', class: 'medium', style: 'width: 12%' },
|
||||||
{ name: 'created_at', display: 'Created', tag: 'time', style: 'width: 12%' },
|
{ name: 'last_contact', display: 'Last contact', type: 'time', null: true, style: 'width: 12%' },
|
||||||
{ name: 'last_contact', display: 'Last contact', tag: 'time', null: true, style: 'width: 12%' },
|
{ name: 'last_contact_agent', display: 'Last contact (Agent)', type: 'time', null: true, style: 'width: 12%' },
|
||||||
{ name: 'last_contact_agent', display: 'Last contact (Agent)', tag: 'time', null: true, style: 'width: 12%' },
|
{ name: 'last_contact_customer', display: 'Last contact (Customer)', type: 'time', null: true, style: 'width: 12%' },
|
||||||
{ name: 'last_contact_customer', display: 'Last contact (Customer)', tag: 'time', null: true, style: 'width: 12%' },
|
{ name: 'first_response', display: 'First response', type: 'time', null: true, style: 'width: 12%' },
|
||||||
{ name: 'first_response', display: 'First response', tag: 'time', null: true, style: 'width: 12%' },
|
{ name: 'close_time', display: 'Close time', type: 'time', null: true, style: 'width: 12%' },
|
||||||
{ name: 'close_time', display: 'Close time', tag: 'time', null: true, style: 'width: 12%' },
|
{ name: 'escalation_time', display: 'Escalation in', type: 'time', null: true, style: 'width: 12%', class: 'escalation' },
|
||||||
{ name: 'escalation_time', display: 'Escalation in', tag: 'time', null: true, style: 'width: 12%' },
|
|
||||||
{ name: 'article_count', display: 'Article#', style: 'width: 12%' },
|
{ name: 'article_count', display: 'Article#', style: 'width: 12%' },
|
||||||
|
{ name: 'created_at', display: 'Created', type: 'time', style: 'width: 12%', readonly: 1 },
|
||||||
|
{ name: 'updated_at', display: 'Updated', type: 'time', style: 'width: 12%', readonly: 1 },
|
||||||
]
|
]
|
||||||
|
|
||||||
uiUrl: ->
|
uiUrl: ->
|
||||||
|
@ -41,6 +43,13 @@ class App.Ticket extends App.Model
|
||||||
else
|
else
|
||||||
data.customer = App.User.find( data.customer_id )
|
data.customer = App.User.find( data.customer_id )
|
||||||
|
|
||||||
|
# organization_id
|
||||||
|
if data.organization_id
|
||||||
|
if !App.Organization.exists( data.organization_id )
|
||||||
|
console.error("Can't find user for data.organization_id #{data.organization_id} for ticket #{data.id}")
|
||||||
|
else
|
||||||
|
data.organization = App.Organization.find( data.organization_id )
|
||||||
|
|
||||||
# owner
|
# owner
|
||||||
if data.owner_id
|
if data.owner_id
|
||||||
if !App.User.exists( data.owner_id )
|
if !App.User.exists( data.owner_id )
|
||||||
|
|
|
@ -2,3 +2,4 @@ class App.TicketArticleSender extends App.Model
|
||||||
@configure 'TicketArticleSender', 'name', 'updated_at'
|
@configure 'TicketArticleSender', 'name', 'updated_at'
|
||||||
@extend Spine.Model.Ajax
|
@extend Spine.Model.Ajax
|
||||||
@url: @apiPath + '/ticket_article_senders'
|
@url: @apiPath + '/ticket_article_senders'
|
||||||
|
@configure_translate = true
|
|
@ -2,3 +2,4 @@ class App.TicketArticleType extends App.Model
|
||||||
@configure 'TicketArticleType', 'name', 'updated_at'
|
@configure 'TicketArticleType', 'name', 'updated_at'
|
||||||
@extend Spine.Model.Ajax
|
@extend Spine.Model.Ajax
|
||||||
@url: @apiPath + '/ticket_article_types'
|
@url: @apiPath + '/ticket_article_types'
|
||||||
|
@configure_translate = true
|
|
@ -2,3 +2,13 @@ class App.TicketPriority extends App.Model
|
||||||
@configure 'TicketPriority', 'name', 'note', 'active', 'updated_at'
|
@configure 'TicketPriority', 'name', 'note', 'active', 'updated_at'
|
||||||
@extend Spine.Model.Ajax
|
@extend Spine.Model.Ajax
|
||||||
@url: @apiPath + '/ticket_priorities'
|
@url: @apiPath + '/ticket_priorities'
|
||||||
|
@configure_attributes = [
|
||||||
|
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, 'null': false, translate: true },
|
||||||
|
{ name: 'active', display: 'Active', tag: 'boolean', type: 'boolean', 'default': true, 'null': false },
|
||||||
|
{ name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 },
|
||||||
|
{ name: 'created_at', display: 'Created', type: 'time', readonly: 1 },
|
||||||
|
]
|
||||||
|
@configure_translate = true
|
||||||
|
@configure_overview = [
|
||||||
|
'name',
|
||||||
|
]
|
|
@ -2,3 +2,13 @@ class App.TicketState extends App.Model
|
||||||
@configure 'TicketState', 'name', 'note', 'active'
|
@configure 'TicketState', 'name', 'note', 'active'
|
||||||
@extend Spine.Model.Ajax
|
@extend Spine.Model.Ajax
|
||||||
@url: @apiPath + '/ticket_states'
|
@url: @apiPath + '/ticket_states'
|
||||||
|
@configure_attributes = [
|
||||||
|
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, 'null': false, translate: true },
|
||||||
|
{ name: 'active', display: 'Active', tag: 'boolean', type: 'boolean', 'default': true, 'null': false },
|
||||||
|
{ name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 },
|
||||||
|
{ name: 'created_at', display: 'Created', type: 'time', readonly: 1 },
|
||||||
|
]
|
||||||
|
@configure_translate = true
|
||||||
|
@configure_overview = [
|
||||||
|
'name',
|
||||||
|
]
|
|
@ -7,8 +7,8 @@
|
||||||
<% if @radio: %>
|
<% if @radio: %>
|
||||||
<th style="width: 22px"></th>
|
<th style="width: 22px"></th>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% for row in @header: %>
|
<% for item in @header: %>
|
||||||
<th <% if row.style: %>style="<%= row.style %>"<% end %>><%- @T( row.display ) %></th>
|
<th <% if item.style: %>style="<%= item.style %>"<% end %>><%- @T( item.display ) %></th>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if @destroy: %>
|
<% if @destroy: %>
|
||||||
<th class="span2"><%- @T('Delete') %></th>
|
<th class="span2"><%- @T('Delete') %></th>
|
||||||
|
@ -16,17 +16,25 @@
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
<% position = 0 %>
|
||||||
<% length = @header.length %>
|
<% length = @header.length %>
|
||||||
<% if @checkbox || @radio: %>
|
<% if @checkbox || @radio: %>
|
||||||
<% length++ %>
|
<% length++ %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% position = 0 %>
|
|
||||||
<% groupLast = '' %>
|
<% groupLast = '' %>
|
||||||
<% for object in @objects: %>
|
<% for object in @objects: %>
|
||||||
<% if @groupBy: %>
|
<% if @groupBy: %>
|
||||||
<% if groupLast isnt object[@groupBy.id]: %>
|
<% if object[@groupBy] && object[@groupBy].displayName: %>
|
||||||
<tr class=""><td colspan="<%= length %>"><b><%- @P( object[@groupBy.name] ) %></b></td></tr>
|
<% groupByName = object[@groupBy].displayName() %>
|
||||||
<% groupLast = object[@groupBy.id] %>
|
<% if object[@groupBy].translate(): %>
|
||||||
|
<% groupByName = @T(groupByName) %>
|
||||||
|
<% end %>
|
||||||
|
<% else: %>
|
||||||
|
<% groupByName = object[@groupBy] || '-' %>
|
||||||
|
<% end %>
|
||||||
|
<% if groupLast isnt groupByName: %>
|
||||||
|
<tr class=""><td colspan="<%= length %>"><b><%- @P( groupByName ) %></b></td></tr>
|
||||||
|
<% groupLast = groupByName %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% position++ %>
|
<% position++ %>
|
||||||
|
@ -37,33 +45,53 @@
|
||||||
<% if @radio: %>
|
<% if @radio: %>
|
||||||
<td><input type="radio" value="<%= object.id %>" name="radio"/></td>
|
<td><input type="radio" value="<%= object.id %>" name="radio"/></td>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% for row in @overview: %>
|
<% for item in @header: %>
|
||||||
<% displayName = @P( object[row.name], row ) %>
|
<% translation = false %>
|
||||||
<% if row.translate: %><% displayName = @T( displayName ) %><% end %>
|
<% value = object[item.name] %>
|
||||||
<% if row.title: %>
|
<% item_id = item.name.substr(item.name.length-3, item.name.length) %>
|
||||||
<% displayNameTitle = displayName %>
|
<% if item_id is '_id' && object[ item.name.substr(0, item.name.length-3) ]: %>
|
||||||
<% if object[row.title]: %>
|
<% value = object[ item.name.substr(0, item.name.length-3) ] %>
|
||||||
<% displayNameTitle = @P( object[row.title], row ) %>
|
<% refObject = object[ item.name.substr(0, item.name.length-3) ] %>
|
||||||
<% end %>
|
|
||||||
<% end %>
|
<% end %>
|
||||||
<td <% if row.title: %>title="<%= displayNameTitle %>"<% end %>>
|
<% if !value: %>
|
||||||
<% if row.type is 'link': %>
|
<% parts = item.name.split '::' %>
|
||||||
<a href="#" data-type="<%= row.dataType %>" <% if row.class: %>class="<%= row.class %>"<% end %>>
|
<% if parts[0] && parts[1] && object[ parts[0] ]: %>
|
||||||
<% else: %>
|
<% value = object[ parts[0] ][ parts[1] ] %>
|
||||||
<span <% if row.class: %>class="<%= row.class %>"<% end %> <% if row.data && row.data.id: %>data-id="<%= object[row.name].id %>"<% end %>>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if row.translate || row.callback: %><%- displayName %><% else: %><%= displayName %><% end %>
|
<% if value && value.displayNameLong : %>
|
||||||
<% if row.type is 'link': %></a><% else: %></span><% end %>
|
<% translation = true %>
|
||||||
|
<% value = value.displayNameLong() %>
|
||||||
|
<% else if value && value.displayName : %>
|
||||||
|
<% translation = true %>
|
||||||
|
<% value = value.displayName() %>
|
||||||
|
<% end %>
|
||||||
|
<% item_clone = item %>
|
||||||
|
<% if @callbacks: %>
|
||||||
|
<% for attribute, callbacksAll of @callbacks: %>
|
||||||
|
<% if attribute is item.name || attribute is item_id: %>
|
||||||
|
<% for callback in callbacksAll: %>
|
||||||
|
<% callback( value, object, item_clone, @header, refObject ) %>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
<% #console.log('HH', item_clone.name, item_clone.type, item_clone.translate, item_clone, object.translate(), refObject, translation) %>
|
||||||
|
<td>
|
||||||
|
<% if item_clone.link: %><a href="<%- item_clone.link %>"><% end %>
|
||||||
|
<% if item_clone.translate || ( translation && !refObject && object.translate && object.translate() ) || ( translation && refObject && refObject.translate && refObject.translate() ) : %>
|
||||||
|
<span <% if item_clone.class: %>class="<%= item_clone.class %>"<% end %>><%- @T( @P( value, item_clone ) ) %></span>
|
||||||
|
<% else if item_clone.type is 'time': %>
|
||||||
|
<span class="humanTimeFromNow <% if item_clone.class: %><%= item_clone.class %><% end %>" data-time="<%- object[item_clone.name] %>">?</span>
|
||||||
|
<% else: %>
|
||||||
|
<span <% if item_clone.class: %>class="<%= item_clone.class %>"<% end %> <% if item_clone.title: %>title="<%= item_clone.title %>"<% end %> <% if item_clone.data: %>data-id="<%= item_clone.data.id %><% end %>"><%= @P(value) %></span>
|
||||||
|
<% end %>
|
||||||
|
<% if item_clone.link: %></a><% end %>
|
||||||
</td>
|
</td>
|
||||||
<% end %>
|
<% end %>
|
||||||
<!--
|
<% if @destroy: %>
|
||||||
<td><%= object.updated_at %></td>
|
<td><a href="#" class="glyphicon glyphicon-trash" data-type="destroy"></a></td>
|
||||||
-->
|
<% end %>
|
||||||
<% if @destroy: %>
|
|
||||||
<td>
|
|
||||||
<a href="#" class="glyphicon glyphicon-trash" data-type="destroy"></a>
|
|
||||||
</td>
|
|
||||||
<% end %>
|
|
||||||
</tr>
|
</tr>
|
||||||
<% end %>
|
<% end %>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
@ -16,6 +16,13 @@ class TestsController < ApplicationController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# GET /tests/table
|
||||||
|
def table
|
||||||
|
respond_to do |format|
|
||||||
|
format.html # index.html.erb
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# GET /test/wait
|
# GET /test/wait
|
||||||
def wait
|
def wait
|
||||||
sleep params[:sec].to_i
|
sleep params[:sec].to_i
|
||||||
|
|
17
app/views/tests/table.html.erb
Normal file
17
app/views/tests/table.html.erb
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/assets/tests/qunit-1.10.0.css">
|
||||||
|
<script src="/assets/tests/qunit-1.10.0.js"></script>
|
||||||
|
<script src="/assets/tests/table.js"></script>
|
||||||
|
|
||||||
|
<style type="text/css">
|
||||||
|
body {
|
||||||
|
padding-top: 0px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div id="qunit"></div>
|
||||||
|
|
||||||
|
<div id="table"></div>
|
|
@ -2,6 +2,7 @@ Zammad::Application.routes.draw do
|
||||||
|
|
||||||
match '/tests-core', :to => 'tests#core', :via => :get
|
match '/tests-core', :to => 'tests#core', :via => :get
|
||||||
match '/tests-form', :to => 'tests#form', :via => :get
|
match '/tests-form', :to => 'tests#form', :via => :get
|
||||||
|
match '/tests-table', :to => 'tests#table', :via => :get
|
||||||
match '/tests/wait/:sec', :to => 'tests#wait', :via => :get
|
match '/tests/wait/:sec', :to => 'tests#wait', :via => :get
|
||||||
|
|
||||||
end
|
end
|
|
@ -1,7 +1,7 @@
|
||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
require 'browser_test_helper'
|
require 'browser_test_helper'
|
||||||
|
|
||||||
class UnitTest < TestCase
|
class AAbUnitTest < TestCase
|
||||||
def test_core
|
def test_core
|
||||||
tests = [
|
tests = [
|
||||||
{
|
{
|
Loading…
Reference in a new issue