Introduced new @P() to print values in templates based on attribute definition.

This commit is contained in:
Martin Edenhofer 2015-02-07 23:43:27 +01:00
parent 0d216b3bc6
commit 64794c3767
39 changed files with 409 additions and 247 deletions

View file

@ -369,7 +369,7 @@ class App.Controller extends Spine.Controller
userTicketPopups: (params) -> userTicketPopups: (params) ->
show = (data, tickets) => show = (data, ticket_list) =>
if !data.position if !data.position
data.position = 'left' data.position = 'left'
@ -390,15 +390,14 @@ class App.Controller extends Spine.Controller
content: -> content: ->
type = $(@).filter('[data-type]').data('type') type = $(@).filter('[data-type]').data('type')
data = tickets[type] || [] tickets = []
if ticket_list[type]
# set human time for ticket_id in ticket_list[type]
for ticket in data tickets.push App.Ticket.fullLocal( ticket_id )
ticket.humanTime = controller.humanTime(ticket.created_at)
# insert data # insert data
App.view('popover/user_ticket_list')( App.view('popover/user_ticket_list')(
tickets: data, tickets: tickets,
) )
) )
@ -411,14 +410,18 @@ class App.Controller extends Spine.Controller
} }
processData: true, processData: true,
success: (data, status, xhr) => success: (data, status, xhr) =>
App.Store.write( "user-ticket-popover::#{params.user_id}", data.tickets ) App.Store.write( "user-ticket-popover::#{params.user_id}", data )
show( params, data.tickets )
# load assets
App.Collection.loadAssets( data.assets )
show( params, { open: data.ticket_ids_open, closed: data.ticket_ids_closed } )
) )
# get data # get data
tickets = App.Store.get( "user-ticket-popover::#{params.user_id}" ) data = App.Store.get( "user-ticket-popover::#{params.user_id}" )
if tickets if data
show( params, tickets ) show( params, { open: data.ticket_ids_open, closed: data.ticket_ids_closed } )
@delay( @delay(
=> =>
fetch(params) fetch(params)

View file

@ -82,7 +82,7 @@ class App.ControllerTable extends App.Controller
el: element el: element
overview: ['time', 'area', 'level', 'browser', 'location', 'data'] overview: ['time', 'area', 'level', 'browser', 'location', 'data']
attributes: [ attributes: [
{ name: 'time', display: 'Time', type: 'time' }, { name: 'time', display: 'Time', tag: 'datetime' },
{ name: 'area', display: 'Area', type: 'text' }, { name: 'area', display: 'Area', type: 'text' },
{ name: 'level', display: 'Level', type: 'text' }, { name: 'level', display: 'Level', type: 'text' },
{ name: 'browser', display: 'Browser', type: 'text' }, { name: 'browser', display: 'Browser', type: 'text' },

View file

@ -156,11 +156,8 @@ class App.Navigation extends App.Controller
area.result = [] area.result = []
for id in area.ids for id in area.ids
ticket = App.Ticket.find( id ) ticket = App.Ticket.find( id )
ticket.humanTime = @humanTime(ticket.created_at)
data = data =
display: "##{ticket.number} - #{ticket.title}" display: "##{ticket.number} - #{ticket.title}"
createt_at: "#{ticket.created_at}"
humanTime: "#{ticket.humanTime}"
id: ticket.id id: ticket.id
class: "task level-1 ticket-popover" class: "task level-1 ticket-popover"
url: ticket.uiUrl() url: ticket.uiUrl()

View file

@ -10,29 +10,111 @@
#= require_tree ./lib/app_post #= require_tree ./lib/app_post
class App extends Spine.Controller class App extends Spine.Controller
@viewPrint: (object, attribute_name) ->
attributes = {}
if object.constructor.attributesGet
attributes = object.constructor.attributesGet()
attribute_config = attributes[attribute_name]
value = object[attribute_name]
valueRef = undefined
# check if relation is requested
if !attribute_config
attribute_name_new = "#{attribute_name}_id"
attribute_config = attributes[attribute_name_new]
if attribute_config
attribute_name = attribute_name_new
if object[attribute_name]
valueRef = value
value = object[attribute_name]
# in case of :: key, get the sub value
if !value
parts = attribute_name.split('::')
if parts[0] && parts[1] && object[ parts[0] ]
value = object[ parts[0] ][ parts[1] ]
#console.log('Pa', attribute_name, object, attribute_config, object[attribute_name], valueRef, value)
# if we have no config, get output this way
if !attribute_config
return @viewPrintItem( value )
# check if valueRef already exists, no lookup needed later
if !valueRef
attribute_name_without_ref = attribute_name.substr(attribute_name.length-3, attribute_name.length)
if attribute_name_without_ref is '_id'
attribute_name_without_ref = attribute_name.substr(0, attribute_name.length-3)
if object[attribute_name_without_ref]
valueRef = object[attribute_name_without_ref]
return @viewPrintItem( value, attribute_config, valueRef )
# define print name helper
@viewPrintItem: ( item, attribute_config = {}, valueRef ) ->
return '-' if item is undefined
return '-' if item is ''
return item if !item
result = item
# lookup relation
if attribute_config.relation || valueRef
if valueRef
item = valueRef
else
item = App[attribute_config.relation].find(item)
# if date is a object, get name of the object
isObject = false
if typeof item is 'object'
isObject = true
if item.displayNameLong
result = item.displayNameLong()
else if item.displayName
result = item.displayName()
else
result = item.name
# execute callback on content
if attribute_config.callback
result = attribute_config.callback( result, attribute_config )
# text2html in textarea view
if attribute_config.tag is 'textarea'
result = App.Utils.text2html( result )
# fillup options
if !_.isEmpty(attribute_config.options)
if attribute_config.options[result]
result = attribute_config.options[result]
# translate content
isTranslated = false
if attribute_config.translate || ( isObject && item.translate && item.translate() )
isTranslated = true
result = App.i18n.translateContent( result )
# transform date
if attribute_config.tag is 'date'
result = App.i18n.translateDate(result)
# use pretty time for datetime
else if attribute_config.tag is 'datetime'
result = "<span class=\"humanTimeFromNow #{attribute_config.class}\" data-time=\"#{result}\">?</span>"
#result = App.i18n.translateTimestamp(result)
else if !isTranslated
if typeof result is 'string'
result = App.Utils.htmlEscape(result)
result
@view: (name) -> @view: (name) ->
template = ( params = {} ) => template = ( params = {} ) =>
# define print name helper # define print name helper
params.P = ( item, row = {} ) -> params.P = ( object, attribute_name ) ->
return '-' if item is undefined App.viewPrint( object, attribute_name )
return '-' if item is ''
return item if !item
# if date is a object, get name of the object
if typeof item is 'object'
if item.displayNameLong
return item.displayNameLong()
else if item.displayName
return item.displayName()
return item.name
# execute callback on content
if row.callback
return row.callback( item, row )
# return raw data
item
# define date format helper # define date format helper
params.date = ( time ) -> params.date = ( time ) ->

View file

@ -4,11 +4,11 @@ class App.EmailAddress extends App.Model
@url: @apiPath + '/email_addresses' @url: @apiPath + '/email_addresses'
@configure_attributes = [ @configure_attributes = [
{ name: 'realname', display: 'Realname', tag: 'input', type: 'text', limit: 250, 'null': false, 'class': 'span4' }, { name: 'realname', display: 'Realname', tag: 'input', type: 'text', limit: 250, null: false },
{ name: 'email', display: 'Email', tag: 'input', type: 'text', limit: 250, 'null': false, 'class': 'span4' }, { name: 'email', display: 'Email', tag: 'input', type: 'text', limit: 250, null: false },
{ name: 'note', display: 'Note', tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, 'null': true, 'class': 'span4' }, { name: 'note', display: 'Note', tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, null: true },
{ name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 }, { name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 },
{ name: 'active', display: 'Active', tag: 'boolean', type: 'boolean', 'default': true, 'null': false, 'class': 'span4' }, { name: 'active', display: 'Active', tag: 'boolean', type: 'boolean', default: true, null: false },
] ]
@configure_overview = [ @configure_overview = [
'realname', 'email' 'realname', 'email'

View file

@ -4,15 +4,15 @@ class App.Group extends App.Model
@url: @apiPath + '/groups' @url: @apiPath + '/groups'
@configure_attributes = [ @configure_attributes = [
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, 'null': false, 'class': 'span4' }, { name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, null: false },
{ name: 'assignment_timeout', display: 'Assignment Timeout', tag: 'input', note: 'Assignment timeout in minutes if assigned agent is not working on it. Ticket will be shown as unassigend.', type: 'text', limit: 100, 'null': true, 'class': 'span4' }, { name: 'assignment_timeout', display: 'Assignment Timeout', tag: 'input', note: 'Assignment timeout in minutes if assigned agent is not working on it. Ticket will be shown as unassigend.', type: 'text', limit: 100, null: true },
{ name: 'follow_up_possible', display: 'Follow up possible',tag: 'select', default: 'yes', options: { yes: 'yes', reject: 'reject follow up/do not reopen Ticket', 'new_ticket': 'do not reopen Ticket but create new Ticket' }, 'null': false, note: 'Follow up for closed ticket possible or not.', 'class': 'span4' }, { name: 'follow_up_possible', display: 'Follow up possible',tag: 'select', default: 'yes', options: { yes: 'yes', reject: 'reject follow up/do not reopen Ticket', 'new_ticket': 'do not reopen Ticket but create new Ticket' }, null: false, note: 'Follow up for closed ticket possible or not.' },
{ name: 'follow_up_assignment', display: 'Assign Follow Ups', tag: 'select', default: 'yes', options: { true: 'yes', false: 'no' }, 'null': false, note: 'Assign follow up to latest agent again.', 'class': 'span4' }, { name: 'follow_up_assignment', display: 'Assign Follow Ups', tag: 'select', default: 'yes', options: { true: 'yes', false: 'no' }, 'null': false, note: 'Assign follow up to latest agent again.' },
{ name: 'email_address_id', display: 'Email', tag: 'select', multiple: false, null: true, relation: 'EmailAddress', nulloption: true, class: 'span4' }, { name: 'email_address_id', display: 'Email', tag: 'select', multiple: false, null: true, relation: 'EmailAddress', nulloption: true },
{ name: 'signature_id', display: 'Signature', tag: 'select', multiple: false, null: true, relation: 'Signature', nulloption: true, class: 'span4' }, { name: 'signature_id', display: 'Signature', tag: 'select', multiple: false, null: true, relation: 'Signature', nulloption: true },
{ name: 'note', display: 'Note', tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, 'null': true, 'class': 'span4' }, { name: 'note', display: 'Note', tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, null: true },
{ name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 }, { name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 },
{ name: 'active', display: 'Active', tag: 'boolean', type: 'boolean', 'default': true, 'null': false, 'class': 'span4' }, { name: 'active', display: 'Active', tag: 'boolean', type: 'boolean', default: true, null: false },
] ]
@configure_overview = [ @configure_overview = [
'name', 'name',

View file

@ -8,15 +8,15 @@ class App.Job extends App.Model
{ name: 'condition', display: 'Conditions for matching objects.', tag: 'ticket_attribute_selection', null: true }, { name: 'condition', display: 'Conditions for matching objects.', tag: 'ticket_attribute_selection', null: true },
{ name: 'execute', display: 'Execute changes on objects.', tag: 'ticket_attribute_set', null: true }, { name: 'execute', display: 'Execute changes on objects.', tag: 'ticket_attribute_set', null: true },
{ name: 'note', display: 'Note', tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, null: true }, { name: 'note', display: 'Note', tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, null: true },
{ name: 'active', display: 'Active', tag: 'boolean', note: 'boolean', 'default': true, null: false }, { name: 'active', display: 'Active', tag: 'boolean', note: 'boolean', default: true, null: false },
{ name: 'matching', display: 'Matching', readonly: 1 }, { name: 'matching', display: 'Matching', readonly: 1 },
{ name: 'processed', display: 'Processed', readonly: 1 }, { name: 'processed', display: 'Processed', readonly: 1 },
{ name: 'last_run_at', display: 'Last run', type: 'time', readonly: 1 }, { name: 'last_run_at', display: 'Last run', tag: 'datetime', readonly: 1 },
{ name: 'running', display: 'Running', tag: 'boolean', readonly: 1 }, { name: 'running', display: 'Running', tag: 'boolean', readonly: 1 },
{ name: 'created_by_id', display: 'Created by', relation: 'User', readonly: 1 }, { name: 'created_by_id', display: 'Created by', relation: 'User', readonly: 1 },
{ name: 'created_at', display: 'Created', type: 'time', readonly: 1 }, { name: 'created_at', display: 'Created', tag: 'datetime', readonly: 1 },
{ name: 'updated_by_id', display: 'Updated by', relation: 'User', readonly: 1 }, { name: 'updated_by_id', display: 'Updated by', relation: 'User', readonly: 1 },
{ name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 }, { name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 },
] ]
@configure_delete = true @configure_delete = true
@configure_overview = [ @configure_overview = [

View file

@ -2,8 +2,8 @@ class App.Network extends App.Model
@configure 'Network', 'name', 'note', 'active', 'updated_at' @configure 'Network', 'name', 'note', 'active', 'updated_at'
@extend Spine.Model.Ajax @extend Spine.Model.Ajax
@configure_attributes = [ @configure_attributes = [
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, 'null': false, 'class': 'xlarge' }, { name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, null: false },
{ name: 'note', display: 'Note', note: 'Notes are visible to agents only, never to customers.', tag: 'textarea', limit: 250, 'null': true, 'class': 'xlarge' }, { name: 'note', display: 'Note', note: 'Notes are visible to agents only, never to customers.', tag: 'textarea', limit: 250, null: true },
{ name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 }, { name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 },
{ name: 'active', display: 'Active', tag: 'boolean', type: 'boolean', 'default': true, 'null': false, 'class': 'xlarge' }, { name: 'active', display: 'Active', tag: 'boolean', type: 'boolean', default: true, null: false },
] ]

View file

@ -3,13 +3,13 @@ class App.ObjectManagerAttribute extends App.Model
@extend Spine.Model.Ajax @extend Spine.Model.Ajax
@url: @apiPath + '/object_manager_attributes' @url: @apiPath + '/object_manager_attributes'
@configure_attributes = [ @configure_attributes = [
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, 'null': false }, { name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, null: false },
{ name: 'display', display: 'Anzeige', tag: 'input', type: 'text', limit: 100, 'null': false }, { name: 'display', display: 'Anzeige', tag: 'input', type: 'text', limit: 100, null: false },
{ name: 'object', display: 'Object', tag: 'input', readonly: 1 }, { name: 'object', display: 'Object', tag: 'input', readonly: 1 },
{ name: 'position', display: 'Position', tag: 'input', readonly: 1 }, { name: 'position', display: 'Position', tag: 'input', readonly: 1 },
{ name: 'active', display: 'Active', tag: 'boolean', 'default': true, 'null': false }, { name: 'active', display: 'Active', tag: 'boolean', default: true, null: false },
{ name: 'data_type', display: 'Format', tag: 'input', type: 'text', limit: 100, 'null': false }, { name: 'data_type', display: 'Format', tag: 'input', type: 'text', limit: 100, null: false },
{ name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 }, { name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 },
] ]
@configure_overview = [ @configure_overview = [
#'name', #'name',

View file

@ -3,11 +3,11 @@ class App.Organization extends App.Model
@extend Spine.Model.Ajax @extend Spine.Model.Ajax
@url: @apiPath + '/organizations' @url: @apiPath + '/organizations'
@configure_attributes = [ @configure_attributes = [
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, 'null': false, info: true }, { name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, null: false, info: true },
{ name: 'shared', display: 'Shared organization', tag: 'boolean', note: 'Customers in the organization can view each other items.', type: 'boolean', 'default': true, 'null': false, info: false }, { name: 'shared', display: 'Shared organization', tag: 'boolean', note: 'Customers in the organization can view each other items.', type: 'boolean', default: true, null: false, info: false },
{ name: 'note', display: 'Note', tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, 'null': true, info: true }, { name: 'note', display: 'Note', tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, null: true, info: true },
{ name: 'updated_at', display: 'Updated', type: 'time', readonly: 1, info: false }, { name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1, info: false },
{ name: 'active', display: 'Active', tag: 'boolean', 'default': true, 'null': false, info: false }, { name: 'active', display: 'Active', tag: 'boolean', default: true, null: false, info: false },
] ]
@configure_overview = [ @configure_overview = [
'name', 'name',

View file

@ -131,11 +131,11 @@ class App.Overview extends App.Model
owner: 'Owner' owner: 'Owner'
class: 'span4' class: 'span4'
}, },
{ name: 'active', display: 'Active', tag: 'boolean', note: 'boolean', 'default': true, 'null': false, 'class': 'span4' }, { name: 'active', display: 'Active', tag: 'boolean', note: 'boolean', default: true, null: false },
{ name: 'created_by_id', display: 'Created by', relation: 'User', readonly: 1 }, { name: 'created_by_id', display: 'Created by', relation: 'User', readonly: 1 },
{ name: 'created_at', display: 'Created', type: 'time', readonly: 1 }, { name: 'created_at', display: 'Created', tag: 'datetime', readonly: 1 },
{ name: 'updated_by_id', display: 'Updated by', relation: 'User', readonly: 1 }, { name: 'updated_by_id', display: 'Updated by', relation: 'User', readonly: 1 },
{ name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 }, { name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 },
] ]
@configure_delete = true @configure_delete = true
@configure_overview = [ @configure_overview = [

View file

@ -8,13 +8,13 @@ class App.PostmasterFilter extends App.Model
{ name: 'channel', display: 'Channel', type: 'input', readonly: 1 }, { name: 'channel', display: 'Channel', type: 'input', readonly: 1 },
{ name: 'match', display: 'Match all of the following', tag: 'postmaster_match' }, { name: 'match', display: 'Match all of the following', tag: 'postmaster_match' },
{ name: 'perform', display: 'Perform action of the following', tag: 'postmaster_set' }, { name: 'perform', display: 'Perform action of the following', tag: 'postmaster_set' },
{ name: 'note', display: 'Note', tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, 'null': true }, { name: 'note', display: 'Note', tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, null: true },
{ name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 }, { name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 },
{ name: 'active', display: 'Active', tag: 'boolean', type: 'boolean', 'default': true, 'null': false }, { name: 'active', display: 'Active', tag: 'boolean', type: 'boolean', default: true, null: false },
{ name: 'created_by_id', display: 'Created by', relation: 'User', readonly: 1 }, { name: 'created_by_id', display: 'Created by', relation: 'User', readonly: 1 },
{ name: 'created_at', display: 'Created', type: 'time', readonly: 1 }, { name: 'created_at', display: 'Created', tag: 'datetime', readonly: 1 },
{ name: 'updated_by_id', display: 'Updated by', relation: 'User', readonly: 1 }, { name: 'updated_by_id', display: 'Updated by', relation: 'User', readonly: 1 },
{ name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 }, { name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 },
] ]
@configure_delete = true @configure_delete = true
@configure_overview = [ @configure_overview = [

View file

@ -3,13 +3,13 @@ class App.Role extends App.Model
@extend Spine.Model.Ajax @extend Spine.Model.Ajax
@url: @apiPath + '/roles' @url: @apiPath + '/roles'
@configure_attributes = [ @configure_attributes = [
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, null: false }, { name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, null: false },
{ name: 'note', display: 'Note', tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, null: true }, { name: 'note', display: 'Note', tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, null: true },
{ name: 'active', display: 'Active', tag: 'boolean', type: 'boolean', 'default': true, null: false }, { name: 'active', display: 'Active', tag: 'boolean', type: 'boolean', 'default': true, null: false },
{ name: 'created_by_id', display: 'Created by', relation: 'User', readonly: 1 }, { name: 'created_by_id', display: 'Created by', relation: 'User', readonly: 1 },
{ name: 'created_at', display: 'Created', type: 'time', readonly: 1 }, { name: 'created_at', display: 'Created', tag: 'datetime', readonly: 1 },
{ name: 'updated_by_id', display: 'Updated by', relation: 'User', readonly: 1 }, { name: 'updated_by_id', display: 'Updated by', relation: 'User', readonly: 1 },
{ name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 }, { name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 },
] ]
@configure_overview = [ @configure_overview = [
'name', 'name',

View file

@ -4,14 +4,14 @@ class App.Signature extends App.Model
@url: @apiPath + '/signatures' @url: @apiPath + '/signatures'
@configure_attributes = [ @configure_attributes = [
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, 'null': false, 'class': 'span4' }, { name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, 'null': false },
{ name: 'body', display: 'Text', tag: 'textarea', limit: 250, 'null': true, 'class': 'span4', rows: 10 }, { name: 'body', display: 'Text', tag: 'textarea', limit: 250, 'null': true, rows: 10 },
{ name: 'note', display: 'Note', tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, 'null': true, 'class': 'span4' }, { name: 'note', display: 'Note', tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, 'null': true },
{ name: 'active', display: 'Active', tag: 'boolean', type: 'boolean', 'default': true, 'null': false, 'class': 'span4' }, { name: 'active', display: 'Active', tag: 'boolean', type: 'boolean', 'default': true, 'null': false },
{ name: 'created_by_id', display: 'Created by', relation: 'User', readonly: 1 }, { name: 'created_by_id', display: 'Created by', relation: 'User', readonly: 1 },
{ name: 'created_at', display: 'Created', type: 'time', readonly: 1 }, { name: 'created_at', display: 'Created', tag: 'datetime', readonly: 1 },
{ name: 'updated_by_id', display: 'Updated by', relation: 'User', readonly: 1 }, { name: 'updated_by_id', display: 'Updated by', relation: 'User', readonly: 1 },
{ name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 }, { name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 },
] ]
@configure_overview = [ @configure_overview = [
'name', 'name',

View file

@ -31,11 +31,11 @@ class App.Sla extends App.Model
group: 'Group' group: 'Group'
owner: 'Owner' owner: 'Owner'
}, },
{ name: 'active', display: 'Active', tag: 'boolean', note: 'boolean', 'default': true, 'null': false }, { name: 'active', display: 'Active', tag: 'boolean', note: 'boolean', default: true, null: false },
{ name: 'created_by_id', display: 'Created by', relation: 'User', readonly: 1 }, { name: 'created_by_id', display: 'Created by', relation: 'User', readonly: 1 },
{ name: 'created_at', display: 'Created', type: 'time', readonly: 1 }, { name: 'created_at', display: 'Created', tag: 'datetime', readonly: 1 },
{ name: 'updated_by_id', display: 'Updated by', relation: 'User', readonly: 1 }, { name: 'updated_by_id', display: 'Updated by', relation: 'User', readonly: 1 },
{ name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 }, { name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 },
] ]
@configure_delete = true @configure_delete = true
@configure_overview = [ @configure_overview = [

View file

@ -3,11 +3,11 @@ class App.TextModule extends App.Model
@extend Spine.Model.Ajax @extend Spine.Model.Ajax
@url: @apiPath + '/text_modules' @url: @apiPath + '/text_modules'
@configure_attributes = [ @configure_attributes = [
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, 'null': false, 'class': 'span4' }, { name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, 'null': false, 'class': 'span4' },
{ name: 'keywords', display: 'Keywords', tag: 'input', type: 'text', limit: 100, 'null': true, 'class': 'span4' }, { name: 'keywords', display: 'Keywords', tag: 'input', type: 'text', limit: 100, 'null': true, 'class': 'span4' },
{ name: 'content', display: 'Content', tag: 'textarea', limit: 250, 'null': false, 'class': 'span4' }, { name: 'content', display: 'Content', tag: 'textarea', limit: 250, 'null': false, 'class': 'span4' },
{ name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 }, { name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 },
{ name: 'active', display: 'Active', tag: 'boolean', note: 'boolean', 'default': true, 'null': false, 'class': 'span4' }, { name: 'active', display: 'Active', tag: 'boolean', note: 'boolean', 'default': true, 'null': false, 'class': 'span4' },
] ]
@configure_delete = true @configure_delete = true
@configure_overview = [ @configure_overview = [

View file

@ -11,18 +11,18 @@ class App.Ticket extends App.Model
{ name: 'title', display: 'Title', tag: 'input', type: 'text', limit: 100, null: false, parentClass: 'noTruncate' }, { name: 'title', display: 'Title', tag: 'input', type: 'text', limit: 100, null: false, parentClass: 'noTruncate' },
{ name: 'state_id', display: 'State', tag: 'select', multiple: false, null: false, relation: 'TicketState', default: 'new', style: 'width: 12%', edit: true, customer: true, }, { name: 'state_id', display: 'State', tag: 'select', multiple: false, null: false, relation: 'TicketState', default: 'new', style: 'width: 12%', edit: true, customer: true, },
{ name: 'priority_id', display: 'Priority', tag: 'select', multiple: false, null: false, relation: 'TicketPriority', default: '2 normal', style: 'width: 12%', edit: true, customer: true, }, { name: 'priority_id', display: 'Priority', tag: 'select', multiple: false, null: false, relation: 'TicketPriority', default: '2 normal', style: 'width: 12%', edit: true, customer: true, },
{ name: 'last_contact', display: 'Last contact', type: 'time', null: true, style: 'width: 12%', parentClass: 'noTruncate' }, { name: 'last_contact', display: 'Last contact', tag: 'datetime', null: true, style: 'width: 12%', parentClass: 'noTruncate' },
{ name: 'last_contact_agent', display: 'Last contact (Agent)', type: 'time', null: true, style: 'width: 12%', parentClass: 'noTruncate' }, { name: 'last_contact_agent', display: 'Last contact (Agent)', tag: 'datetime', null: true, style: 'width: 12%', parentClass: 'noTruncate' },
{ name: 'last_contact_customer', display: 'Last contact (Customer)', type: 'time', null: true, style: 'width: 12%', parentClass: 'noTruncate' }, { name: 'last_contact_customer', display: 'Last contact (Customer)', tag: 'datetime', null: true, style: 'width: 12%', parentClass: 'noTruncate' },
{ name: 'first_response', display: 'First response', type: 'time', null: true, style: 'width: 12%', parentClass: 'noTruncate' }, { name: 'first_response', display: 'First response', tag: 'datetime', null: true, style: 'width: 12%', parentClass: 'noTruncate' },
{ name: 'close_time', display: 'Close time', type: 'time', null: true, style: 'width: 12%', parentClass: 'noTruncate' }, { name: 'close_time', display: 'Close time', tag: 'datetime', null: true, style: 'width: 12%', parentClass: 'noTruncate' },
{ name: 'pending_time', display: 'Pending Time', type: 'time', null: true, style: 'width: 12%', parentClass: 'noTruncate' }, { name: 'pending_time', display: 'Pending Time', tag: 'datetime', null: true, style: 'width: 12%', parentClass: 'noTruncate' },
{ name: 'escalation_time', display: 'Escalation', type: 'time', null: true, style: 'width: 12%', class: 'escalation', parentClass: 'noTruncate' }, { name: 'escalation_time', display: 'Escalation', tag: 'datetime', null: true, style: 'width: 12%', class: 'escalation', parentClass: 'noTruncate' },
{ name: 'article_count', display: 'Article#', style: 'width: 12%' }, { name: 'article_count', display: 'Article#', style: 'width: 12%' },
{ name: 'created_by_id', display: 'Created by', relation: 'User', readonly: 1 }, { name: 'created_by_id', display: 'Created by', relation: 'User', readonly: 1 },
{ name: 'created_at', display: 'Created', type: 'time', style: 'width: 120px', readonly: 1, parentClass: 'noTruncate' }, { name: 'created_at', display: 'Created', tag: 'datetime', style: 'width: 120px', readonly: 1, parentClass: 'noTruncate' },
{ name: 'updated_by_id', display: 'Updated by', relation: 'User', readonly: 1 }, { name: 'updated_by_id', display: 'Updated by', relation: 'User', readonly: 1 },
{ name: 'updated_at', display: 'Updated', type: 'time', style: 'width: 120px', readonly: 1, parentClass: 'noTruncate' }, { name: 'updated_at', display: 'Updated', tag: 'datetime', style: 'width: 120px', readonly: 1, parentClass: 'noTruncate' },
] ]
uiUrl: -> uiUrl: ->

View file

@ -3,19 +3,19 @@ class App.TicketArticle extends App.Model
@extend Spine.Model.Ajax @extend Spine.Model.Ajax
@url: @apiPath + '/ticket_articles' @url: @apiPath + '/ticket_articles'
@configure_attributes = [ @configure_attributes = [
{ name: 'ticket_id', display: 'TicketID', null: false, readonly: 1, }, { name: 'ticket_id', display: 'TicketID', null: false, readonly: 1, },
{ name: 'from', display: 'From', tag: 'input', type: 'text', limit: 100, null: false, }, { name: 'from', display: 'From', tag: 'input', type: 'text', limit: 100, null: false },
{ name: 'to', display: 'To', tag: 'input', type: 'text', limit: 100, null: true, }, { name: 'to', display: 'To', tag: 'input', type: 'text', limit: 100, null: true },
{ name: 'cc', display: 'Cc', tag: 'input', type: 'text', limit: 100, null: true, }, { name: 'cc', display: 'Cc', tag: 'input', type: 'text', limit: 100, null: true },
{ name: 'subject', display: 'Subject', tag: 'input', type: 'text', limit: 100, null: true, }, { name: 'subject', display: 'Subject', tag: 'input', type: 'text', limit: 100, null: true },
{ name: 'body', display: 'Text', tag: 'textarea', rows: 5, limit: 100, null: false, }, { name: 'body', display: 'Text', tag: 'textarea', rows: 5, limit: 100, null: false },
{ name: 'type_id', display: 'Type', tag: 'select', multiple: false, null: false, relation: 'TicketArticleType', default: '', class: 'medium' }, { name: 'type_id', display: 'Type', tag: 'select', multiple: false, null: false, relation: 'TicketArticleType', default: '' },
{ name: 'sender_id', display: 'Sender', tag: 'select', multiple: false, null: false, relation: 'TicketArticleSender', default: '', class: 'medium' }, { name: 'sender_id', display: 'Sender', tag: 'select', multiple: false, null: false, relation: 'TicketArticleSender', default: '' },
{ name: 'internal', display: 'Visibility', tag: 'radio', default: false, null: true, options: { true: 'internal', false: 'public' }, class: 'medium' }, { name: 'internal', display: 'Visibility', tag: 'radio', default: false, null: true, options: { true: 'internal', false: 'public' } },
{ name: 'created_by_id', display: 'Created by', relation: 'User', readonly: 1 }, { name: 'created_by_id', display: 'Created by', relation: 'User', readonly: 1 },
{ name: 'created_at', display: 'Created', type: 'time', readonly: 1 }, { name: 'created_at', display: 'Created', tag: 'datetime', readonly: 1 },
{ name: 'updated_by_id', display: 'Updated by', relation: 'User', readonly: 1 }, { name: 'updated_by_id', display: 'Updated by', relation: 'User', readonly: 1 },
{ name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 }, { name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 },
] ]
uiUrl: -> uiUrl: ->

View file

@ -3,10 +3,10 @@ class App.TicketPriority extends App.Model
@extend Spine.Model.Ajax @extend Spine.Model.Ajax
@url: @apiPath + '/ticket_priorities' @url: @apiPath + '/ticket_priorities'
@configure_attributes = [ @configure_attributes = [
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, 'null': false, translate: true }, { 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: 'active', display: 'Active', tag: 'boolean', type: 'boolean', default: true, null: false },
{ name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 }, { name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 },
{ name: 'created_at', display: 'Created', type: 'time', readonly: 1 }, { name: 'created_at', display: 'Created', tag: 'datetime', readonly: 1 },
] ]
@configure_translate = true @configure_translate = true
@configure_overview = [ @configure_overview = [

View file

@ -3,10 +3,10 @@ class App.TicketState extends App.Model
@extend Spine.Model.Ajax @extend Spine.Model.Ajax
@url: @apiPath + '/ticket_states' @url: @apiPath + '/ticket_states'
@configure_attributes = [ @configure_attributes = [
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, 'null': false, translate: true }, { 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: 'active', display: 'Active', tag: 'boolean', type: 'boolean', default: true, null: false },
{ name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 }, { name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 },
{ name: 'created_at', display: 'Created', type: 'time', readonly: 1 }, { name: 'created_at', display: 'Created', tag: 'datetime', readonly: 1 },
] ]
@configure_translate = true @configure_translate = true
@configure_overview = [ @configure_overview = [

View file

@ -5,25 +5,25 @@ class App.User extends App.Model
# @hasMany 'roles', 'App.Role' # @hasMany 'roles', 'App.Role'
@configure_attributes = [ @configure_attributes = [
{ name: 'login', display: 'Login', tag: 'input', type: 'text', limit: 100, null: false, class: 'span4', autocapitalize: false, signup: false, quick: false }, { name: 'login', display: 'Login', tag: 'input', type: 'text', limit: 100, null: false, autocapitalize: false, signup: false, quick: false },
{ name: 'firstname', display: 'Firstname', tag: 'input', type: 'text', limit: 100, null: false, class: 'span4', signup: true, info: true, invite_agent: true }, { name: 'firstname', display: 'Firstname', tag: 'input', type: 'text', limit: 100, null: false, signup: true, info: true, invite_agent: true },
{ name: 'lastname', display: 'Lastname', tag: 'input', type: 'text', limit: 100, null: false, class: 'span4', signup: true, info: true, invite_agent: true }, { name: 'lastname', display: 'Lastname', tag: 'input', type: 'text', limit: 100, null: false, signup: true, info: true, invite_agent: true },
{ name: 'email', display: 'Email', tag: 'input', type: 'email', limit: 100, null: false, class: 'span4', signup: true, info: true, invite_agent: true }, { name: 'email', display: 'Email', tag: 'input', type: 'email', limit: 100, null: false, signup: true, info: true, invite_agent: true },
{ name: 'web', display: 'Web', tag: 'input', type: 'url', limit: 100, null: true, class: 'span4', signup: false, info: true }, { name: 'web', display: 'Web', tag: 'input', type: 'url', limit: 100, null: true, signup: false, info: true },
{ name: 'phone', display: 'Phone', tag: 'input', type: 'phone', limit: 100, null: true, class: 'span4', signup: false, info: true }, { name: 'phone', display: 'Phone', tag: 'input', type: 'phone', limit: 100, null: true, signup: false, info: true },
{ name: 'mobile', display: 'Mobile', tag: 'input', type: 'phone', limit: 100, null: true, class: 'span4', signup: false, info: true }, { name: 'mobile', display: 'Mobile', tag: 'input', type: 'phone', limit: 100, null: true, signup: false, info: true },
{ name: 'fax', display: 'Fax', tag: 'input', type: 'phone', limit: 100, null: true, class: 'span4', signup: false, info: true }, { name: 'fax', display: 'Fax', tag: 'input', type: 'phone', limit: 100, null: true, signup: false, info: true },
{ name: 'organization_id', display: 'Organization', tag: 'select', multiple: false, nulloption: true, null: true, relation: 'Organization', class: 'span4', signup: false, info: true }, { name: 'organization_id', display: 'Organization', tag: 'select', multiple: false, nulloption: true, null: true, relation: 'Organization', signup: false, info: true },
{ name: 'department', display: 'Department', tag: 'input', type: 'text', limit: 200, null: true, class: 'span4', signup: false, info: true }, { name: 'department', display: 'Department', tag: 'input', type: 'text', limit: 200, null: true, signup: false, info: true },
{ name: 'street', display: 'Street', tag: 'input', type: 'text', limit: 100, null: true, class: 'span4', signup: false, info: true }, { name: 'street', display: 'Street', tag: 'input', type: 'text', limit: 100, null: true, signup: false, info: true },
{ name: 'zip', display: 'Zip', tag: 'input', type: 'text', limit: 100, null: true, class: 'span4', signup: false, info: true }, { name: 'zip', display: 'Zip', tag: 'input', type: 'text', limit: 100, null: true, signup: false, info: true },
{ name: 'city', display: 'City', tag: 'input', type: 'text', limit: 100, null: true, class: 'span4', signup: false, info: true }, { name: 'city', display: 'City', tag: 'input', type: 'text', limit: 100, null: true, signup: false, info: true },
{ name: 'password', display: 'Password', tag: 'input', type: 'password', limit: 50, null: true, autocomplete: 'off', class: 'span4', signup: true, }, { name: 'password', display: 'Password', tag: 'input', type: 'password', limit: 50, null: true, autocomplete: 'off', signup: true, },
{ name: 'note', display: 'Note', tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, null: true, class: 'span4', info: true }, { name: 'note', display: 'Note', tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, null: true, info: true },
{ name: 'role_ids', display: 'Roles', tag: 'checkbox', multiple: true, null: false, relation: 'Role', class: 'span4' }, { name: 'role_ids', display: 'Roles', tag: 'checkbox', multiple: true, null: false, relation: 'Role' },
{ name: 'group_ids', display: 'Groups', tag: 'checkbox', multiple: true, null: true, relation: 'Group', class: 'span4', invite_agent: true }, { name: 'group_ids', display: 'Groups', tag: 'checkbox', multiple: true, null: true, relation: 'Group', invite_agent: true },
{ name: 'active', display: 'Active', tag: 'boolean', default: true, null: true, class: 'span4' }, { name: 'active', display: 'Active', tag: 'boolean', default: true, null: true },
{ name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 }, { name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 },
] ]
@configure_overview = [ @configure_overview = [
# 'login', 'firstname', 'lastname', 'email', 'updated_at', # 'login', 'firstname', 'lastname', 'email', 'updated_at',

View file

@ -17,24 +17,24 @@
<h3><a href="#" data-type="edit"><%= ticket.title %></a> <small><%= ticket.number %> <span class="humanTimeFromNow" data-time="<%= ticket.created_at %>">?</span></small></h3> <h3><a href="#" data-type="edit"><%= ticket.title %></a> <small><%= ticket.number %> <span class="humanTimeFromNow" data-time="<%= ticket.created_at %>">?</span></small></h3>
<div class="row"> <div class="row">
<div class="span2"> <div class="span2">
<b><%- @T( 'State' ) %></b> <%- @T( ticket.state.name ) %> <b><%- @T( 'State' ) %></b> <%- @P( ticket, 'state' ) %>
</div> </div>
<div class="span2"> <div class="span2">
<b><%- @T( 'Group' ) %></b> <%= ticket.group.name %> <b><%- @T( 'Group' ) %></b> <%- @P( ticket, 'group' ) %>
</div> </div>
<div class="span2"> <div class="span2">
<b><%- @T( 'Customer' ) %></b> <%= ticket.customer.displayName() %> <b><%- @T( 'Customer' ) %></b> <%- @P( ticket, 'customer' ) %>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="span2"> <div class="span2">
<b><%- @T( 'Priority' ) %></b> <%- @T( ticket.priority.name ) %> <b><%- @T( 'Priority' ) %></b> <%- @P( ticket, 'priority' ) %>
</div> </div>
<div class="span2"> <div class="span2">
<b><%- @T( 'Owner' ) %></b> <%= ticket.owner.displayName() %> <b><%- @T( 'Owner' ) %></b> <%- @P( ticket, 'owner' ) %>
</div> </div>
<div class="span2"> <div class="span2">
<b><%- @T( 'Organization' ) %></b> <%= @P( ticket.customer.organization ) %> <b><%- @T( 'Organization' ) %></b> <%- @P( ticket, 'organization' ) %>
</div> </div>
</div> </div>
</div> </div>

View file

@ -29,16 +29,9 @@
<% groupLast = '' %> <% groupLast = '' %>
<% for object in @objects: %> <% for object in @objects: %>
<% if @groupBy: %> <% if @groupBy: %>
<% if object[@groupBy] && object[@groupBy].displayName: %> <% groupByName = @P( object, @groupBy ) %>
<% groupByName = object[@groupBy].displayName() %>
<% if object[@groupBy].translate(): %>
<% groupByName = @T(groupByName) %>
<% end %>
<% else: %>
<% groupByName = object[@groupBy] || '-' %>
<% end %>
<% if groupLast isnt groupByName: %> <% if groupLast isnt groupByName: %>
<tr class=""><td colspan="<%= length %>"><b><%- @P( groupByName ) %></b></td></tr> <tr class=""><td colspan="<%= length %>"><b><%= groupByName %></b></td></tr>
<% groupLast = groupByName %> <% groupLast = groupByName %>
<% end %> <% end %>
<% end %> <% end %>
@ -56,47 +49,26 @@
<td><input type="radio" value="<%= object.id %>" name="radio"/></td> <td><input type="radio" value="<%= object.id %>" name="radio"/></td>
<% end %> <% end %>
<% for item in @header: %> <% for item in @header: %>
<% translation = false %> <% value = @P( object, item.name ) %>
<% value = object[item.name] %>
<% item_id = item.name.substr(item.name.length-3, item.name.length) %>
<% if item_id is '_id' && object[ item.name.substr(0, item.name.length-3) ]: %>
<% value = object[ item.name.substr(0, item.name.length-3) ] %>
<% refObject = object[ item.name.substr(0, item.name.length-3) ] %>
<% end %>
<% if !value: %>
<% parts = item.name.split '::' %>
<% if parts[0] && parts[1] && object[ parts[0] ]: %>
<% value = object[ parts[0] ][ parts[1] ] %>
<% end %>
<% end %>
<% if value && value.displayNameLong : %>
<% translation = true %>
<% value = value.displayNameLong() %>
<% else if value && value.displayName : %>
<% translation = true %>
<% value = value.displayName() %>
<% end %>
<% item_clone = item %>
<% if @callbacks: %> <% if @callbacks: %>
<% if item.name.substr(item.name.length-3, item.name.length) is '_id' && object[ item.name.substr(0, item.name.length-3) ]: %>
<% refObject = object[ item.name.substr(0, item.name.length-3) ] %>
<% end %>
<% for attribute, callbacksAll of @callbacks: %> <% for attribute, callbacksAll of @callbacks: %>
<% if attribute is item.name || attribute is item_id: %> <% if attribute is item.name: %>
<% for callback in callbacksAll: %> <% for callback in callbacksAll: %>
<% value = callback( value, object, item_clone, @header, refObject ) %> <% value = callback( value, object, item, @header, refObject ) %>
<% end %> <% end %>
<% end %> <% end %>
<% 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.parentClass: %>class="<%= item_clone.parentClass %>"<% end %>> <td <% if item.parentClass: %>class="<%= item.parentClass %>"<% end %>>
<% if item_clone.link: %><a href="<%- item_clone.link %>" <% if item_clone.target: %>target="<%= item_clone.target %>"<% end %>><% end %>
<% if item_clone.translate || ( translation && !refObject && object.translate && object.translate() ) || ( translation && refObject && refObject.translate && refObject.translate() ) : %> <% if item.link: %><a href="<%- item.link %>" <% if item.target: %>target="<%= item.target %>"<% end %>><% end %>
<span <% if item_clone.class: %>class="<%= item_clone.class %>"<% end %>><%- @T( @P( value, item_clone ) ) %></span> <span <% if item.class: %>class="<%= item.class %>"<% end %> <% if item.title: %>title="<%= item.title %>"<% end %> <% if item.data: %><% for data_key, data_item of item.data: %>data-<%- data_key %>="<%= data_item %>" <% end %><% end %>><%- value %></span>
<% else if item_clone.type is 'time': %> <% if item.link: %></a><% end %>
<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: %><% for data_key, data_item of item_clone.data: %>data-<%- data_key %>="<%= data_item %>" <% end %><% end %>><%= @P(value) %></span>
<% end %>
<% if item_clone.link: %></a><% end %>
</td> </td>
<% end %> <% end %>
<% if @destroy: %> <% if @destroy: %>
@ -105,4 +77,4 @@
</tr> </tr>
<% end %> <% end %>
</tbody> </tbody>
</table> </table>

View file

@ -17,7 +17,7 @@
<% if @organization[row.name]: %> <% if @organization[row.name]: %>
<div class="profile-detailsEntry"> <div class="profile-detailsEntry">
<label><%- @Ti( row.display ) %></label> <label><%- @Ti( row.display ) %></label>
<%- @L( @P( @organization[row.name] ) ) %> <%- @P( @organization, row.name ) %>
</div> </div>
<% end %> <% end %>
<% end %> <% end %>

View file

@ -4,11 +4,7 @@
<% if @organization[row.name]: %> <% if @organization[row.name]: %>
<div class="column"> <div class="column">
<h3><%- @T( row.display ) %></h3> <h3><%- @T( row.display ) %></h3>
<% if row.tag is 'richtext': %> <div><%- @P( @organization, row.name ) %></div>
<div><%- @organization[row.name] %></div>
<% else: %>
<div><%- @L( @P( @organization[row.name] ) ) %></div>
<% end %>
</div> </div>
<% end %> <% end %>
<% end %> <% end %>
@ -18,7 +14,7 @@
<h3><%- @T('Members') %></h3> <h3><%- @T('Members') %></h3>
<% for user in @organization.members: %> <% for user in @organization.members: %>
<div class="person"> <div class="person">
<%= user.displayName() %> <%= user.displayName() %>
</div> </div>
<% end %> <% end %>
<% end %> <% end %>

View file

@ -2,17 +2,17 @@
<span class="<%- @ticket.icon() %>" title="<%- @ticket.iconTitle() %>"></span> <span class="<%- @ticket.iconTextClass() %>"><%- @ticket.iconTitle() %></span> <span class="<%- @ticket.icon() %>" title="<%- @ticket.iconTitle() %>"></span> <span class="<%- @ticket.iconTextClass() %>"><%- @ticket.iconTitle() %></span>
</div> </div>
<hr> <hr>
<h3><%- @P('Agent') %></h3> <h3><%- @T('Agent') %></h3>
<div class="person"> <div class="person">
<%= @ticket.owner.displayName() %> <%= @ticket.owner.displayName() %>
<% if @ticket.owner.organization_id: %> <% if @ticket.owner.organization: %>
<span class="organization"><%= @ticket.owner.organization.displayName() %></span> <span class="organization"><%= @ticket.owner.organization.displayName() %></span>
<% end %> <% end %>
</div> </div>
<h3><%- @P('Customer') %></h3> <h3><%- @T('Customer') %></h3>
<div class="person"> <div class="person">
<%= @ticket.customer.displayName() %> <%= @ticket.customer.displayName() %>
<% if @ticket.customer.organization_id: %> <% if @ticket.customer.organization: %>
<span class="organization"><%= @ticket.customer.organization.displayName() %></span> <span class="organization"><%= @ticket.customer.organization.displayName() %></span>
<% end %> <% end %>
</div> </div>
@ -20,18 +20,18 @@
<div class="horizontal two-columns"> <div class="horizontal two-columns">
<div class="column"> <div class="column">
<h3>#</h3> <h3>#</h3>
<div class="u-textTruncate"><%- @P( @ticket.number ) %></div> <div class="u-textTruncate"><%- @P( @ticket, 'number' ) %></div>
</div> </div>
<div class="column"> <div class="column">
<h3><%- @T( 'Priority' ) %></h3> <h3><%- @T( 'Priority' ) %></h3>
<div class="u-textTruncate"><%- @T( @ticket.priority.name ) %></div> <div class="u-textTruncate"><%- @P( @ticket, 'priority' ) %></div>
</div> </div>
<div class="column"> <div class="column">
<h3><%- @T( 'Created' ) %></h3> <h3><%- @T( 'Created' ) %></h3>
<div class="u-textTruncate"><%- @P( @ticket.humanTime ) %></div> <div class="u-textTruncate"><%- @P( @ticket, 'created_at' ) %></div>
</div> </div>
<div class="column"> <div class="column">
<h3><%- @T( 'Group' ) %></h3> <h3><%- @T( 'Group' ) %></h3>
<div class="u-textTruncate"><%- @P( @ticket.group ) %></div> <div class="u-textTruncate"><%- @P( @ticket, 'group' ) %></div>
</div> </div>
</div> </div>

View file

@ -7,11 +7,7 @@
<% if @user[row.name]: %> <% if @user[row.name]: %>
<div class="column"> <div class="column">
<h3><%- @T( row.display ) %></h3> <h3><%- @T( row.display ) %></h3>
<% if row.tag is 'richtext': %> <div><%- @P( @user, row.name ) %></div>
<div><%- @user[row.name] %></div>
<% else: %>
<div><%- @L( @P( @user[row.name] ) ) %></div>
<% end %>
</div> </div>
<% end %> <% end %>
<% end %> <% end %>

View file

@ -1,3 +1,5 @@
<ul>
<% for ticket in @tickets: %> <% for ticket in @tickets: %>
<div class="customer-info"><a href="#ticket/zoom/<%= ticket.id %>" title="<%= ticket.title %>">T:<%= ticket.number %></a> <span title="<%= ticket.created_at_short %>"><%= ticket.humanTime %></span><br/><%= ticket.title %></div> <li><a href="#ticket/zoom/<%= ticket.id %>" title="<%= ticket.title %>">T:<%= ticket.number %></a> <span title="<%- @P( ticket, 'created_at') %>"><%- @P( ticket, 'created_at') %></span><br/><%= ticket.title %></li>
<% end %> <% end %>
<ul>

View file

@ -1 +1 @@
<h1 contenteditable="true" class="ticket-title-update" data-placeholder="<%= @T('Enter Title...') %>"><%= @P( @ticket.title ) %></h1> <div contenteditable="true" class="ticket-title-update" data-placeholder="<%= @T('Enter Title...') %>"><%= @ticket.title %></div>

View file

@ -18,7 +18,7 @@
<% if @user[row.name]: %> <% if @user[row.name]: %>
<div class="profile-detailsEntry"> <div class="profile-detailsEntry">
<label><%- @Ti( row.display ) %></label> <label><%- @Ti( row.display ) %></label>
<%- @L( @P( @user[row.name] ) ) %> <%- @P( @user, row.name ) %>
</div> </div>
<% end %> <% end %>
<% end %> <% end %>

View file

@ -9,7 +9,7 @@
<div class="sidebar-block"> <div class="sidebar-block">
<% if row.tag isnt 'richtext': %> <% if row.tag isnt 'richtext': %>
<label><%- @T( row.display ) %></label> <label><%- @T( row.display ) %></label>
<%- @L( @P( @organization[row.name] ) ) %> <%- @P( @organization, row.name ) %>
<% else: %> <% else: %>
<label><%- @T( row.display ) %></label> <label><%- @T( row.display ) %></label>
<div contenteditable="true" data-name="<%= row.name %>" data-type="update-org" data-placeholder="<%- @T('Add a Note') %>"><%- @organization[row.name] %></div> <div contenteditable="true" data-name="<%= row.name %>" data-type="update-org" data-placeholder="<%- @T('Add a Note') %>"><%- @organization[row.name] %></div>

View file

@ -10,7 +10,7 @@
<div class="sidebar-block"> <div class="sidebar-block">
<% if row.tag isnt 'richtext': %> <% if row.tag isnt 'richtext': %>
<label><%- @T( row.display ) %></label> <label><%- @T( row.display ) %></label>
<%- @L( @P( @user[row.name] ) ) %> <%- @P( @user, row.name ) %>
<% else: %> <% else: %>
<label><%- @T( row.display ) %></label> <label><%- @T( row.display ) %></label>
<div contenteditable="true" data-name="<%= row.name %>" data-type="update" data-placeholder="<%- @T('Add a Note') %>"><%- @user[row.name] %></div> <div contenteditable="true" data-name="<%= row.name %>" data-type="update" data-placeholder="<%- @T('Add a Note') %>"><%- @user[row.name] %></div>

View file

@ -714,6 +714,10 @@ textarea,
background: none; background: none;
} }
textarea.form-control {
height: 118px;
}
select.form-control { select.form-control {
padding-left: 10px; padding-left: 10px;
padding-right: 34px; padding-right: 34px;
@ -3159,14 +3163,12 @@ footer {
padding: 0 81px; padding: 0 81px;
} }
.ticket-title h1 {
margin-top: 15px;
margin-bottom: 8px;
text-align: center;
}
.ticket-title-update { .ticket-title-update {
@extend h1;
white-space: normal; white-space: normal;
margin-top: 15px;
margin-bottom: 8px;
text-align: center;
} }
.task-subline { .task-subline {
@ -3177,7 +3179,7 @@ footer {
.ticket-article-item { .ticket-article-item {
padding-bottom: 33px; padding-bottom: 33px;
position: relative; position: relative;
.avatar { .avatar {
position: absolute; position: absolute;
right: 0; right: 0;

View file

@ -97,9 +97,7 @@ class TicketsController < ApplicationController
:customer_id => params[:customer_id], :customer_id => params[:customer_id],
:limit => 15, :limit => 15,
) )
render :json => { render :json => result
:tickets => result
}
end end
# GET /api/v1/ticket_history/1 # GET /api/v1/ticket_history/1

View file

@ -133,8 +133,9 @@ list tickets by customer groupd in state categroie open and closed
returns returns
result = { result = {
:open => tickets_open, :ticket_ids_open => tickets_open,
:closed => tickets_closed, :ticket_ids_closed => tickets_closed,
:assets => { ...list of assets... },
} }
=end =end
@ -150,15 +151,27 @@ returns
:customer_id => data[:customer_id], :customer_id => data[:customer_id],
:state_id => state_list_open :state_id => state_list_open
).limit( data[:limit] || 15 ).order('created_at DESC') ).limit( data[:limit] || 15 ).order('created_at DESC')
assets = {}
ticket_ids_open = []
tickets_open.each {|ticket|
ticket_ids_open.push ticket.id
assets = ticket.assets(assets)
}
tickets_closed = Ticket.where( tickets_closed = Ticket.where(
:customer_id => data[:customer_id], :customer_id => data[:customer_id],
:state_id => state_list_closed :state_id => state_list_closed
).limit( data[:limit] || 15 ).order('created_at DESC') ).limit( data[:limit] || 15 ).order('created_at DESC')
ticket_ids_closed = []
tickets_closed.each {|ticket|
ticket_ids_closed.push ticket.id
assets = ticket.assets(assets)
}
return { return {
:open => tickets_open, :ticket_ids_open => ticket_ids_open,
:closed => tickets_closed, :ticket_ids_closed => ticket_ids_closed,
:assets => assets,
} }
end end

View file

@ -3,6 +3,7 @@ Zammad::Application.routes.draw do
match '/tests-core', :to => 'tests#core', :via => :get match '/tests-core', :to => 'tests#core', :via => :get
match '/tests-ui', :to => 'tests#ui', :via => :get match '/tests-ui', :to => 'tests#ui', :via => :get
match '/tests-model', :to => 'tests#model', :via => :get match '/tests-model', :to => 'tests#model', :via => :get
match '/tests-model-ui', :to => 'tests#model_ui', :via => :get
match '/tests-form', :to => 'tests#form', :via => :get match '/tests-form', :to => 'tests#form', :via => :get
match '/tests-form-extended', :to => 'tests#form_extended', :via => :get match '/tests-form-extended', :to => 'tests#form_extended', :via => :get
match '/tests-form-validation', :to => 'tests#form_validation', :via => :get match '/tests-form-validation', :to => 'tests#form_validation', :via => :get

View file

@ -0,0 +1,79 @@
window.onload = function() {
// model
test( "model ui basic tests", function() {
// load ref object
App.Collection.loadAssets({
TicketState: {
1: {
name: 'new', id: 1, updated_at: "2014-11-07T23:43:08.000Z",
},
2: {
name: 'open', id: 2, updated_at: "2014-11-07T23:43:08.000Z",
},
3: {
name: 'closed <>&', id: 3, updated_at: "2014-11-07T23:43:08.000Z",
},
},
})
// create ticket
var attribute1 = {
name: 'date', display: 'date 1', tag: 'date', null: true
};
App.Ticket.configure_attributes.push( attribute1 )
var ticket = new App.Ticket()
ticket.load({
id: 1000,
title: 'some title <>&',
state_id: 2,
updated_at: '2014-11-07T23:43:08.000Z',
date: '2015-02-07',
})
App.i18n.set('en')
equal( App.viewPrint( ticket, 'id' ), 1000)
equal( App.viewPrint( ticket, 'title' ), 'some title &lt;&gt;&amp;')
equal( App.viewPrint( ticket, 'state' ), 'open')
equal( App.viewPrint( ticket, 'state_id' ), 'open')
equal( App.viewPrint( ticket, 'not_existing' ), '-')
equal( App.viewPrint( ticket, 'updated_at' ), "<span class=\"humanTimeFromNow undefined\" data-time=\"2014-11-07T23:43:08.000Z\">?</span>")
equal( App.viewPrint( ticket, 'date' ), '2015-02-07')
App.i18n.set('de')
equal( App.viewPrint( ticket, 'id' ), 1000)
equal( App.viewPrint( ticket, 'title' ), 'some title &lt;&gt;&amp;')
equal( App.viewPrint( ticket, 'state' ), 'offen')
equal( App.viewPrint( ticket, 'state_id' ), 'offen')
equal( App.viewPrint( ticket, 'not_existing' ), '-')
equal( App.viewPrint( ticket, 'updated_at' ), "<span class=\"humanTimeFromNow undefined\" data-time=\"2014-11-07T23:43:08.000Z\">?</span>")
equal( App.viewPrint( ticket, 'date' ), '07.02.2015')
App.i18n.set('en')
ticket.state_id = 3
equal( App.viewPrint( ticket, 'state' ), 'closed &lt;&gt;&amp;')
equal( App.viewPrint( ticket, 'state_id' ), 'closed &lt;&gt;&amp;')
App.i18n.set('de')
equal( App.viewPrint( ticket, 'state' ), 'closed &lt;&gt;&amp;')
equal( App.viewPrint( ticket, 'state_id' ), 'closed &lt;&gt;&amp;')
// normal string
data = {
a: 1,
b: 'abc',
c: {
displayName: function() { return "my displayName <>&" }
},
}
equal( App.viewPrint( data, 'a' ), 1)
equal( App.viewPrint( data, 'b' ), 'abc')
equal( App.viewPrint( data, 'c' ), 'my displayName &lt;&gt;&amp;')
});
}

View file

@ -410,14 +410,13 @@ test( "table test 2", function() {
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(1)').text().trim(), 'adapter1', 'check row 1') equal( el.find('tbody > tr:nth-child(1) > td:nth-child(1)').text().trim(), 'adapter1', 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), 'host1', 'check row 1') equal( el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), 'host1', 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'user1', 'check row 1') equal( el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'user1', 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(4)').text().trim(), 'true', 'check row 1') equal( el.find('tbody > tr:nth-child(1) > td:nth-child(4)').text().trim(), 'ja', 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(4)').text().trim(), 'true', 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(5)').text().trim(), '', 'check row 1') equal( el.find('tbody > tr:nth-child(1) > td:nth-child(5)').text().trim(), '', 'check row 1')
equal( el.find('tbody > tr:nth-child(2) > td').length, 5, 'check row 2') equal( el.find('tbody > tr:nth-child(2) > td').length, 5, 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(1)').text().trim(), 'adapter2', 'check row 2') equal( el.find('tbody > tr:nth-child(2) > td:nth-child(1)').text().trim(), 'adapter2', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), 'host2', 'check row 2') equal( el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), 'host2', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'user2', 'check row 2') equal( el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'user2', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(4)').text().trim(), 'true', 'check row 2') equal( el.find('tbody > tr:nth-child(2) > td:nth-child(4)').text().trim(), 'ja', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(5)').text().trim(), '', 'check row 2') equal( el.find('tbody > tr:nth-child(2) > td:nth-child(5)').text().trim(), '', 'check row 2')
}); });

View file

@ -68,6 +68,28 @@ class AAbUnitTest < TestCase
] ]
browser_single_test(tests) browser_single_test(tests)
end end
def test_model_ui
tests = [
{
:name => 'start',
:instance => browser_instance,
:url => browser_url + '/tests-model-ui',
:action => [
{
:execute => 'wait',
:value => 8,
},
{
:execute => 'match',
:css => '.result .failed',
:value => '0',
:match_result => true,
},
],
},
]
browser_single_test(tests)
end
def test_form def test_form
tests = [ tests = [
{ {