Merge branch 'develop' into interface

Conflicts:
	app/assets/javascripts/app/controllers/customer_ticket_create.js.coffee
	app/assets/javascripts/app/controllers/ticket_zoom.js.coffee
	app/assets/javascripts/app/models/user.js.coffee
	app/assets/javascripts/app/views/agent_ticket_create.jst.eco
	app/assets/javascripts/app/views/customer_ticket_create.jst.eco
	app/assets/javascripts/app/views/navigation/personal.jst.eco
	config/routes/test.rb
	test/browser/aab_unit_test.rb
This commit is contained in:
Martin Edenhofer 2014-09-13 13:12:00 +02:00
commit 5a11480447
60 changed files with 12252 additions and 11438 deletions

View file

@ -1,6 +1,6 @@
source 'http://rubygems.org' source 'http://rubygems.org'
gem 'rails', '4.1.4' gem 'rails', '4.1.5'
gem 'rails-observers' gem 'rails-observers'
gem 'activerecord-session_store' gem 'activerecord-session_store'

View file

@ -2,7 +2,11 @@ class App.ControllerForm extends App.Controller
constructor: (params) -> constructor: (params) ->
for key, value of params for key, value of params
@[key] = value @[key] = value
@attribute_count = 0
if !@handlers
@handlers = []
@handlers.push @_showHideToggle
@handlers.push @_requiredMandantoryToggle
if !@form if !@form
@form = @formGen() @form = @formGen()
@ -23,33 +27,51 @@ class App.ControllerForm extends App.Controller
fieldset = $('<fieldset></fieldset>') fieldset = $('<fieldset></fieldset>')
for attribute_clean in @model.configure_attributes # collect form attributes
attribute = _.clone( attribute_clean ) @attributes = []
if @model.attributesGet
attributesClean = @model.attributesGet(@screen)
else
attributesClean = App.Model.attributesGet(@screen, @model.configure_attributes )
if !attribute.readonly && ( !@required || @required && attribute[@required] ) for attributeName, attribute of attributesClean
@attribute_count = @attribute_count + 1 # ignore read only attributes
if !attribute.readonly
# add item # check generic filter
item = @formGenItem( attribute, @model.className, fieldset ) if @filter && !attribute.filter
item.appendTo(fieldset) if @filter[ attributeName ]
attribute.filter = @filter[ attributeName ]
# if password, add confirm password item @attributes.push attribute
if attribute.type is 'password'
# set selected value passed on current params attribute_count = 0
if @params className = @model.className + '_' + Math.floor( Math.random() * 999999 ).toString()
if attribute.name of @params
attribute.value = @params[attribute.name]
# rename display and name to _confirm for attribute in @attributes
if !attribute.single attribute_count = attribute_count + 1
attribute.display = attribute.display + ' (confirm)'
attribute.name = attribute.name + '_confirm';
item = @formGenItem( attribute, @model.className, fieldset )
item.appendTo(fieldset)
if @no_fieldset # add item
item = @formGenItem( attribute, className, fieldset, attribute_count )
item.appendTo(fieldset)
# if password, add confirm password item
if attribute.type is 'password'
# set selected value passed on current params
if @params
if attribute.name of @params
attribute.value = @params[attribute.name]
# rename display and name to _confirm
if !attribute.single
attribute.display = attribute.display + ' (confirm)'
attribute.name = attribute.name + '_confirm';
item = @formGenItem( attribute, className, fieldset, attribute_count )
item.appendTo(fieldset)
if @noFieldset
fieldset = fieldset.children() fieldset = fieldset.children()
if @fullForm if @fullForm
@ -57,6 +79,13 @@ class App.ControllerForm extends App.Controller
@formClass = '' @formClass = ''
fieldset = $('<form class="' + @formClass + '"><button class="btn">' + App.i18n.translateContent('Submit') + '</button></form>').prepend( fieldset ) fieldset = $('<form class="' + @formClass + '"><button class="btn">' + App.i18n.translateContent('Submit') + '</button></form>').prepend( fieldset )
# bind form events
if @events
for eventSelector, callback of @events
do (eventSelector, callback) =>
evs = eventSelector.split(' ')
fieldset.find( evs[1] ).bind(evs[0], (e) => callback(e) )
# return form # return form
return fieldset return fieldset
@ -85,7 +114,7 @@ class App.ControllerForm extends App.Controller
null: false null: false
relation: 'User' relation: 'User'
autocapitalize: false autocapitalize: false
help: 'Select the customer of the Ticket or create one.' help: 'Select the customer of the ticket or create one.'
helpLink: '<a href="" class="customer_new">&raquo;</a>' helpLink: '<a href="" class="customer_new">&raquo;</a>'
callback: @userInfo callback: @userInfo
class: 'span7' class: 'span7'
@ -134,14 +163,14 @@ class App.ControllerForm extends App.Controller
### ###
formGenItem: (attribute_config, classname, form ) -> formGenItem: (attribute_config, classname, form, attribute_count ) ->
attribute = _.clone( attribute_config ) attribute = clone( attribute_config )
# create item id # create item id
attribute.id = classname + '_' + attribute.name attribute.id = classname + '_' + attribute.name
# set autofocus # set autofocus
if @autofocus && @attribute_count is 1 if @autofocus && attribute_count is 1
attribute.autofocus = 'autofocus' attribute.autofocus = 'autofocus'
# set required option # set required option
@ -237,6 +266,22 @@ class App.ControllerForm extends App.Controller
else if attribute.tag is 'select' else if attribute.tag is 'select'
item = $( App.view('generic/select')( attribute: attribute ) ) item = $( App.view('generic/select')( attribute: attribute ) )
# date
else if attribute.tag is 'date'
attribute.type = 'text'
item = $( App.view('generic/date')( attribute: attribute ) )
#item.datetimepicker({
# format: 'Y.m.d'
#});
# date
else if attribute.tag is 'datetime'
attribute.type = 'text'
item = $( App.view('generic/date')( attribute: attribute ) )
#item.datetimepicker({
# format: 'Y.m.d H:i'
#});
# timezone # timezone
else if attribute.tag is 'timezone' else if attribute.tag is 'timezone'
attribute.options = [] attribute.options = []
@ -720,7 +765,7 @@ class App.ControllerForm extends App.Controller
b = (event, item) => b = (event, item) =>
# set html form attribute # set html form attribute
$(local_attribute).val(item.id) $(local_attribute).val(item.id).trigger('change')
$(local_attribute + '_autocompletion_value_shown').val(item.value) $(local_attribute + '_autocompletion_value_shown').val(item.value)
# call calback # call calback
@ -741,8 +786,11 @@ class App.ControllerForm extends App.Controller
} }
) )
### ###
source = attribute.source
if typeof(source) is 'string'
source = source.replace('#{@apiPath}', App.Config.get('api_path') );
$(local_attribute_full).autocomplete( $(local_attribute_full).autocomplete(
source: attribute.source, source: source,
minLength: attribute.minLengt || 3, minLength: attribute.minLengt || 3,
select: ( event, ui ) => select: ( event, ui ) =>
b(event, ui.item) b(event, ui.item)
@ -1224,63 +1272,12 @@ class App.ControllerForm extends App.Controller
else else
item = $( App.view('generic/input')( attribute: attribute ) ) item = $( App.view('generic/input')( attribute: attribute ) )
if attribute.onchange if @handlers
if typeof attribute.onchange is 'function' item.bind('change', (e) =>
attribute.onchange(attribute) params = App.ControllerForm.params( $(e.target) )
else for handler in @handlers
for i of attribute.onchange handler(params, attribute, @attributes, classname, form, @)
a = i.split(/__/) )
if a[1]
if a[0] is attribute.name
@attribute = attribute
@classname = classname
@attributes_clean = attributes_clean
@change = a
b = =>
# console.log 'aaa', @attribute
attribute = @attribute
change = @change
classname = @classname
attributes_clean = @attributes_clean
ui = @
$( '#' + @attribute.id ).bind('change', ->
ui.log 'change', @, attribute, change
ui.log change[0] + ' has changed - changing ' + change[1]
item = $( ui.formGenItem(attribute, classname, attributes_clean) )
ui.log item, classname
)
App.Delay.set( b, 100, undefined, 'form_change' )
# if attribute.onchange[]
ui = @
item.bind('change', ->
if ui.form_data
params = App.ControllerForm.params(@)
for i of ui.form_data
a = i.split(/__/)
if a[1] && a[0] is attribute.name
newListAttribute = i
changedAttribute = a[0]
toChangeAttribute = a[1]
# get new option list
newListAttributes = ui['form_data'][newListAttribute][ params['group_id'] ]
# find element to replace
for item in ui.model.configure_attributes
if item.name is toChangeAttribute
item.display = false
item['filter'][toChangeAttribute] = newListAttributes
if params[changedAttribute]
item.default = params[toChangeAttribute]
if !item.default
delete item['default']
newElement = ui.formGenItem( item, classname, form )
# replace new option list
form.find('[name="' + toChangeAttribute + '"]').replaceWith( newElement )
)
# bind dependency # bind dependency
if @dependency if @dependency
@ -1342,6 +1339,44 @@ class App.ControllerForm extends App.Controller
el.find('[name="' + key + '"]').parents('.form-group').addClass('hide') el.find('[name="' + key + '"]').parents('.form-group').addClass('hide')
el.find('[name="' + key + '"]').addClass('is-hidden') el.find('[name="' + key + '"]').addClass('is-hidden')
_mandantory: (name, el = @el) ->
if !_.isArray(name)
name = [name]
for key in name
el.find('[name="' + key + '"]').attr('required', true)
el.find('[name="' + key + '"]').parents('.form-group').find('label span').html('*')
_optional: (name, el = @el) ->
if !_.isArray(name)
name = [name]
for key in name
el.find('[name="' + key + '"]').attr('required', false)
el.find('[name="' + key + '"]').parents('.form-group').find('label span').html('')
_showHideToggle: (params, changedAttribute, attributes, classname, form, ui) =>
for attribute in attributes
if attribute.shown_if
hit = false
for refAttribute, refValue of attribute.shown_if
if params[refAttribute] && params[refAttribute].toString() is refValue.toString()
hit = true
if hit
ui._show(attribute.name)
else
ui._hide(attribute.name)
_requiredMandantoryToggle: (params, changedAttribute, attributes, classname, form, ui) =>
for attribute in attributes
if attribute.required_if
hit = false
for refAttribute, refValue of attribute.required_if
if params[refAttribute] && params[refAttribute].toString() is refValue.toString()
hit = true
if hit
ui._mandantory(attribute.name)
else
ui._optional(attribute.name)
# sort attribute.options # sort attribute.options
_sortOptions: (attribute) -> _sortOptions: (attribute) ->
@ -1402,6 +1437,7 @@ class App.ControllerForm extends App.Controller
list = [] list = []
if attribute.filter if attribute.filter
App.Log.debug 'ControllerForm', '_getRelationOptionList:filter', attribute.filter App.Log.debug 'ControllerForm', '_getRelationOptionList:filter', attribute.filter
# function based filter # function based filter
@ -1429,6 +1465,22 @@ class App.ControllerForm extends App.Controller
if record['id'] is key if record['id'] is key
list.push record list.push record
# data based filter
else if attribute.filter && _.isArray attribute.filter
App.Log.debug 'ControllerForm', '_getRelationOptionList:filter-array', attribute.filter
# check all records
for record in App[ attribute.relation ].search( sortBy: attribute.sortBy )
# check all filter attributes
for key in attribute.filter
# check all filter values as array
# if it's matching, use it for selection
if record['id'] is key
list.push record
# no data filter matched # no data filter matched
else else
App.Log.debug 'ControllerForm', '_getRelationOptionList:filter-data no filter matched' App.Log.debug 'ControllerForm', '_getRelationOptionList:filter-data no filter matched'
@ -1515,9 +1567,10 @@ class App.ControllerForm extends App.Controller
validate: (params) -> validate: (params) ->
App.Model.validate( App.Model.validate(
model: @model, model: @model
params: params, params: params
) screen: @screen
)
# get all params of the form # get all params of the form
@params: (form) -> @params: (form) ->
@ -1640,13 +1693,8 @@ class App.ControllerForm extends App.Controller
# show new errors # show new errors
for key, msg of data.errors for key, msg of data.errors
$(data.form).parents().find('[name*="' + key + '"]').parents('div .form-group').addClass('has-error') $(data.form).parents('form').find('[name="' + key + '"]').parents('div .form-group').addClass('has-error')
$(data.form).parents().find('[name*="' + key + '"]').parent().find('.help-inline').html(msg) $(data.form).parents('form').find('[name="' + key + '"]').parent().find('.help-inline').html(msg)
# set autofocus # set autofocus
$(data.form).parents().find('.has-error').find('input, textarea').first().focus() $(data.form).parents('form').find('.has-error').find('input, textarea').first().focus()
# # enable form again
# if $(data.form).parents().find('.has-error').html()
# @formEnable(data.form)

View file

@ -7,11 +7,11 @@ class App.ControllerGenericNew extends App.ControllerModal
@html App.view('generic/admin/new')( head: @pageData.object ) @html App.view('generic/admin/new')( head: @pageData.object )
new App.ControllerForm( new App.ControllerForm(
el: @el.find('#object_new'), el: @el.find('#object_new')
model: App[ @genericObject ], model: App[ @genericObject ]
params: @item, params: @item
required: @required, screen: @screen || 'edit'
autofocus: true, autofocus: true
) )
@modalShow() @modalShow()
@ -59,7 +59,7 @@ class App.ControllerGenericEdit extends App.ControllerModal
el: @el.find('#object_edit') el: @el.find('#object_edit')
model: App[ @genericObject ] model: App[ @genericObject ]
params: @item params: @item
required: @required screen: @screen || 'edit'
autofocus: true autofocus: true
) )
@modalShow() @modalShow()

View file

@ -99,6 +99,7 @@ class App.ControllerTable extends App.Controller
data.model = {} data.model = {}
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 || {}
attributes = App.Model.attributesGet(false, attributes)
destroy = data.model.configure_delete destroy = data.model.configure_delete
# check if table is empty # check if table is empty
@ -146,13 +147,13 @@ class App.ControllerTable extends App.Controller
header = [] header = []
for item in overview for item in overview
headerFound = false headerFound = false
for attribute in attributes for attributeName, attribute of attributes
if attribute.name is item if attributeName is item
headerFound = true headerFound = true
header.push attribute header.push attribute
else else
rowWithoutId = item + '_id' rowWithoutId = item + '_id'
if attribute.name is rowWithoutId if attributeName is rowWithoutId
headerFound = true headerFound = true
header.push attribute header.push attribute

View file

@ -1,9 +1,10 @@
class App.TicketCreate extends App.Controller class App.TicketCreate extends App.Controller
events: events:
'click .customer_new': 'userNew' 'click .type-tabs .tab': 'changeFormType'
'submit form': 'submit' 'click .customer_new': 'userNew'
'click .submit': 'submit' 'submit form': 'submit'
'click .cancel': 'cancel' 'click .submit': 'submit'
'click .cancel': 'cancel'
constructor: (params) -> constructor: (params) ->
super super
@ -13,40 +14,18 @@ class App.TicketCreate extends App.Controller
# set title # set title
@form_id = App.ControllerForm.formId() @form_id = App.ControllerForm.formId()
@form_meta = undefined
@edit_form = undefined # define default type
@default_type = 'phone-in'
# set article attributes
default_type = 'call_inbound'
if !@type
@type = default_type
article_sender_type_map =
call_inbound:
sender: 'Customer'
article: 'phone'
title: 'Call Inbound'
call_outbound:
sender: 'Agent'
article: 'phone'
title: 'Call Outbound'
email:
sender: 'Agent'
article: 'email'
title: 'Email'
@article_attributes = article_sender_type_map[@type]
# remember split info if exists # remember split info if exists
split = '' split = ''
if @ticket_id && @article_id if @ticket_id && @article_id
split = "/#{@ticket_id}/#{@article_id}" split = "/#{@ticket_id}/#{@article_id}"
# if no map entry exists, route to default
if !@article_attributes
@navigate '#ticket/create/' + default_type + split
return
# update navbar highlighting # update navbar highlighting
@navupdate '#ticket/create/' + @type + '/id/' + @id + split @navupdate '#ticket/create/id/' + @id + split
@fetch(params) @fetch(params)
@ -55,20 +34,72 @@ class App.TicketCreate extends App.Controller
@log 'notice', 'error', defaults @log 'notice', 'error', defaults
@render(defaults) @render(defaults)
changeFormType: (e) =>
type = $(e.target).data('type')
if !type
type = $(e.target).parent().data('type')
@setFormTypeInUi(type)
setFormTypeInUi: (type) =>
# detect current form type
if !type
type = @el.find('.type-tabs .tab.active').data('type')
if !type
type = @default_type
# reset all tabs
tabs = @el.find('.type-tabs .tab')
tabs.removeClass('active')
tabIcons = @el.find('.type-tabs .tab .icon')
tabIcons.addClass('gray')
tabIcons.removeClass('white')
# set active tab
selectedTab = @el.find(".type-tabs .tab[data-type='#{type}']")
selectedTab.addClass('active')
selectedTabIcon = @el.find(".type-tabs .tab[data-type='#{type}'] .icon")
selectedTabIcon.removeClass('gray')
selectedTabIcon.addClass('white')
# set form type attributes
articleSenderTypeMap =
'phone-in':
sender: 'Customer'
article: 'phone'
title: 'Call Inbound'
screen: 'create_phone_in'
'phone-out':
sender: 'Agent'
article: 'phone'
title: 'Call Outbound'
screen: 'create_phone_out'
'email-out':
sender: 'Agent'
article: 'email'
title: 'Email'
screen: 'create_email_out'
@articleAttributes = articleSenderTypeMap[type]
# update form
@el.find('[name="formSenderType"]').val(type)
meta: => meta: =>
text = App.i18n.translateInline( @article_attributes['title'] ) text = ''
subject = @el.find('[name=subject]').val() if @articleAttributes
if subject text = App.i18n.translateInline( @articleAttributes['title'] )
text = "#{text}: #{subject}" title = @el.find('[name=title]').val()
if title
text = "#{text}: #{title}"
meta = meta =
url: @url() url: @url()
head: text head: text
title: text title: text
id: @type id: @id
iconClass: 'pen' iconClass: 'pen'
url: => url: =>
'#ticket/create/' + @type + '/id/' + @id '#ticket/create/id/' + @id
activate: => activate: =>
@navupdate '#' @navupdate '#'
@ -101,7 +132,7 @@ class App.TicketCreate extends App.Controller
if cache && !params.ticket_id && !params.article_id if cache && !params.ticket_id && !params.article_id
# get edit form attributes # get edit form attributes
@edit_form = cache.edit_form @form_meta = cache.form_meta
# load assets # load assets
App.Collection.loadAssets( cache.assets ) App.Collection.loadAssets( cache.assets )
@ -109,7 +140,7 @@ class App.TicketCreate extends App.Controller
@render() @render()
else else
@ajax( @ajax(
id: 'ticket_create' id: 'ticket_create' + @task_key
type: 'GET' type: 'GET'
url: @apiPath + '/ticket_create' url: @apiPath + '/ticket_create'
data: data:
@ -122,7 +153,7 @@ class App.TicketCreate extends App.Controller
App.Store.write( 'ticket_create_attributes', data ) App.Store.write( 'ticket_create_attributes', data )
# get edit form attributes # get edit form attributes
@edit_form = data.edit_form @form_meta = data.form_meta
# load assets # load assets
App.Collection.loadAssets( data.assets ) App.Collection.loadAssets( data.assets )
@ -144,43 +175,90 @@ class App.TicketCreate extends App.Controller
render: (template = {}) -> render: (template = {}) ->
# set defaults
defaults =
state_id: App.TicketState.findByAttribute( 'name', 'open' ).id
priority_id: App.TicketPriority.findByAttribute( 'name', '2 normal' ).id
# generate form
configure_attributes = [
{ name: 'customer_id', display: 'Customer', tag: 'autocompletion', type: 'text', limit: 200, null: false, relation: 'User', class: 'span7', autocapitalize: false, help: 'Select the customer of the Ticket or create one.', helpLink: '<a href="" class="customer_new">&raquo;</a>', callback: @localUserInfo, source: @apiPath + '/users/search', minLengt: 2 },
{ name: 'group_id', display: 'Group', tag: 'select', multiple: false, null: false, filter: @edit_form, nulloption: true, relation: 'Group', default: defaults['group_id'], class: 'span7', },
{ name: 'owner_id', display: 'Owner', tag: 'select', multiple: false, null: true, filter: @edit_form, nulloption: true, relation: 'User', default: defaults['owner_id'], class: 'span7', },
{ name: 'tags', display: 'Tags', tag: 'tag', type: 'text', null: true, default: defaults['tags'], class: 'span7', },
{ name: 'subject', display: 'Subject', tag: 'input', type: 'text', limit: 200, null: false, default: defaults['subject'], class: 'span7', },
{ name: 'body', display: 'Text', tag: 'textarea', rows: 8, null: false, default: defaults['body'], class: 'span7', upload: true },
{ name: 'state_id', display: 'State', tag: 'select', multiple: false, null: false, filter: @edit_form, relation: 'TicketState', default: defaults['state_id'], translate: true, class: 'medium' },
{ name: 'priority_id', display: 'Priority', tag: 'select', multiple: false, null: false, filter: @edit_form, relation: 'TicketPriority', default: defaults['priority_id'], translate: true, class: 'medium' },
]
@html App.view('agent_ticket_create')( @html App.view('agent_ticket_create')(
head: 'New Ticket' head: 'New Ticket'
title: @article_attributes['title']
agent: @isRole('Agent') agent: @isRole('Agent')
admin: @isRole('Admin') admin: @isRole('Admin')
) )
params = undefined # get params
params = {}
if template && !_.isEmpty( template.options ) if template && !_.isEmpty( template.options )
params = template.options params = template.options
else if App.TaskManager.get(@task_key) && !_.isEmpty( App.TaskManager.get(@task_key).state ) else if App.TaskManager.get(@task_key) && !_.isEmpty( App.TaskManager.get(@task_key).state )
params = App.TaskManager.get(@task_key).state params = App.TaskManager.get(@task_key).state
formChanges = (params, attribute, attributes, classname, form, ui) =>
if @form_meta.dependencies && @form_meta.dependencies[attribute.name]
dependency = @form_meta.dependencies[attribute.name][ parseInt(params[attribute.name]) ]
if dependency
for fieldNameToChange of dependency
filter = []
if dependency[fieldNameToChange]
filter = dependency[fieldNameToChange]
# find element to replace
for item in attributes
if item.name is fieldNameToChange
item.display = false
item['filter'] = {}
item['filter'][ fieldNameToChange ] = filter
item.default = params[item.name]
#if !item.default
# delete item['default']
newElement = ui.formGenItem( item, classname, form )
# replace new option list
form.find('[name="' + fieldNameToChange + '"]').replaceWith( newElement )
new App.ControllerForm( new App.ControllerForm(
el: @el.find('.ticket_create') el: @el.find('.ticket-form-top')
form_id: @form_id form_id: @form_id
model: model: App.Ticket
configure_attributes: configure_attributes screen: 'create_top'
className: 'create_' + @type + '_' + @id events:
'change [name=customer_id]': @localUserInfo
handlers: [
formChanges
]
filter: @form_meta.filter
autofocus: true autofocus: true
form_data: @edit_form params: params
)
new App.ControllerForm(
el: @el.find('.article-form-top')
form_id: @form_id
model: App.TicketArticle
screen: 'create_top'
params: params
)
new App.ControllerForm(
el: @el.find('.ticket-form-middle')
form_id: @form_id
model: App.Ticket
screen: 'create_middle'
events:
'change [name=customer_id]': @localUserInfo
handlers: [
formChanges
]
filter: @form_meta.filter
params: params
noFieldset: true
)
new App.ControllerForm(
el: @el.find('.ticket-form-bottom')
form_id: @form_id
model: App.Ticket
screen: 'create_bottom'
events:
'change [name=customer_id]': @localUserInfo
handlers: [
formChanges
]
filter: @form_meta.filter
params: params params: params
) )
@ -190,11 +268,15 @@ class App.TicketCreate extends App.Controller
# template_id: template['id'] # template_id: template['id']
# ) # )
# set type selector
@setFormTypeInUi( params['formSenderType'] )
# remember form params of init load
@formDefault = @formParam( @el.find('.ticket-create') ) @formDefault = @formParam( @el.find('.ticket-create') )
# show text module UI # show text module UI
@textModule = new App.WidgetTextModule( @textModule = new App.WidgetTextModule(
el: @el.find('.ticket-create').find('textarea') el: @el.find('form').find('textarea')
) )
$('#tags').tokenfield() $('#tags').tokenfield()
@ -202,14 +284,17 @@ class App.TicketCreate extends App.Controller
# start auto save # start auto save
@autosave() @autosave()
localUserInfo: (params) => localUserInfo: (e) =>
params = App.ControllerForm.params( $(e.target).closest('form') )
# update text module UI # update text module UI
callback = (user) => callback = (user) =>
@textModule.reload( if @textModule
ticket: @textModule.reload(
customer: user ticket:
) customer: user
)
@userInfo( @userInfo(
user_id: params.customer_id user_id: params.customer_id
@ -223,7 +308,8 @@ class App.TicketCreate extends App.Controller
create_screen: @ create_screen: @
) )
cancel: -> cancel: (e) ->
e.preventDefault()
@navigate '#' @navigate '#'
submit: (e) -> submit: (e) ->
@ -237,11 +323,11 @@ class App.TicketCreate extends App.Controller
params.title = params.subject params.title = params.subject
# create ticket # create ticket
object = new App.Ticket ticket = new App.Ticket
# find sender_id # find sender_id
sender = App.TicketArticleSender.findByAttribute( 'name', @article_attributes['sender'] ) sender = App.TicketArticleSender.findByAttribute( 'name', @articleAttributes['sender'] )
type = App.TicketArticleType.findByAttribute( 'name', @article_attributes['article'] ) type = App.TicketArticleType.findByAttribute( 'name', @articleAttributes['article'] )
if params.group_id if params.group_id
group = App.Group.find( params.group_id ) group = App.Group.find( params.group_id )
@ -251,6 +337,7 @@ class App.TicketCreate extends App.Controller
params['article'] = { params['article'] = {
to: (group && group.name) || '' to: (group && group.name) || ''
from: params.customer_id_autocompletion from: params.customer_id_autocompletion
cc: params.cc
subject: params.subject subject: params.subject
body: params.body body: params.body
type_id: type.id type_id: type.id
@ -261,6 +348,7 @@ class App.TicketCreate extends App.Controller
params['article'] = { params['article'] = {
from: (group && group.name) || '' from: (group && group.name) || ''
to: params.customer_id_autocompletion to: params.customer_id_autocompletion
cc: params.cc
subject: params.subject subject: params.subject
body: params.body body: params.body
type_id: type.id type_id: type.id
@ -268,15 +356,38 @@ class App.TicketCreate extends App.Controller
form_id: @form_id form_id: @form_id
} }
object.load(params) ticket.load(params)
# validate form ticketErrorsTop = ticket.validate(
errors = object.validate() screen: 'create_top'
)
ticketErrorsMiddle = ticket.validate(
screen: 'create_middle'
)
ticketErrorsBottom = ticket.validate(
screen: 'create_bottom'
)
article = new App.TicketArticle
article.load( params['article'] )
articleErrors = article.validate(
screen: 'create_top'
)
# collect whole validation result
errors = {}
errors = _.extend( errors, ticketErrorsTop )
errors = _.extend( errors, ticketErrorsMiddle )
errors = _.extend( errors, ticketErrorsBottom )
errors = _.extend( errors, articleErrors )
# show errors in form # show errors in form
if errors if !_.isEmpty( errors )
@log 'error', errors @log 'error', errors
@formValidate( form: e.target, errors: errors ) @formValidate(
form: e.target
errors: errors
)
# save ticket, create article # save ticket, create article
else else
@ -284,7 +395,7 @@ class App.TicketCreate extends App.Controller
# disable form # disable form
@formDisable(e) @formDisable(e)
ui = @ ui = @
object.save( ticket.save(
done: -> done: ->
# notify UI # notify UI
@ -325,10 +436,10 @@ class UserNew extends App.ControllerModal
@html App.view('agent_user_create')( head: 'New User' ) @html App.view('agent_user_create')( head: 'New User' )
new App.ControllerForm( new App.ControllerForm(
el: @el.find('#form-user'), el: @el.find('#form-user')
model: App.User, model: App.User
required: 'quick', screen: 'edit'
autofocus: true, autofocus: true
) )
@modalShow() @modalShow()
@ -390,7 +501,7 @@ class Router extends App.ControllerPermanent
split = "/#{params['ticket_id']}/#{params['article_id']}" split = "/#{params['ticket_id']}/#{params['article_id']}"
id = Math.floor( Math.random() * 99999 ) id = Math.floor( Math.random() * 99999 )
@navigate "#ticket/create/#{params['type']}/id/#{id}#{split}" @navigate "#ticket/create/id/#{id}#{split}"
return return
# cleanup params # cleanup params
@ -400,20 +511,16 @@ class Router extends App.ControllerPermanent
type: params.type type: params.type
id: params.id id: params.id
App.TaskManager.add( 'TicketCreateScreen-' + params['type'] + '-' + params['id'], 'TicketCreate', clean_params ) App.TaskManager.add( 'TicketCreateScreen-' + params['id'], 'TicketCreate', clean_params )
# create new ticket routes/controller # create new ticket routes/controller
App.Config.set( 'ticket/create', Router, 'Routes' ) App.Config.set( 'ticket/create', Router, 'Routes' )
App.Config.set( 'ticket/create/:type', Router, 'Routes' ) App.Config.set( 'ticket/create/', Router, 'Routes' )
App.Config.set( 'ticket/create/:type/id/:id', Router, 'Routes' ) App.Config.set( 'ticket/create/id/:id', Router, 'Routes' )
# split ticket # split ticket
App.Config.set( 'ticket/create/:type/:ticket_id/:article_id', Router, 'Routes' ) App.Config.set( 'ticket/create/:ticket_id/:article_id', Router, 'Routes' )
App.Config.set( 'ticket/create/:type/id/:id/:ticket_id/:article_id', Router, 'Routes' ) App.Config.set( 'ticket/create/id/:id/:ticket_id/:article_id', Router, 'Routes' )
# set new task actions
App.Config.set( 'TicketNewCallOutbound', { prio: 8001, parent: '#new', name: 'Call Outbound', target: '#ticket/create/call_outbound', role: ['Agent'], divider: true }, 'NavBarRight' )
App.Config.set( 'TicketNewCallInbound', { prio: 8002, parent: '#new', name: 'Call Inbound', target: '#ticket/create/call_inbound', role: ['Agent'], divider: true }, 'NavBarRight' )
App.Config.set( 'TicketNewEmail', { prio: 8003, parent: '#new', name: 'Email', target: '#ticket/create/email', role: ['Agent'], divider: true }, 'NavBarRight' )
# set new actions
App.Config.set( 'TicketCreate', { prio: 8003, parent: '#new', name: 'New Ticket', target: '#ticket/create', role: ['Agent'], divider: true }, 'NavBarRight' )

View file

@ -13,11 +13,11 @@ class Index extends App.ControllerContent
# set title # set title
@title 'New Ticket' @title 'New Ticket'
@form_id = App.ControllerForm.formId() @form_id = App.ControllerForm.formId()
@form_meta = undefined
@fetch(params) @fetch(params)
@navupdate '#customer_ticket_new' @navupdate '#customer_ticket_new'
@edit_form = undefined
# get data / in case also ticket data for split # get data / in case also ticket data for split
fetch: (params) -> fetch: (params) ->
@ -27,7 +27,7 @@ class Index extends App.ControllerContent
if cache if cache
# get edit form attributes # get edit form attributes
@edit_form = cache.edit_form @form_meta = cache.form_meta
# load assets # load assets
App.Collection.loadAssets( cache.assets ) App.Collection.loadAssets( cache.assets )
@ -45,7 +45,7 @@ class Index extends App.ControllerContent
App.Store.write( 'ticket_create_attributes', data ) App.Store.write( 'ticket_create_attributes', data )
# get edit form attributes # get edit form attributes
@edit_form = data.edit_form @form_meta = data.form_meta
# load assets # load assets
App.Collection.loadAssets( data.assets ) App.Collection.loadAssets( data.assets )
@ -87,27 +87,77 @@ class Index extends App.ControllerContent
return item if item && _.contains( group_ids, item.id.toString() ) return item if item && _.contains( group_ids, item.id.toString() )
) )
# generate form formChanges = (params, attribute, attributes, classname, form, ui) =>
configure_attributes = [ if @form_meta.dependencies && @form_meta.dependencies[attribute.name]
{ name: 'group_id', display: 'Group', tag: 'select', multiple: false, null: false, filter: groupFilter, nulloption: true, relation: 'Group', default: defaults['group_id'], class: 'span7', }, dependency = @form_meta.dependencies[attribute.name][ parseInt(params[attribute.name]) ]
# { name: 'owner_id', display: 'Owner', tag: 'select', multiple: false, null: true, filter: @edit_form, nulloption: true, relation: 'User', default: defaults['owner_id'], class: 'span7', }, if dependency
{ name: 'subject', display: 'Subject', tag: 'input', type: 'text', limit: 100, null: false, default: defaults['subject'], class: 'span7', },
{ name: 'body', display: 'Text', tag: 'textarea', rows: 10, null: false, default: defaults['body'], class: 'span7', upload: true }, for fieldNameToChange of dependency
# { name: 'state_id', display: 'State', tag: 'select', multiple: false, null: false, filter: @edit_form, relation: 'TicketState', default: defaults['state_id'], translate: true, class: 'medium' }, filter = []
# { name: 'priority_id', display: 'Priority', tag: 'select', multiple: false, null: false, filter: @edit_form, relation: 'TicketPriority', default: defaults['priority_id'], translate: true, class: 'medium' }, if dependency[fieldNameToChange]
] filter = dependency[fieldNameToChange]
# find element to replace
for item in attributes
if item.name is fieldNameToChange
item.display = false
item['filter'] = {}
item['filter'][ fieldNameToChange ] = filter
item.default = params[item.name]
#if !item.default
# delete item['default']
newElement = ui.formGenItem( item, classname, form )
# replace new option list
form.find('[name="' + fieldNameToChange + '"]').replaceWith( newElement )
@html App.view('customer_ticket_create')( head: 'New Ticket' ) @html App.view('customer_ticket_create')( head: 'New Ticket' )
new App.ControllerForm( new App.ControllerForm(
el: @el.find('#form_create') el: @el.find('.ticket-form-top')
form_id: @form_id form_id: @form_id
model: model: App.Ticket
configure_attributes: configure_attributes screen: 'create_top'#@article_attributes['screen']
className: 'create' handlers: [
formChanges
]
filter: @form_meta.filter
autofocus: true autofocus: true
form_data: @edit_form params: defaults
) )
new App.ControllerForm(
el: @el.find('.article-form-top')
form_id: @form_id
model: App.TicketArticle
screen: 'create_top'#@article_attributes['screen']
params: defaults
)
new App.ControllerForm(
el: @el.find('.ticket-form-middle')
form_id: @form_id
model: App.Ticket
screen: 'create_middle'#@article_attributes['screen']
handlers: [
formChanges
]
filter: @form_meta.filter
params: defaults
noFieldset: true
)
#new App.ControllerForm(
# el: @el.find('.ticket-form-bottom')
# form_id: @form_id
# model: App.Ticket
# screen: 'create_bottom'#@article_attributes['screen']
# handlers: [
# formChanges
# ]
# filter: @form_meta.filter
# params: defaults
#)
new App.ControllerDrox( new App.ControllerDrox(
el: @el.find('.sidebar') el: @el.find('.sidebar')
data: data:
@ -128,19 +178,21 @@ class Index extends App.ControllerContent
params.customer_id = @Session.get('id') params.customer_id = @Session.get('id')
# set prio # set prio
priority = App.TicketPriority.findByAttribute( 'name', '2 normal' ) if !params.priority_id
params.priority_id = priority.id priority = App.TicketPriority.findByAttribute( 'name', '2 normal' )
params.priority_id = priority.id
# set state # set state
state = App.TicketState.findByAttribute( 'name', 'new' ) if !params.state_id
params.state_id = state.id state = App.TicketState.findByAttribute( 'name', 'new' )
params.state_id = state.id
# fillup params # fillup params
if !params.title if !params.title
params.title = params.subject params.title = params.subject
# create ticket # create ticket
object = new App.Ticket ticket = new App.Ticket
@log 'CustomerTicketCreate', 'notice', 'updateAttributes', params @log 'CustomerTicketCreate', 'notice', 'updateAttributes', params
# find sender_id # find sender_id
@ -160,16 +212,35 @@ class Index extends App.ControllerContent
form_id: @form_id form_id: @form_id
} }
object.load(params) ticket.load(params)
# validate form # validate form
errors = object.validate() ticketErrorsTop = ticket.validate(
screen: 'create_top'
)
ticketErrorsMiddle = ticket.validate(
screen: 'create_middle'
)
article = new App.TicketArticle
article.load(params['article'])
articleErrors = article.validate(
screen: 'create_top'
)
# collect whole validation
errors = {}
errors = _.extend( errors, ticketErrorsTop )
errors = _.extend( errors, ticketErrorsMiddle )
errors = _.extend( errors, articleErrors )
# show errors in form # show errors in form
if errors if !_.isEmpty(errors)
@log 'CustomerTicketCreate', 'error', 'can not create', errors @log 'CustomerTicketCreate', 'error', 'can not create', errors
@formValidate( form: e.target, errors: errors ) @formValidate(
form: e.target
errors: errors
)
# save ticket, create article # save ticket, create article
else else
@ -177,7 +248,7 @@ class Index extends App.ControllerContent
# disable form # disable form
@formDisable(e) @formDisable(e)
ui = @ ui = @
object.save( ticket.save(
done: -> done: ->
# redirect to zoom # redirect to zoom
@ -189,4 +260,4 @@ class Index extends App.ControllerContent
) )
App.Config.set( 'customer_ticket_new', Index, 'Routes' ) App.Config.set( 'customer_ticket_new', Index, 'Routes' )
App.Config.set( 'CustomerTicketNew', { prio: 8003, parent: '#new', name: 'New Ticket', target: '#customer_ticket_new', role: ['Customer'], divider: true }, 'NavBarRight' ) App.Config.set( 'CustomerTicketNew', { prio: 8003, parent: '#new', name: 'New Ticket', target: '#customer_ticket_new', role: ['Customer'], divider: true }, 'NavBarRight' )

View file

@ -32,7 +32,7 @@ class Index extends App.ControllerContent
new App.ControllerForm( new App.ControllerForm(
el: @el.find('form') el: @el.find('form')
model: App.User model: App.User
required: 'signup' screen: 'signup'
autofocus: true autofocus: true
) )

View file

@ -322,7 +322,7 @@ class Table extends App.ControllerContent
configure_attributes: @configure_attributes_ticket configure_attributes: @configure_attributes_ticket
className: 'create' className: 'create'
form_data: @bulk form_data: @bulk
no_fieldset: true noFieldset: true
) )
#html.delegate('.bulk-action-form', 'submit', (e) => #html.delegate('.bulk-action-form', 'submit', (e) =>
html.bind('submit', (e) => html.bind('submit', (e) =>

View file

@ -5,7 +5,9 @@ class App.TicketZoom extends App.Controller
# check authentication # check authentication
return if !@authenticate() return if !@authenticate()
@edit_form = undefined @navupdate '#'
@form_meta = undefined
@ticket_id = params.ticket_id @ticket_id = params.ticket_id
@article_id = params.article_id @article_id = params.article_id
@signature = undefined @signature = undefined
@ -112,7 +114,7 @@ class App.TicketZoom extends App.Controller
@ticket_article_ids = data.ticket_article_ids @ticket_article_ids = data.ticket_article_ids
# get edit form attributes # get edit form attributes
@edit_form = data.edit_form @form_meta = data.form_meta
# get signature # get signature
@signature = data.signature @signature = data.signature
@ -145,7 +147,7 @@ class App.TicketZoom extends App.Controller
new App.ControllerForm( new App.ControllerForm(
el: @el.find('.edit') el: @el.find('.edit')
model: App.Ticket model: App.Ticket
required: required screen: 'edit'
params: App.Ticket.find(@ticket.id) params: App.Ticket.find(@ticket.id)
) )
# start link info controller # start link info controller
@ -163,13 +165,14 @@ class App.TicketZoom extends App.Controller
new App.ControllerForm( new App.ControllerForm(
el: @el.find('.customer-edit') el: @el.find('.customer-edit')
model: App.User model: App.User
required: 'quick' screen: 'edit'
params: App.User.find(@ticket.customer_id) params: App.User.find(@ticket.customer_id)
) )
new App.ControllerForm( new App.ControllerForm(
el: @el.find('.organization-edit') el: @el.find('.organization-edit')
model: App.Organization model: App.Organization
params: App.Organization.find(@ticket.organitaion_id) params: App.Organization.find(@ticket.organitaion_id)
screen: 'edit'
) )
@TicketAction() @TicketAction()
@ -214,7 +217,8 @@ class App.TicketZoom extends App.Controller
new Edit( new Edit(
ticket: @ticket ticket: @ticket
el: @el.find('.ticket-edit') el: @el.find('.ticket-edit')
edit_form: @edit_form #el: @el.find('.edit')
form_meta: @form_meta
task_key: @task_key task_key: @task_key
ui: @ ui: @
) )
@ -244,9 +248,13 @@ class TicketTitle extends App.Controller
render: (ticket) => render: (ticket) =>
@html App.view('ticket_zoom/title')( @html App.view('ticket_zoom/title')(
ticket: ticket ticket: ticket
isCustomer: @isRole('Customer')
) )
# show frontend times
@frontendTimeUpdate()
update: (e) => update: (e) =>
$this = $(e.target) $this = $(e.target)
title = $this.html() title = $this.html()
@ -298,7 +306,7 @@ class Sidebar extends App.Controller
if name if name
if name is @currentTab if name is @currentTab
@toggleSidebar() @toggleSidebar()
else else
@el.find('.ticket-zoom .sidebar-tab').removeClass('active') @el.find('.ticket-zoom .sidebar-tab').removeClass('active')
$(e.target).closest('.sidebar-tab').addClass('active') $(e.target).closest('.sidebar-tab').addClass('active')
@ -372,57 +380,55 @@ class Edit extends App.Controller
formChanged: !_.isEmpty( App.TaskManager.get(@task_key).state ) formChanged: !_.isEmpty( App.TaskManager.get(@task_key).state )
) )
@configure_attributes_ticket = [
{ name: 'state_id', display: 'State', tag: 'select', multiple: false, null: true, relation: 'TicketState', filter: @edit_form, translate: true, class: 'span2', item_class: 'pull-left' },
{ name: 'priority_id', display: 'Priority', tag: 'select', multiple: false, null: true, relation: 'TicketPriority', filter: @edit_form, translate: true, class: 'span2', item_class: 'pull-left' },
{ name: 'group_id', display: 'Group', tag: 'select', multiple: false, null: true, relation: 'Group', filter: @edit_form, class: 'span2', item_class: 'pull-left' },
{ name: 'owner_id', display: 'Owner', tag: 'select', multiple: false, null: true, relation: 'User', filter: @edit_form, nulloption: true, class: 'span2', item_class: 'pull-left' },
]
if @isRole('Customer')
@configure_attributes_ticket = [
{ name: 'state_id', display: 'State', tag: 'select', multiple: false, null: true, relation: 'TicketState', filter: @edit_form, translate: true, class: 'span2', item_class: 'pull-left' },
{ name: 'priority_id', display: 'Priority', tag: 'select', multiple: false, null: true, relation: 'TicketPriority', filter: @edit_form, translate: true, class: 'span2', item_class: 'pull-left' },
]
@configure_attributes_article = [
{ name: 'type_id', display: 'Type', tag: 'select', multiple: false, null: true, relation: 'TicketArticleType', filter: @edit_form, default: '9', translate: true, class: 'medium' },
{ name: 'internal', display: 'Visibility', tag: 'select', null: true, options: { true: 'internal', false: 'public' }, class: 'medium', item_class: '', default: false },
{ name: 'to', display: 'To', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', hide: true },
{ name: 'cc', display: 'Cc', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', hide: true },
# { name: 'subject', display: 'Subject', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', hide: true },
{ name: 'in_reply_to', display: 'In Reply to', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide' },
{ name: 'body', display: 'Text', tag: 'textarea', rows: 6, limit: 100, null: true, class: 'span7', item_class: '', upload: true },
]
if @isRole('Customer')
@configure_attributes_article = [
{ name: 'to', display: 'To', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', hide: true },
{ name: 'cc', display: 'Cc', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', hide: true },
# { name: 'subject', display: 'Subject', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', hide: true },
{ name: 'in_reply_to', display: 'In Reply to', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide' },
{ name: 'body', display: 'Text', tag: 'textarea', rows: 6, limit: 100, null: true, class: 'span7', item_class: '', upload: true },
]
@form_id = App.ControllerForm.formId() @form_id = App.ControllerForm.formId()
defaults = ticket defaults = ticket.attributes()
if @isRole('Customer')
delete defaults['state_id']
delete defaults['state']
if !_.isEmpty( App.TaskManager.get(@task_key).state ) if !_.isEmpty( App.TaskManager.get(@task_key).state )
defaults = App.TaskManager.get(@task_key).state defaults = App.TaskManager.get(@task_key).state
new App.ControllerForm( formChanges = (params, attribute, attributes, classname, form, ui) =>
el: @el.find('.form-ticket-update') if @form_meta.dependencies && @form_meta.dependencies[attribute.name]
form_id: @form_id dependency = @form_meta.dependencies[attribute.name][ parseInt(params[attribute.name]) ]
model: if dependency
configure_attributes: @configure_attributes_ticket
className: 'update_ticket_' + ticket.id
params: defaults
form_data: @edit_form
)
for fieldNameToChange of dependency
filter = []
if dependency[fieldNameToChange]
filter = dependency[fieldNameToChange]
# find element to replace
for item in attributes
if item.name is fieldNameToChange
item.display = false
item['filter'] = {}
item['filter'][ fieldNameToChange ] = filter
item.default = params[item.name]
#if !item.default
# delete item['default']
newElement = ui.formGenItem( item, classname, form )
# replace new option list
form.find('[name="' + fieldNameToChange + '"]').replaceWith( newElement )
new App.ControllerForm(
el: @el.find('.form-ticket-update')
form_id: @form_id
model: App.Ticket
screen: 'edit'
handlers: [
formChanges
]
filter: @form_meta.filter
params: defaults
)
new App.ControllerForm( new App.ControllerForm(
el: @el.find('.form-article-update') el: @el.find('.form-article-update')
form_id: @form_id form_id: @form_id
model: model: App.TicketArticle
configure_attributes: @configure_attributes_article screen: 'edit'
className: 'update_ticket_' + ticket.id filter:
form_data: @edit_form type_id: [1,9,5]
params: defaults params: defaults
dependency: [ dependency: [
{ {
@ -440,13 +446,24 @@ class Edit extends App.Controller
bind: { bind: {
name: 'type_id' name: 'type_id'
relation: 'TicketArticleType' relation: 'TicketArticleType'
value: ['note', 'twitter status', 'twitter direct-message'] value: ['note', 'phone', 'twitter status']
}, },
change: { change: {
action: 'hide' action: 'hide'
name: ['to', 'cc'], name: ['to', 'cc'],
}, },
}, },
{
bind: {
name: 'type_id'
relation: 'TicketArticleType'
value: ['twitter direct-message']
},
change: {
action: 'show'
name: ['to'],
},
},
] ]
) )
@ -680,10 +697,16 @@ class Edit extends App.Controller
@autosaveStop() @autosaveStop()
params = @formParam(e.target) params = @formParam(e.target)
# get ticket
ticket = App.Ticket.fullLocal( @ticket.id ) ticket = App.Ticket.fullLocal( @ticket.id )
@log 'notice', 'update', params, ticket @log 'notice', 'update', params, ticket
# update local ticket
# create local article
# find sender_id # find sender_id
if @isRole('Customer') if @isRole('Customer')
sender = App.TicketArticleSender.findByAttribute( 'name', 'Customer' ) sender = App.TicketArticleSender.findByAttribute( 'name', 'Customer' )
@ -696,17 +719,16 @@ class Edit extends App.Controller
params.sender_id = sender.id params.sender_id = sender.id
# update ticket # update ticket
ticket_update = {} for key, value of params
for item in @configure_attributes_ticket ticket[key] = value
ticket_update[item.name] = params[item.name]
# check owner assignment # check owner assignment
if !@isRole('Customer') if !@isRole('Customer')
if !ticket_update['owner_id'] if !ticket['owner_id']
ticket_update['owner_id'] = 1 ticket['owner_id'] = 1
# check if title exists # check if title exists
if !ticket_update['title'] && !ticket.title if !ticket['title']
alert( App.i18n.translateContent('Title needed') ) alert( App.i18n.translateContent('Title needed') )
return return
@ -732,22 +754,32 @@ class Edit extends App.Controller
@autosaveStart() @autosaveStart()
return return
ticket.load( ticket_update ) # submit ticket & article
@log 'notice', 'update ticket', ticket_update, ticket @log 'notice', 'update ticket', ticket
# disable form # disable form
@formDisable(e) @formDisable(e)
# validate ticket # validate ticket
errors = ticket.validate() errors = ticket.validate(
screen: 'edit'
)
if errors if errors
@log 'error', 'update', errors @log 'error', 'update', errors
@log 'error', errors
@formValidate(
form: e.target
errors: errors
screen: 'edit'
)
@formEnable(e) @formEnable(e)
@autosaveStart() @autosaveStart()
return return
# validate article # validate article
if params['body'] articleAttributes = App.TicketArticle.attributesGet( 'edit' )
if params['body'] || ( articleAttributes['body'] && articleAttributes['body']['null'] is false )
article = new App.TicketArticle article = new App.TicketArticle
params.from = @Session.get( 'firstname' ) + ' ' + @Session.get( 'lastname' ) params.from = @Session.get( 'firstname' ) + ' ' + @Session.get( 'lastname' )
params.ticket_id = ticket.id params.ticket_id = ticket.id
@ -761,6 +793,11 @@ class Edit extends App.Controller
errors = article.validate() errors = article.validate()
if errors if errors
@log 'error', 'update article', errors @log 'error', 'update article', errors
@formValidate(
form: e.target
errors: errors
screen: 'edit'
)
@formEnable(e) @formEnable(e)
@autosaveStart() @autosaveStart()
return return

View file

@ -109,13 +109,12 @@ class App.WidgetUser extends App.ControllerDrox
edit: (e) => edit: (e) =>
e.preventDefault() e.preventDefault()
new App.ControllerGenericEdit( new App.ControllerGenericEdit(
id: @user_id, id: @user_id
genericObject: 'User', genericObject: 'User'
required: 'quick', screen: 'edit'
pageData: { pageData:
title: 'Users', title: 'Users'
object: 'User', object: 'User'
objects: 'Users', objects: 'Users'
},
callback: @render callback: @render
) )

View file

@ -69,12 +69,26 @@ class App.Auth
App.Event.trigger( 'auth:logout' ) App.Event.trigger( 'auth:logout' )
App.Event.trigger( 'ui:rerender' ) App.Event.trigger( 'ui:rerender' )
# update model definition
if data.models
for model, attributes of data.models
for attribute in attributes
App[model].attributes.push attribute.name
App[model].configure_attributes.push attribute
return false; return false;
# clear local store # clear local store
if type isnt 'check' if type isnt 'check'
App.Event.trigger( 'clearStore' ) App.Event.trigger( 'clearStore' )
# update model definition
if data.models
for model, attributes of data.models
for attribute in attributes
App[model].attributes.push attribute.name
App[model].configure_attributes.push attribute
# update config # update config
for key, value of data.config for key, value of data.config
App.Config.set( key, value ) App.Config.set( key, value )
@ -129,4 +143,3 @@ class App.Auth
App.Event.trigger( 'auth:logout' ) App.Event.trigger( 'auth:logout' )
App.Event.trigger( 'ui:rerender' ) App.Event.trigger( 'ui:rerender' )
App.Event.trigger( 'clearStore' ) App.Event.trigger( 'clearStore' )

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

0
app/assets/javascripts/app/lib/spine/ajax.coffee Executable file → Normal file
View file

0
app/assets/javascripts/app/lib/spine/bindings.coffee Executable file → Normal file
View file

0
app/assets/javascripts/app/lib/spine/list.coffee Executable file → Normal file
View file

0
app/assets/javascripts/app/lib/spine/local.coffee Executable file → Normal file
View file

0
app/assets/javascripts/app/lib/spine/manager.coffee Executable file → Normal file
View file

9
app/assets/javascripts/app/lib/spine/relation.coffee Executable file → Normal file
View file

@ -1,6 +1,5 @@
Spine = @Spine or require('spine') Spine = @Spine or require('spine')
isArray = Spine.isArray isArray = Spine.isArray
require = @require or ((value) -> eval(value))
class Collection extends Spine.Module class Collection extends Spine.Module
constructor: (options = {}) -> constructor: (options = {}) ->
@ -111,8 +110,14 @@ underscore = (str) ->
.replace(/-/g, '_') .replace(/-/g, '_')
.toLowerCase() .toLowerCase()
requireModel = (model) ->
if typeof model is 'string'
require?(model) or eval(model)
else
model
association = (name, model, record, fkey, Ctor) -> association = (name, model, record, fkey, Ctor) ->
model = require(model) if typeof model is 'string' model = requireModel(model) if typeof model is 'string'
new Ctor(name: name, model: model, record: record, fkey: fkey) new Ctor(name: name, model: model, record: record, fkey: fkey)
Spine.Model.extend Spine.Model.extend

30
app/assets/javascripts/app/lib/spine/route.coffee Executable file → Normal file
View file

@ -71,6 +71,9 @@ class Route extends Spine.Module
@change() @change()
@unbind: -> @unbind: ->
unbindResult = Spine.Events.unbind.apply this, arguments
return unbindResult if arguments.length > 0
return if @options.shim return if @options.shim
if @history if @history
@ -80,33 +83,30 @@ class Route extends Spine.Module
@navigate: (args...) -> @navigate: (args...) ->
options = {} options = {}
lastArg = args[args.length - 1] lastArg = args[args.length - 1]
if typeof lastArg is 'object' if typeof lastArg is 'object'
options = args.pop() options = args.pop()
else if typeof lastArg is 'boolean' else if typeof lastArg is 'boolean'
options.trigger = args.pop() options.trigger = args.pop()
options = $.extend({}, @options, options) options = $.extend({}, @options, options)
path = args.join('/') path = args.join('/')
return if @path is path return if @path is path
@path = path @path = path
@trigger('navigate', @path) if options.trigger
@trigger('navigate', @path)
routes = @matchRoutes(@path, options)
unless routes.length
if typeof options.redirect is 'function'
return options.redirect.apply this, [@path, options]
else
if options.redirect is true
@redirect(@path)
routes = @matchRoutes(@path, options) if options.trigger if options.shim
true
return if options.shim else if @history and options.replace
unless routes.length
if typeof options.redirect is 'function'
return options.redirect.apply this, [@path, options]
else
if options.redirect is true
@redirect(@path)
if @history and options.replace
history.replaceState({}, document.title, @path) history.replaceState({}, document.title, @path)
else if @history else if @history
history.pushState({}, document.title, @path) history.pushState({}, document.title, @path)

17
app/assets/javascripts/app/lib/spine/spine.coffee Executable file → Normal file
View file

@ -149,13 +149,14 @@ class Model extends Module
@toString: -> "#{@className}(#{@attributes.join(", ")})" @toString: -> "#{@className}(#{@attributes.join(", ")})"
@find: (id, notFound = @notFound) -> @find: (id, notFound = @notFound) ->
record = @irecords[id]?.clone() @irecords[id]?.clone() or notFound?(id)
return record or notFound?(id)
@notFound: (id) -> return null @findAll: (ids, notFound) ->
(@find(id) for id in ids when @find(id, notFound))
@exists: (id) -> @notFound: (id) -> null
return if @irecords[id] then true else false
@exists: (id) -> Boolean @irecords[id]
@addRecord: (record, options = {}) -> @addRecord: (record, options = {}) ->
if record.id and @irecords[record.id] if record.id and @irecords[record.id]
@ -321,8 +322,8 @@ class Model extends Module
result result
eql: (rec) -> eql: (rec) ->
!!(rec and rec.constructor is @constructor and rec and rec.constructor is @constructor and
((rec.cid is @cid) or (rec.id and rec.id is @id))) ((rec.cid is @cid) or (rec.id and rec.id is @id))
save: (options = {}) -> save: (options = {}) ->
unless options.validate is false unless options.validate is false
@ -634,7 +635,7 @@ makeArray = (args) ->
Spine = @Spine = {} Spine = @Spine = {}
module?.exports = Spine module?.exports = Spine
Spine.version = '1.3.1' Spine.version = '1.3.2'
Spine.isArray = isArray Spine.isArray = isArray
Spine.isBlank = isBlank Spine.isBlank = isBlank
Spine.$ = $ Spine.$ = $

View file

@ -73,55 +73,116 @@ class App.Model extends Spine.Model
'' ''
@validate: ( data = {} ) -> @validate: ( data = {} ) ->
return if !data['model'].configure_attributes
# based on model attrbutes
if App[ data['model'] ] && App[ data['model'] ].attributesGet
attributes = App[ data['model'] ].attributesGet( data['screen'] )
# based on custom attributes
else if data['model'].configure_attributes
attributes = App.Model.attributesGet( data['screen'], data['model'].configure_attributes )
# check required_if attributes
for attributeName, attribute of attributes
if attribute['required_if']
for key, values of attribute['required_if']
localValues = data['params'][key]
if !_.isArray( localValues )
localValues = [ localValues ]
match = false
for value in values
if localValues
for localValue in localValues
if value && localValue && value.toString() is localValue.toString()
match = true
if match is true
attribute['null'] = false
else
attribute['null'] = true
# check attributes/each attribute of object # check attributes/each attribute of object
errors = {} errors = {}
for attribute in data['model'].configure_attributes for attributeName, attribute of attributes
# only if attribute is not read only # only if attribute is not read only
if !attribute.readonly if !attribute.readonly
# 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']
# check :: fields # check :: fields
parts = attribute.name.split '::' parts = attribute.name.split '::'
if parts[0] && !parts[1] if parts[0] && !parts[1]
# key exists not in hash || value is '' || value is undefined # 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 if !( attributeName of data['params'] ) || data['params'][attributeName] is '' || data['params'][attributeName] is undefined
errors[attribute.name] = 'is required' errors[attributeName] = 'is required'
else if parts[0] && parts[1] && !parts[2] else if parts[0] && parts[1] && !parts[2]
# key exists not in hash || value is '' || value is undefined # 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 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' errors[attributeName] = 'is required'
else else
throw "can't parse '#{attribute.name}'" 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'][attributeName] && "#{attributeName}_confirm" of data['params']
# get confirm password # get confirm password
if data['params'][attribute.name] isnt data['params']["#{attribute.name}_confirm"] if data['params'][attributeName] isnt data['params']["#{attributeName}_confirm"]
errors[attribute.name] = 'didn\'t match' errors[attributeName] = 'didn\'t match'
errors["#{attribute.name}_confirm"] = '' errors["#{attributeName}_confirm"] = ''
# return error object # return error object
if !_.isEmpty(errors) if !_.isEmpty(errors)
console.log 'error', 'validation vailed', errors console.log 'error', 'validation failed', errors
return errors return errors
# return no errors # return no errors
return return
validate: -> ###
attributes = App.Model.attributesGet(optionalScreen, optionalAttributesList)
###
@attributesGet: (screen = undefined, attributes = false) ->
if !attributes
attributes = clone( App[ @.className ].configure_attributes )
else
attributes = clone( attributes )
# in case if no configure_attributes exist
return if !attributes
attributesNew = {}
# check params of screen if screen is requested
if screen
for attribute in attributes
if attribute.screen
if attribute && attribute.screen && attribute.screen[ screen ] && !_.isEmpty( attribute.screen[ screen ] )
for item, value of attribute.screen[ screen ]
attribute[item] = value
attributesNew[ attribute.name ] = attribute
if !screen || _.isEmpty( attributesNew )
for attribute in attributes
attributesNew[ attribute.name ] = attribute
console.log(attributesNew)
attributesNew
validate: (params = {}) ->
App.Model.validate( App.Model.validate(
model: @constructor, model: @constructor.className
params: @, params: @
screen: params.screen
) )
isOnline: -> isOnline: ->

View file

@ -5,7 +5,7 @@ class App.Group extends App.Model
@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: 'assignment_timeout', display: 'Assignment Timout', tag: 'input', note: 'Assignment timout 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, '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.', '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.', '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.', '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.', 'class': 'span4' },
{ 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, class: 'span4' },
@ -19,4 +19,4 @@ class App.Group extends App.Model
] ]
uiUrl: -> uiUrl: ->
'#group/zoom/' + @id '#group/zoom/' + @id

View file

@ -6,20 +6,20 @@ 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, class: 'span4', autocapitalize: false, signup: false, quick: false },
{ name: 'firstname', display: 'Firstname', tag: 'input', type: 'text', limit: 100, null: false, class: 'span4', signup: true, quick: true, info: true, invite_agent: true }, { name: 'firstname', display: 'Firstname', 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, class: 'span4', signup: true, quick: 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: 'email', display: 'Email', tag: 'input', type: 'email', limit: 100, null: false, class: 'span4', signup: true, quick: 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: 'web', display: 'Web', tag: 'input', type: 'url', limit: 100, null: true, class: 'span4', signup: false, quick: true, info: true }, { name: 'web', display: 'Web', tag: 'input', type: 'url', limit: 100, null: true, class: 'span4', signup: false, info: true },
{ name: 'phone', display: 'Phone', tag: 'input', type: 'phone', limit: 100, null: true, class: 'span4', signup: false, quick: true, info: true }, { name: 'phone', display: 'Phone', 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, class: 'span4', signup: false, quick: true, info: true }, { name: 'mobile', display: 'Mobile', 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, class: 'span4', signup: false, quick: true, info: true }, { name: 'fax', display: 'Fax', tag: 'input', type: 'phone', limit: 100, null: true, class: 'span4', signup: false, info: true },
{ name: 'organization_id', display: 'Organization', tag: 'select', multiple: false, nulloption: true, null: true, relation: 'Organization', class: 'span4', signup: false, quick: true, info: true }, { name: 'organization_id', display: 'Organization', tag: 'select', multiple: false, nulloption: true, null: true, relation: 'Organization', class: 'span4', signup: false, info: true },
{ name: 'department', display: 'Department', tag: 'input', type: 'text', limit: 200, null: true, class: 'span4', signup: false, quick: true, info: true }, { name: 'department', display: 'Department', tag: 'input', type: 'text', limit: 200, null: true, class: 'span4', signup: false, info: true },
{ name: 'street', display: 'Street', tag: 'input', type: 'text', limit: 100, null: true, class: 'span4', signup: false, quick: true, info: true }, { name: 'street', display: 'Street', 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, class: 'span4', signup: false, quick: true, info: true }, { name: 'zip', display: 'Zip', 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, class: 'span4', signup: false, quick: true, info: true }, { name: 'city', display: 'City', tag: 'input', type: 'text', limit: 100, null: true, class: 'span4', signup: false, info: true },
{ name: 'password', display: 'Password', tag: 'input', type: 'password', limit: 50, null: true, autocomplete: 'off', class: 'span4', signup: true, quick: false }, { name: 'password', display: 'Password', tag: 'input', type: 'password', limit: 50, null: true, autocomplete: 'off', class: 'span4', signup: true, },
{ name: 'note', display: 'Note', tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, null: true, class: 'span4', quick: true, info: 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: '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', class: 'span4' },
{ 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', class: 'span4', 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, class: 'span4' },

View file

@ -2,87 +2,41 @@
<div class="create-new main flex"> <div class="create-new main flex">
<div class="box"> <div class="box">
<div class="page-header"> <div class="page-header">
<h1><%- @T( 'Create New Ticket' ) %></h1> <h1><%- @T( @head ) %></h1>
</div> </div>
<ul class="horizontal tabs type-tabs"> <ul class="horizontal tabs type-tabs">
<li class="tab u-textTruncate active"> <li class="tab u-textTruncate" data-type="phone-in">
<div class="white email channel icon"></div>
<%- @T( 'E-Mail' ) %>
<li class="tab u-textTruncate">
<div class="gray received-calls channel icon"></div> <div class="gray received-calls channel icon"></div>
<%- @T( 'Received Call' ) %> <%- @T( 'Received Call' ) %>
</li>
<li class="tab u-textTruncate"> <li class="tab u-textTruncate" data-type="phone-out">
<div class="gray outbound-calls channel icon"></div> <div class="gray outbound-calls channel icon"></div>
<%- @T( 'Outbound Call' ) %> <%- @T( 'Outbound Call' ) %>
</li>
<li class="tab u-textTruncate" data-type="email-out">
<div class="gray email channel icon"></div>
<%- @T( 'Send E-Mail' ) %>
</li>
</ul> </ul>
<form role="form"> <form role="form" class="form-large ticket-create">
<input type="hidden" name="formSenderType"/>
<div class="form-group"> <div class="ticket-form-top"></div>
<label for="customer"><%- @T('Customer') %></label> <div class="article-form-top"></div>
<input class="form-control" id="customer" placeholder="<%- @T('Enter Person or Organisation/Company') %>">
</div>
<div class="form-group">
<label for="subject"><%- @T('Subject') %></label>
<input class="form-control" id="subject">
</div>
<div class="form-group">
<label for="text"><%- @T('Text') %></label>
<textarea class="form-control" id="text" rows="4"></textarea>
</div>
<div class="formset-inset"> <div class="formset-inset">
<div class="horizontal two-columns"> <div class="ticket-form-middle horizontal two-columns"></div>
<div class="form-group column"> <div class="ticket-form-bottom"></div>
<label for="owner"><%- @T('Owner') %></label>
<select class="form-control" id="owner">
<option>Support -> Oliver Ruhm</option>
<option>Engineering -> Web-Dev</option>
</select>
</div>
<div class="form-group column">
<label for="type"><%- @T('Type') %></label>
<select class="form-control" id="type">
<option>Inquiry</option>
<option>Support</option>
<option selected>Question</option>
</select>
</div>
<div class="form-group column">
<label for="status"><%- @T('Status') %></label>
<select class="form-control" id="status">
<option selected>open</option>
<option>closed</option>
</select>
</div>
<div class="form-group column">
<label for="proprity"><%- @T('Priority') %></label>
<select class="form-control" id="proprity">
<option>low</option>
<option selected>normal</option>
<option>high</option>
</select>
</div>
</div>
<div class="form-group">
<label for="tags"><%- @T('Tags') %></label>
<input class="form-control" id="tags" placeholder="<%- @T('Tag hinzufügen') %>" value="New Website, Feedback">
</div>
</div> </div>
<input type="hidden" value="" name="article_type"/>
<div class="form-actions horizontal"> <div class="form-actions horizontal">
<a class="subtle-link standalone cancel" href="#/"><%- @T( 'Cancel & Go Back' ) %></a> <a class="subtle-link standalone cancel" href="#/"><%- @T( 'Cancel & Go Back' ) %></a>
<button type="submit" class="btn btn-create submit align-right"><%- @T( 'Create Ticket' ) %></button> <button type="submit" class="btn btn-create submit align-right"><%- @T( 'Create' ) %></button>
</div> </div>
</form> </form>
</div> </div>
@ -208,4 +162,4 @@
<div class="text_module"></div> <div class="text_module"></div>
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,18 +1,27 @@
<div class="main flex"> <div class="create-new horizontal flex">
<div class="create-new main flex">
<div class="box">
<div class="page-header">
<h1><%- @T( 'New Ticket' ) %></h1>
</div>
<div class="ticket-create vertical"> <form role="form" class="form-large ticket-create">
<div class="page-header">
<h1 class="pull-left"><%- @T( 'New Ticket' ) %></h1> <div class="ticket-form-top"></div>
</div> <div class="article-form-top"></div>
<div class="page-content">
<form class="form-horizontal form-large"> <div class="formset-inset">
<input type="hidden" value="" name="article_type"/> <div class="ticket-form-middle horizontal two-columns"></div>
<div id="form_create"></div> <div class="ticket-form-bottom"></div>
<div class="form-actions"> </div>
<button type="reset" class="btn btn-default cancel"><%- @T( 'Cancel' ) %></button>
<button type="submit" class="btn btn-primary submit"><%- @T( 'Create' ) %></button>
<div class="form-actions horizontal">
<a class="subtle-link standalone cancel" href="#/"><%- @T( 'Cancel & Go Back' ) %></a>
<button type="submit" class="btn btn-create submit align-right"><%- @T( 'Create' ) %></button>
</div> </div>
</form> </form>
</div> </div>
</div> </div>

View file

@ -1,5 +1,5 @@
<div class="form-group <%= @attribute.item_class %>"> <div class="form-group <%= @attribute.item_class %>">
<label for="<%= @attribute.id %>"><%- @T( @attribute.display ) %><% if !@attribute.null: %> *<% end %></label> <label for="<%= @attribute.id %>"><%- @T( @attribute.display ) %> <span><% if !@attribute.null: %>*<% end %></span></label>
<div class="controls"> <div class="controls">
<%- @item %><% if @attribute.note: %><span class="glyphicon glyphicon-question-sign help-message" title="<%- @Ti( @attribute.note ) + ' ' %>"></span><% end %> <%- @item %><% if @attribute.note: %><span class="glyphicon glyphicon-question-sign help-message" title="<%- @Ti( @attribute.note ) + ' ' %>"></span><% end %>
<% if @attribute.remove: %><span><a href="#" class="glyphicon glyphicon-minus"></a></span><% end %> <% if @attribute.remove: %><span><a href="#" class="glyphicon glyphicon-minus"></a></span><% end %>

View file

@ -1,3 +1,3 @@
<input id="<%= @attribute.id %>" type="hidden" name="<%= @attribute.name %>" value="<%= @attribute.value %>" <%= @attribute.required %> /> <input id="<%= @attribute.id %>" type="hidden" name="<%= @attribute.name %>" value="<%= @attribute.value %>" <%= @attribute.required %> />
<input id="<%= @attribute.id %>_autocompletion" type="text" name="<%= @attribute.name %>_autocompletion" value="<%= @attribute.valueShown %>" class="form-control <%= @attribute.class %>" <%= @attribute.required %> <%= @attribute.autofocus %> <%- @attribute.autocapitalize %>/> <input id="<%= @attribute.id %>_autocompletion" type="text" name="<%= @attribute.name %>_autocompletion" value="<%= @attribute.valueShown %>" class="form-control <%= @attribute.class %>" <%= @attribute.required %> <%= @attribute.autofocus %> <%- @attribute.autocapitalize %> <% if @attribute.placeholder: %>placeholder="<%- @T(@attribute.placeholder) %>"<% end %>/>
<input id="<%= @attribute.id %>_autocompletion_value_shown" type="hidden" name="<%= @attribute.name %>_autocompletion_value_shown" value="<%= @attribute.valueShown %>"/> <input id="<%= @attribute.id %>_autocompletion_value_shown" type="hidden" name="<%= @attribute.name %>_autocompletion_value_shown" value="<%= @attribute.valueShown %>"/>

View file

@ -0,0 +1 @@
<input id="<%= @attribute.id %>" type="<%= @attribute.type %>" class="form-control <%= @attribute.class %>" placeholder="<%= @attribute.placeholder %>" name="<%= @attribute.name %>" value="<%= @attribute.value %>" <%= @attribute.required %>>

View file

@ -1 +1 @@
<input id="<%= @attribute.id %>" type="<%= @attribute.type %>" name="<%= @attribute.name %>" value="<%= @attribute.value %>" class="form-control <%= @attribute.class %>" <%= @attribute.required %> <%= @attribute.autofocus %> <%- @attribute.autocapitalize %> <%- @attribute.autocomplete %>/> <input id="<%= @attribute.id %>" type="<%= @attribute.type %>" name="<%= @attribute.name %>" value="<%= @attribute.value %>" class="form-control <%= @attribute.class %>" <% if @attribute.placeholder: %>placeholder="<%- @T(@attribute.placeholder) %>"<% end %> <%= @attribute.required %> <%= @attribute.autofocus %> <%- @attribute.autocapitalize %> <%- @attribute.autocomplete %>/>

View file

@ -1,5 +1,7 @@
<select id="<%= @attribute.id %>" class="form-control <%= @attribute.class %>" name="<%= @attribute.name %>" <%= @attribute.multiple %> <%= @attribute.required %> <%= @attribute.autofocus %>> <select id="<%= @attribute.id %>" class="form-control <%= @attribute.class %>" name="<%= @attribute.name %>" <%= @attribute.multiple %> <%= @attribute.required %> <%= @attribute.autofocus %>>
<% if @attribute.options: %>
<% for row in @attribute.options: %> <% for row in @attribute.options: %>
<option value="<%= row.value %>" <%= row.selected %> <%= row.disabled %>><%= row.name %></option> <option value="<%= row.value %>" <%= row.selected %> <%= row.disabled %>><%= row.name %></option>
<% end %> <% end %>
<% end %>
</select> </select>

View file

@ -1,8 +1,14 @@
<% for item in @items: %> <% for item in @items: %>
<% if item.child: %> <% if item.child: %>
<li class="dropdown <%= item.class %> <% if @open_tab[item.target] : %>open<% end %>"> <li class="dropdown <%= item.class %> <% if @open_tab[item.target] : %>open<% end %>">
<a href="<%= item.target %>" class="dropdown-toggle" data-toggle="dropdown"> <a href="<%= item.target %>" class="dropdown-toggle horizontal center" data-toggle="dropdown">
<%- @T( item.name ) %> <b class="caret"></b> <span class="nav-item-icon">
<span class="<%= item.class %> icon"></span>
</span>
<span class="nav-item-name flex">
<%- @T( item.name ) %>
</span>
<b class="caret"></b>
</a> </a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<% for item in item.child: %> <% for item in item.child: %>

View file

@ -5,9 +5,9 @@
// the compiled file. // the compiled file.
// //
//= require ./app/lib/core/jquery-1.11.0.js //= require ./app/lib/core/jquery-2.1.1.js
//= require ./app/lib/core/jquery-ui-1.8.23.custom.min.js //= require ./app/lib/core/jquery-ui-1.8.23.custom.min.js
//= require ./app/lib/core/underscore-1.6.0.js //= require ./app/lib/core/underscore-1.7.0.js
//= require ./app/lib/animations/velocity.min.js //= require ./app/lib/animations/velocity.min.js
//= require ./app/lib/animations/velocity.ui.js //= require ./app/lib/animations/velocity.ui.js
@ -69,6 +69,13 @@ function difference(object1, object2) {
return changes; return changes;
} }
function clone(object) {
if (!object) {
return object
}
return JSON.parse(JSON.stringify(object));
}
jQuery.event.special.remove = { jQuery.event.special.remove = {
remove: function(e) { remove: function(e) {
if (e.handler) e.handler(); if (e.handler) e.handler();

View file

@ -658,13 +658,13 @@ label {
.form-control:focus, .form-control:focus,
.tokenfield.focus { .tokenfield.focus {
box-shadow: none; box-shadow: none;
border-color: #419ed7; border-color: #419ed7 !important;
} }
.has-error .form-control, .has-error .form-control,
.has-error .form-control:focus { .has-error .form-control:focus {
box-shadow: none; box-shadow: none;
border-color: red; border-color: red !important;
} }
.help-inline { .help-inline {
@ -752,6 +752,9 @@ label {
margin-left: 10px; margin-left: 10px;
} }
.help-block {
color: #bcbcbc;
}
.form-horizontal .help-inline, .form-horizontal .help-block { .form-horizontal .help-inline, .form-horizontal .help-block {
font-size: 12px; font-size: 12px;
margin-top: 4px; margin-top: 4px;
@ -3240,7 +3243,7 @@ footer {
.tokenfield .token { .tokenfield .token {
padding: 0 0 0 10px; padding: 0 0 0 10px;
margin: -1px 5px 0 0; margin: -1px 5px 8px 0;
height: 26px; height: 26px;
line-height: 27px; line-height: 27px;
color: white; color: white;
@ -3255,7 +3258,7 @@ footer {
} }
.tokenfield .token .token-label { .tokenfield .token .token-label {
padding: 0; padding: 0;
} }
.tokenfield.form-control { .tokenfield.form-control {

View file

@ -33,8 +33,12 @@ class SessionsController < ApplicationController
# auto population of default collections # auto population of default collections
collections, assets = SessionHelper::default_collections(user) collections, assets = SessionHelper::default_collections(user)
# add session user assets
assets = user.assets(assets) assets = user.assets(assets)
# get models
models = SessionHelper::models(user)
# check logon session # check logon session
logon_session_key = nil logon_session_key = nil
if params['logon_session'] if params['logon_session']
@ -50,6 +54,7 @@ class SessionsController < ApplicationController
# return new session data # return new session data
render :json => { render :json => {
:session => user, :session => user,
:models => models,
:collections => collections, :collections => collections,
:assets => assets, :assets => assets,
:logon_session => logon_session_key, :logon_session => logon_session_key,
@ -75,9 +80,13 @@ class SessionsController < ApplicationController
end end
if !user_id if !user_id
# get models
models = SessionHelper::models()
render :json => { render :json => {
:error => 'no valid session', :error => 'no valid session',
:config => config_frontend, :config => config_frontend,
:models => models,
} }
return return
end end
@ -89,13 +98,18 @@ class SessionsController < ApplicationController
# auto population of default collections # auto population of default collections
collections, assets = SessionHelper::default_collections(user) collections, assets = SessionHelper::default_collections(user)
# add session user assets
assets = user.assets(assets) assets = user.assets(assets)
# get models
models = SessionHelper::models(user)
# return current session # return current session
render :json => { render :json => {
:session => user, :session => user,
:models => models,
:collections => collections, :collections => collections,
:assets => assets, :assets => assets,
:config => config_frontend, :config => config_frontend,
} }
end end

View file

@ -255,24 +255,12 @@ class TicketsController < ApplicationController
) )
end end
# get related users
assets = {}
assets = ticket.assets(assets)
# get attributes to update # get attributes to update
attributes_to_change = Ticket::ScreenOptions.attributes_to_change( :user => current_user, :ticket => ticket ) attributes_to_change = Ticket::ScreenOptions.attributes_to_change( :user => current_user, :ticket => ticket )
attributes_to_change[:owner_id].each { |user_id| # get related users
user = User.find(user_id) assets = attributes_to_change[:assets]
assets = user.assets(assets) assets = ticket.assets(assets)
}
attributes_to_change[:group_id__owner_id].each {|group_id, user_ids|
user_ids.each {|user_id|
user = User.find(user_id)
assets = user.assets(assets)
}
}
# get related articles # get related articles
articles = Ticket::Article.where( :ticket_id => params[:id] ) articles = Ticket::Article.where( :ticket_id => params[:id] )
@ -297,6 +285,7 @@ class TicketsController < ApplicationController
:ticket_article_ids => article_ids, :ticket_article_ids => article_ids,
:signature => signature, :signature => signature,
:assets => assets, :assets => assets,
:form_meta => attributes_to_change,
:edit_form => attributes_to_change, :edit_form => attributes_to_change,
} }
end end
@ -307,24 +296,11 @@ class TicketsController < ApplicationController
# get attributes to update # get attributes to update
attributes_to_change = Ticket::ScreenOptions.attributes_to_change( attributes_to_change = Ticket::ScreenOptions.attributes_to_change(
:user => current_user, :user => current_user,
# :ticket_id => params[:ticket_id], :ticket_id => params[:ticket_id],
# :article_id => params[:article_id] :article_id => params[:article_id]
) )
assets = {} assets = attributes_to_change[:assets]
assets[ User.to_app_model ] = {}
attributes_to_change[:owner_id].each { |user_id|
user = User.find(user_id)
assets = user.assets(assets)
}
attributes_to_change[:group_id__owner_id].each {|group_id, user_ids|
user_ids.each {|user_id|
user = User.find(user_id)
assets = user.assets(assets)
}
}
# split data # split data
split = {} split = {}
if params[:ticket_id] && params[:article_id] if params[:ticket_id] && params[:article_id]
@ -332,12 +308,6 @@ class TicketsController < ApplicationController
split[:ticket_id] = ticket.id split[:ticket_id] = ticket.id
assets = ticket.assets(assets) assets = ticket.assets(assets)
owner_ids = []
ticket.agent_of_group.each { |user|
owner_ids.push user.id
assets = user.assets(assets)
}
# get related articles # get related articles
article = Ticket::Article.find( params[:article_id] ) article = Ticket::Article.find( params[:article_id] )
split[:article_id] = article.id split[:article_id] = article.id
@ -348,13 +318,19 @@ class TicketsController < ApplicationController
render :json => { render :json => {
:split => split, :split => split,
:assets => assets, :assets => assets,
:edit_form => attributes_to_change, :form_meta => {
:filter => attributes_to_change[:filter],
:dependencies => attributes_to_change[:dependencies],
}
} }
end end
# GET /api/v1/tickets/search # GET /api/v1/tickets/search
def search def search
# permit nested conditions
params.require(:condition).permit!
# build result list # build result list
tickets = Ticket.search( tickets = Ticket.search(
:limit => params[:limit], :limit => params[:limit],

View file

@ -0,0 +1,147 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
class ObjectManager
=begin
add a new activity entry for an object
ObjectManager.listObjects()
=end
def self.listObjects
['Ticket', 'TicketArticle', 'Group', 'Organization', 'User']
end
end
class ObjectManager::Attribute < ApplicationModel
self.table_name = 'object_manager_attributes'
belongs_to :object_lookup, :class_name => 'ObjectLookup'
validates :name, :presence => true
store :screens
store :data_option
=begin
add a new activity entry for an object
ObjectManager::Attribute.add(
:object => 'Ticket',
:name => 'group_id',
:frontend => 'Group',
:data_type => 'select',
:data_option => {
:relation => 'Group',
:relation_condition => { :access => 'rw' },
:multiple => false,
:null => true,
},
:editable => false,
:active => true,
:screens => {
:create => {
'-all-' => {
:required => true,
},
},
:edit => {
:Agent => {
:required => true,
},
},
},
:pending_migration => false,
:position => 20,
:created_by_id => 1,
:updated_by_id => 1,
:created_at => '2014-06-04 10:00:00',
:updated_at => '2014-06-04 10:00:00',
)
=end
def self.add(data)
# lookups
if data[:object]
data[:object_lookup_id] = ObjectLookup.by_name( data[:object] )
end
data.delete(:object)
# check newest entry - is needed
result = ObjectManager::Attribute.where(
:object_lookup_id => data[:object_lookup_id],
:name => data[:name],
).first
if result
# raise "ERROR: attribute #{data[:name]} for #{data[:object]} already exists"
return result.update_attributes(data)
end
# create history
ObjectManager::Attribute.create(data)
end
=begin
get list of object attributes
attribute_list = ObjectManager::Attribute.by_object('Ticket', user)
returns:
[
{ :name => 'api_key', :display => 'API KEY', :tag => 'input', :null => true, :edit => true, :maxlength => 32 },
{ :name => 'api_ip_regexp', :display => 'API IP RegExp', :tag => 'input', :null => true, :edit => true },
{ :name => 'api_ip_max', :display => 'API IP Max', :tag => 'input', :null => true, :edit => true },
]
=end
def self.by_object(object, user)
# lookups
if object
object_lookup_id = ObjectLookup.by_name( object )
end
# get attributes in right order
result = ObjectManager::Attribute.where(
:object_lookup_id => object_lookup_id,
:active => true,
).order('position ASC')
attributes = []
result.each {|item|
data = {
:name => item.name,
:display => item.display,
:tag => item.data_type,
#:null => item.null,
}
if item.screens
data[:screen] = {}
item.screens.each {|screen, roles_options |
data[:screen][screen] = {}
roles_options.each {|role, options|
if role == '-all-'
data[:screen][screen] = options
elsif user && user.is_role(role)
data[:screen][screen] = options
end
}
}
end
if item.data_option
data = data.merge( item.data_option )
end
attributes.push data
}
attributes
end
end

View file

@ -56,6 +56,8 @@ class Ticket < ApplicationModel
belongs_to :create_article_type, :class_name => 'Ticket::Article::Type' belongs_to :create_article_type, :class_name => 'Ticket::Article::Type'
belongs_to :create_article_sender, :class_name => 'Ticket::Article::Sender' belongs_to :create_article_sender, :class_name => 'Ticket::Article::Sender'
self.inheritance_column = nil
attr_accessor :callback_loop attr_accessor :callback_loop
=begin =begin

View file

@ -50,6 +50,9 @@ returns
params[:article] = self.find( params[:article_id] ) params[:article] = self.find( params[:article_id] )
end end
filter = {}
assets = {}
# get ticket states # get ticket states
state_ids = [] state_ids = []
if params[:ticket] if params[:ticket]
@ -63,44 +66,21 @@ returns
state_type = Ticket::StateType.where( :name => type ).first state_type = Ticket::StateType.where( :name => type ).first
if state_type if state_type
state_type.states.each {|state| state_type.states.each {|state|
assets = state.assets(assets)
state_ids.push state.id state_ids.push state.id
} }
end end
} }
filter[:state_id] = state_ids
# get owner
owner_ids = []
if params[:ticket]
params[:ticket].agent_of_group.each { |user|
owner_ids.push user.id
}
end
# get group
group_ids = []
Group.where( :active => true ).each { |group|
group_ids.push group.id
}
# get group / user relations
agents = {}
Ticket::ScreenOptions.agents.each { |user|
agents[ user.id ] = 1
}
groups_users = {}
group_ids.each {|group_id|
groups_users[ group_id ] = []
Group.find( group_id ).users.each {|user|
next if !agents[ user.id ]
groups_users[ group_id ].push user.id
}
}
# get priorities # get priorities
priority_ids = [] priority_ids = []
Ticket::Priority.where( :active => true ).each { |priority| Ticket::Priority.where( :active => true ).each { |priority|
assets = priority.assets(assets)
priority_ids.push priority.id priority_ids.push priority.id
} }
filter[:priority_id] = priority_ids
type_ids = [] type_ids = []
if params[:ticket] if params[:ticket]
@ -115,14 +95,29 @@ returns
end end
} }
end end
filter[:type_id] = type_ids
# get group / user relations
agents = {}
Ticket::ScreenOptions.agents.each { |user|
agents[ user.id ] = 1
}
dependencies = { :group_id => { '' => [] } }
Group.where( :active => true ).each { |group|
assets = group.assets(assets)
dependencies[:group_id][group.id] = { :owner_id => [] }
group.users.each {|user|
next if !agents[ user.id ]
assets = user.assets(assets)
dependencies[:group_id][ group.id ][ :owner_id ].push user.id
}
}
return { return {
:type_id => type_ids, :assets => assets,
:state_id => state_ids, :filter => filter,
:priority_id => priority_ids, :dependencies => dependencies,
:owner_id => owner_ids,
:group_id => group_ids,
:group_id__owner_id => groups_users,
} }
end end
@ -131,8 +126,8 @@ returns
list tickets by customer groupd in state categroie open and closed list tickets by customer groupd in state categroie open and closed
result = Ticket::ScreenOptions.list_by_customer( result = Ticket::ScreenOptions.list_by_customer(
:customer_id => 123, :customer_id => 123,
:limit => 15, # optional, default 15 :limit => 15, # optional, default 15
) )
returns returns
@ -152,13 +147,13 @@ returns
# get tickets # get tickets
tickets_open = Ticket.where( tickets_open = Ticket.where(
: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')
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')
return { return {

View file

@ -0,0 +1,16 @@
<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/model.js"></script>
<style type="text/css">
body {
padding-top: 0px;
}
</style>
<script type="text/javascript">
</script>
<div id="qunit"></div>

View file

@ -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-ui', :to => 'tests#ui', :via => :get match '/tests-ui', :to => 'tests#ui', :via => :get
match '/tests-model', :to => 'tests#model', :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-table', :to => 'tests#table', :via => :get
match '/tests/wait/:sec', :to => 'tests#wait', :via => :get match '/tests/wait/:sec', :to => 'tests#wait', :via => :get

File diff suppressed because it is too large Load diff

View file

@ -1311,20 +1311,20 @@ Link::Object.create_if_not_exists( :name => 'Question/Answer' )
Link::Object.create_if_not_exists( :name => 'Idea' ) Link::Object.create_if_not_exists( :name => 'Idea' )
Link::Object.create_if_not_exists( :name => 'Bug' ) Link::Object.create_if_not_exists( :name => 'Bug' )
Ticket::StateType.create_if_not_exists( :name => 'new', :updated_by_id => 1 ) Ticket::StateType.create_if_not_exists( :id => 1, :name => 'new', :updated_by_id => 1 )
Ticket::StateType.create_if_not_exists( :name => 'open', :updated_by_id => 1 ) Ticket::StateType.create_if_not_exists( :id => 2, :name => 'open', :updated_by_id => 1 )
Ticket::StateType.create_if_not_exists( :name => 'pending reminder', :updated_by_id => 1 ) Ticket::StateType.create_if_not_exists( :id => 3, :name => 'pending reminder', :updated_by_id => 1 )
Ticket::StateType.create_if_not_exists( :name => 'pending action', :updated_by_id => 1 ) Ticket::StateType.create_if_not_exists( :id => 4, :name => 'pending action', :updated_by_id => 1 )
Ticket::StateType.create_if_not_exists( :name => 'closed', :updated_by_id => 1 ) Ticket::StateType.create_if_not_exists( :id => 5, :name => 'closed', :updated_by_id => 1 )
Ticket::StateType.create_if_not_exists( :name => 'merged', :updated_by_id => 1 ) Ticket::StateType.create_if_not_exists( :id => 6, :name => 'merged', :updated_by_id => 1 )
Ticket::StateType.create_if_not_exists( :name => 'removed', :updated_by_id => 1 ) Ticket::StateType.create_if_not_exists( :id => 7, :name => 'removed', :updated_by_id => 1 )
Ticket::State.create_if_not_exists( :name => 'new', :state_type_id => Ticket::StateType.where(:name => 'new').first.id ) Ticket::State.create_if_not_exists( :id => 1, :name => 'new', :state_type_id => Ticket::StateType.where(:name => 'new').first.id )
Ticket::State.create_if_not_exists( :name => 'open', :state_type_id => Ticket::StateType.where(:name => 'open').first.id ) Ticket::State.create_if_not_exists( :id => 2, :name => 'open', :state_type_id => Ticket::StateType.where(:name => 'open').first.id )
Ticket::State.create_if_not_exists( :name => 'pending', :state_type_id => Ticket::StateType.where(:name => 'pending reminder').first.id ) Ticket::State.create_if_not_exists( :id => 3, :name => 'pending', :state_type_id => Ticket::StateType.where(:name => 'pending reminder').first.id )
Ticket::State.create_if_not_exists( :name => 'closed', :state_type_id => Ticket::StateType.where(:name => 'closed').first.id ) Ticket::State.create_if_not_exists( :id => 4, :name => 'closed', :state_type_id => Ticket::StateType.where(:name => 'closed').first.id )
Ticket::State.create_if_not_exists( :name => 'merged', :state_type_id => Ticket::StateType.where(:name => 'merged').first.id ) Ticket::State.create_if_not_exists( :id => 5, :name => 'merged', :state_type_id => Ticket::StateType.where(:name => 'merged').first.id )
Ticket::State.create_if_not_exists( :name => 'removed', :state_type_id => Ticket::StateType.where(:name => 'removed').first.id ) Ticket::State.create_if_not_exists( :id => 6, :name => 'removed', :state_type_id => Ticket::StateType.where(:name => 'removed').first.id )
Ticket::Priority.create_if_not_exists( :name => '1 low' ) Ticket::Priority.create_if_not_exists( :name => '1 low' )
Ticket::Priority.create_if_not_exists( :name => '2 normal' ) Ticket::Priority.create_if_not_exists( :name => '2 normal' )
@ -1683,7 +1683,7 @@ Translation.create_if_not_exists( :locale => 'de', :source => "Direction", :targ
Translation.create_if_not_exists( :locale => 'de', :source => "Owner", :target => "Besitzer" ) Translation.create_if_not_exists( :locale => 'de', :source => "Owner", :target => "Besitzer" )
Translation.create_if_not_exists( :locale => 'de', :source => "Subject", :target => "Betreff" ) Translation.create_if_not_exists( :locale => 'de', :source => "Subject", :target => "Betreff" )
Translation.create_if_not_exists( :locale => 'de', :source => "Priority", :target => "Priorität" ) Translation.create_if_not_exists( :locale => 'de', :source => "Priority", :target => "Priorität" )
Translation.create_if_not_exists( :locale => 'de', :source => "Select the customer of the Ticket or create one.", :target => "Wähle den Kundn f<>r das Ticket oder erstell einen neuen." ) Translation.create_if_not_exists( :locale => 'de', :source => "Select the customer of the ticket or create one.", :target => "Wähle den Kunden f<>r das Ticket oder erstelle einen Neuen." )
Translation.create_if_not_exists( :locale => 'de', :source => "New Ticket", :target => "Neues Ticket" ) Translation.create_if_not_exists( :locale => 'de', :source => "New Ticket", :target => "Neues Ticket" )
Translation.create_if_not_exists( :locale => 'de', :source => "Firstname", :target => "Vorname" ) Translation.create_if_not_exists( :locale => 'de', :source => "Firstname", :target => "Vorname" )
Translation.create_if_not_exists( :locale => 'de', :source => "Lastname", :target => "Nachname" ) Translation.create_if_not_exists( :locale => 'de', :source => "Lastname", :target => "Nachname" )
@ -1756,7 +1756,7 @@ Translation.create_if_not_exists( :locale => 'de', :source => "Forgot your passw
Translation.create_if_not_exists( :locale => 'de', :source => "Templates", :target => "Vorlagen" ) Translation.create_if_not_exists( :locale => 'de', :source => "Templates", :target => "Vorlagen" )
Translation.create_if_not_exists( :locale => 'de', :source => "Delete", :target => "Löschen" ) Translation.create_if_not_exists( :locale => 'de', :source => "Delete", :target => "Löschen" )
Translation.create_if_not_exists( :locale => 'de', :source => "Apply", :target => "Übernehmen" ) Translation.create_if_not_exists( :locale => 'de', :source => "Apply", :target => "Übernehmen" )
Translation.create_if_not_exists( :locale => 'de', :source => "Save as Template", :target => "Als Template speichern" ) Translation.create_if_not_exists( :locale => 'de', :source => "Save as Template", :target => "Als Vorlage speichern" )
Translation.create_if_not_exists( :locale => 'de', :source => "Save", :target => "Speichern" ) Translation.create_if_not_exists( :locale => 'de', :source => "Save", :target => "Speichern" )
Translation.create_if_not_exists( :locale => 'de', :source => "Open Tickets", :target => "Offene Ticket" ) Translation.create_if_not_exists( :locale => 'de', :source => "Open Tickets", :target => "Offene Ticket" )
Translation.create_if_not_exists( :locale => 'de', :source => "Closed Tickets", :target => "Geschlossene Ticket" ) Translation.create_if_not_exists( :locale => 'de', :source => "Closed Tickets", :target => "Geschlossene Ticket" )
@ -1771,7 +1771,7 @@ Translation.create_if_not_exists( :locale => 'de', :source => "3 high", :target
Translation.create_if_not_exists( :locale => 'de', :source => "public", :target => "öffentlich" ) Translation.create_if_not_exists( :locale => 'de', :source => "public", :target => "öffentlich" )
Translation.create_if_not_exists( :locale => 'de', :source => "internal", :target => "intern" ) Translation.create_if_not_exists( :locale => 'de', :source => "internal", :target => "intern" )
Translation.create_if_not_exists( :locale => 'de', :source => "Attach files", :target => "Dateien anhängen" ) Translation.create_if_not_exists( :locale => 'de', :source => "Attach files", :target => "Dateien anhängen" )
Translation.create_if_not_exists( :locale => 'de', :source => "Visability", :target => "Sichtbarkeit" ) Translation.create_if_not_exists( :locale => 'de', :source => "Visibility", :target => "Sichtbarkeit" )
Translation.create_if_not_exists( :locale => 'de', :source => "Actions", :target => "Aktionen" ) Translation.create_if_not_exists( :locale => 'de', :source => "Actions", :target => "Aktionen" )
Translation.create_if_not_exists( :locale => 'de', :source => "Email", :target => "E-Mail" ) Translation.create_if_not_exists( :locale => 'de', :source => "Email", :target => "E-Mail" )
Translation.create_if_not_exists( :locale => 'de', :source => "email", :target => "E-Mail" ) Translation.create_if_not_exists( :locale => 'de', :source => "email", :target => "E-Mail" )
@ -1791,7 +1791,7 @@ Translation.create_if_not_exists( :locale => 'de', :source => "Change Customer",
Translation.create_if_not_exists( :locale => 'de', :source => "My Tickets", :target => "Meine Tickets" ) Translation.create_if_not_exists( :locale => 'de', :source => "My Tickets", :target => "Meine Tickets" )
Translation.create_if_not_exists( :locale => 'de', :source => "My Organization Tickets", :target => "Meine Organisations Tickets" ) Translation.create_if_not_exists( :locale => 'de', :source => "My Organization Tickets", :target => "Meine Organisations Tickets" )
Translation.create_if_not_exists( :locale => 'de', :source => "My Organization", :target => "Meine Organisation" ) Translation.create_if_not_exists( :locale => 'de', :source => "My Organization", :target => "Meine Organisation" )
Translation.create_if_not_exists( :locale => 'de', :source => "Assignment Timout", :target => "Zeitliche Zuweisungsüberschritung" ) Translation.create_if_not_exists( :locale => 'de', :source => "Assignment Timeout", :target => "Zeitliche Zuweisungsüberschritung" )
Translation.create_if_not_exists( :locale => 'de', :source => "We've sent password reset instructions to your email address.", :target => "Wir haben Ihnen die Anleitung zum zurücksetzen Ihres Passworts an Ihre E-Mail-Adresse gesendet." ) Translation.create_if_not_exists( :locale => 'de', :source => "We've sent password reset instructions to your email address.", :target => "Wir haben Ihnen die Anleitung zum zurücksetzen Ihres Passworts an Ihre E-Mail-Adresse gesendet." )
Translation.create_if_not_exists( :locale => 'de', :source => "Enter your username or email address", :target => "Bitte geben Sie Ihren Benutzernamen oder E-Mail-Adresse ein" ) Translation.create_if_not_exists( :locale => 'de', :source => "Enter your username or email address", :target => "Bitte geben Sie Ihren Benutzernamen oder E-Mail-Adresse ein" )
Translation.create_if_not_exists( :locale => 'de', :source => "Choose your new password.", :target => "Wählen Sie Ihr neues Passwort." ) Translation.create_if_not_exists( :locale => 'de', :source => "Choose your new password.", :target => "Wählen Sie Ihr neues Passwort." )

View file

@ -16,6 +16,16 @@ module SessionHelper
return default_collection, assets return default_collection, assets
end end
def self.models(user = nil)
models = {}
objects = ObjectManager.listObjects
objects.each {|object|
attributes = ObjectManager::Attribute.by_object(object, user)
models[object] = attributes
}
models
end
def self.cleanup_expired def self.cleanup_expired
# web sessions # web sessions

View file

@ -8,9 +8,9 @@ class Sessions::Backend::TicketCreate
def load def load
# get whole collection # get attributes to update
ticket_create_attributes = Ticket::ScreenOptions.attributes_to_change( ticket_create_attributes = Ticket::ScreenOptions.attributes_to_change(
:current_user_id => @user.id, :user => @user.id,
) )
# no data exists # no data exists
@ -38,32 +38,31 @@ class Sessions::Backend::TicketCreate
# set new timeout # set new timeout
Sessions::CacheIn.set( self.client_key, true, { :expires_in => 25.seconds } ) Sessions::CacheIn.set( self.client_key, true, { :expires_in => 25.seconds } )
create_attributes = self.load ticket_create_attributes = self.load
return if !ticket_create_attributes
return if !create_attributes
users = {}
create_attributes[:owner_id].each {|user_id|
if !users[user_id]
users[user_id] = User.find(user_id).attributes
end
}
data = { data = {
:users => users, :assets => ticket_create_attributes[:assets],
:edit_form => create_attributes, :form_meta => {
:filter => ticket_create_attributes[:filter],
:dependencies => ticket_create_attributes[:dependencies],
}
} }
if !@client if !@client
return { return {
:collection => 'ticket_create_attributes', :collection => 'ticket_create_attributes',
:data => create_attributes, :data => data,
} }
end end
@client.log 'notify', "push ticket_create for user #{ @user.id }" @client.log 'notify', "push ticket_create for user #{ @user.id }"
@client.send({ @client.send({
:collection => 'ticket_create_attributes', :collection => 'ticket_create_attributes',
:data => create_attributes, :data => data,
}) })
end end

View file

@ -495,3 +495,54 @@ test( "form selector", function() {
deepEqual( params, test_params, 'form param check via $("#form").parent()' ); deepEqual( params, test_params, 'form param check via $("#form").parent()' );
}); });
test( "form required_if + shown_if", function() {
$('#forms').append('<hr><h1>form required_if + shown_if</h1><div><form id="form7"></form></div>')
var el = $('#form7')
var defaults = {
input2: 'some name66',
}
new App.ControllerForm({
el: el,
model: {
configure_attributes: [
{ name: 'input1', display: 'Input1', tag: 'input', type: 'text', limit: 100, null: true, default: 'some not used default33' },
{ name: 'input2', display: 'Input2', tag: 'input', type: 'text', limit: 100, null: true, default: 'some used default', required_if: { active: true }, shown_if: { active: true } },
{ name: 'active', display: 'Active', tag: 'boolean', type: 'boolean', 'default': true, null: false },
],
},
params: defaults,
});
test_params = {
input1: "some not used default33",
input2: "some name66",
active: true
};
params = App.ControllerForm.params( el )
deepEqual( params, test_params, 'form param check via $("#form")' );
equal( el.find('[name="input2"]').attr('required'), 'required', 'check required attribute of input2 ')
equal( el.find('[name="input2"]').is(":visible"), true, 'check visible attribute of input2 ')
el.find('[name="active"]').val('{boolean}::false').trigger('change')
test_params = {
input1: "some not used default33",
active: false
};
params = App.ControllerForm.params( el )
deepEqual( params, test_params, 'form param check via $("#form")' );
equal( el.find('[name="input2"]').attr('required'), undefined, 'check required attribute of input2 ')
equal( el.find('[name="input2"]').is(":visible"), false, 'check visible attribute of input2 ')
el.find('[name="active"]').val('{boolean}::true').trigger('change')
test_params = {
input1: "some not used default33",
input2: "some name66",
active: true
};
params = App.ControllerForm.params( el )
deepEqual( params, test_params, 'form param check via $("#form")' );
equal( el.find('[name="input2"]').attr('required'), 'required', 'check required attribute of input2 ')
equal( el.find('[name="input2"]').is(":visible"), true, 'check visible attribute of input2 ')
});

View file

@ -0,0 +1,200 @@
// model
test( "model basic tests", function() {
// define model
var configure_attributes_org = _.clone( App.Ticket.configure_attributes )
var attribute1 = {
name: 'test1', display: 'Test 1', tag: 'input', type: 'text', limit: 200, 'null': false
};
App.Ticket.configure_attributes.push( attribute1 )
var attribute2 = {
name: 'test2', display: 'Test 2', tag: 'input', type: 'text', limit: 200, 'null': true
};
App.Ticket.configure_attributes.push( attribute2 )
var attribute3 = {
name: 'pending_time1', display: 'Pending till1', tag: 'input', type: 'text', limit: 200, 'null': false, required_if: { state_id: [3] },
};
App.Ticket.configure_attributes.push( attribute3 )
var attribute4 = {
name: 'pending_time2', display: 'Pending till2', tag: 'input', type: 'text', limit: 200, 'null': true, required_if: { state_id: [3] },
};
App.Ticket.configure_attributes.push( attribute4 )
// check validation
console.log('TEST 1')
var ticket = new App.Ticket()
ticket.load({title: 'some title'})
var error = ticket.validate()
ok( error['group_id'], 'group_id is required')
ok( !error['title'], 'title is required')
ok( error['state_id'], 'state_id is required')
ok( error['test1'], 'test1 is required')
ok( !error['test2'], 'test2 is not required')
ok( !error['pending_time1'], 'pending_time1 is not required')
ok( !error['pending_time2'], 'pending_time2 is not required')
console.log('TEST 2')
ticket.title = 'some new title'
ticket.state_id = [2,3]
ticket.test2 = 123
error = ticket.validate()
ok( error['group_id'], 'group_id is required')
ok( !error['title'], 'title exists')
ok( !error['state_id'], 'state_id is')
ok( error['test1'], 'test1 is required')
ok( !error['test2'], 'test2 is not required')
ok( error['pending_time1'], 'pending_time1 is required')
ok( error['pending_time2'], 'pending_time2 is required')
console.log('TEST 3')
ticket.title = 'some new title'
ticket.state_id = [2,1]
ticket.test2 = 123
error = ticket.validate()
ok( error['group_id'], 'group_id is required')
ok( !error['title'], 'title exists')
ok( !error['state_id'], 'state_id is')
ok( error['test1'], 'test1 is required')
ok( !error['test2'], 'test2 is not required')
ok( !error['pending_time1'], 'pending_time1 is required')
ok( !error['pending_time2'], 'pending_time2 is required')
console.log('TEST 4')
ticket.title = 'some new title'
ticket.state_id = [2,3]
ticket.test2 = 123
error = ticket.validate()
ok( error['group_id'], 'group_id is required')
ok( !error['title'], 'title exists')
ok( !error['state_id'], 'state_id is')
ok( error['test1'], 'test1 is required')
ok( !error['test2'], 'test2 is not required')
ok( error['pending_time1'], 'pending_time1 is required')
ok( error['pending_time2'], 'pending_time2 is required')
console.log('TEST 5')
ticket.title = 'some new title'
ticket.state_id = [2,3]
ticket.test2 = 123
ticket.pending_time1 = '2014-10-10 09:00'
error = ticket.validate()
ok( error['group_id'], 'group_id is required')
ok( !error['title'], 'title exists')
ok( !error['state_id'], 'state_id is')
ok( error['test1'], 'test1 is required')
ok( !error['test2'], 'test2 is not required')
ok( !error['pending_time1'], 'pending_time1 is required')
ok( error['pending_time2'], 'pending_time2 is required')
// define model with screen
App.Ticket.configure_attributes = configure_attributes_org
var attribute1 = {
name: 'test1', display: 'Test 1', tag: 'input', type: 'text', limit: 200, 'null': false, screen: { some_screen: { required_if: { state_id: [3] } } },
};
App.Ticket.configure_attributes.push( attribute1 )
var attribute2 = {
name: 'test2', display: 'Test 2', tag: 'input', type: 'text', limit: 200, 'null': true, screen: { some_screen: { required_if: { state_id: [3] } } },
};
App.Ticket.configure_attributes.push( attribute2 )
var attribute3 = {
name: 'group_id', display: 'Group', tag: 'select', multiple: false, null: false, relation: 'Group', screen: { some_screen: { null: false } },
};
App.Ticket.configure_attributes.push( attribute3 )
var attribute4 = {
name: 'owner_id', display: 'Owner', tag: 'select', multiple: false, null: false, relation: 'User', screen: { some_screen: { null: false } },
};
App.Ticket.configure_attributes.push( attribute4 )
var attribute5 = {
name: 'state_id', display: 'State', tag: 'select', multiple: false, null: false, relation: 'TicketState', screen: { some_screen: { null: false } },
};
App.Ticket.configure_attributes.push( attribute5 )
// check validation with screen
console.log('TEST 6')
ticket = new App.Ticket()
ticket.load({title: 'some title'})
error = ticket.validate()
ok( error['group_id'], 'group_id is required')
ok( !error['title'], 'title is required')
ok( error['state_id'], 'state_id is required')
ok( error['test1'], 'test1 is required')
ok( !error['test2'], 'test2 is not required')
console.log('TEST 7')
ticket.state_id = 3
error = ticket.validate()
ok( error['group_id'], 'group_id is required')
ok( !error['title'], 'title is required')
ok( !error['state_id'], 'state_id is required')
ok( error['test1'], 'test1 is required')
ok( !error['test2'], 'test2 is not required')
console.log('TEST 8')
ticket.state_id = 2
error = ticket.validate()
ok( error['group_id'], 'group_id is required')
ok( !error['title'], 'title is required')
ok( !error['state_id'], 'state_id is required')
ok( error['test1'], 'test1 is required')
ok( !error['test2'], 'test2 is not required')
console.log('TEST 9')
ticket.state_id = undefined
error = ticket.validate({screen: 'some_screen'})
ok( error['group_id'], 'group_id is required')
ok( !error['title'], 'title is required')
ok( error['state_id'], 'state_id is required')
ok( !error['test1'], 'test1 is required')
ok( !error['test2'], 'test2 is required')
console.log('TEST 10')
ticket.state_id = 2
error = ticket.validate({screen: 'some_screen'})
ok( error['group_id'], 'group_id is required')
ok( !error['title'], 'title is required')
ok( !error['state_id'], 'state_id is required')
ok( !error['test1'], 'test1 is required')
ok( !error['test2'], 'test2 is not required')
console.log('TEST 11')
ticket.state_id = 3
error = ticket.validate({screen: 'some_screen'})
ok( error['group_id'], 'group_id is required')
ok( !error['title'], 'title is required')
ok( !error['state_id'], 'state_id is required')
ok( error['test1'], 'test1 is required')
ok( error['test2'], 'test2 is required')
console.log('TEST 12')
ticket.state_id = 2
error = ticket.validate()
ok( error['group_id'], 'group_id is required')
ok( !error['title'], 'title is required')
ok( !error['state_id'], 'state_id is required')
ok( error['test1'], 'test1 is required')
ok( !error['test2'], 'test2 is not required')
console.log('TEST 13')
ticket.state_id = 3
error = ticket.validate()
ok( error['group_id'], 'group_id is required')
ok( !error['title'], 'title is required')
ok( !error['state_id'], 'state_id is required')
ok( error['test1'], 'test1 is required')
ok( !error['test2'], 'test2 is required')
console.log('TEST 14')
ticket.state_id = 2
error = ticket.validate()
ok( error['group_id'], 'group_id is required')
ok( !error['title'], 'title is required')
ok( !error['state_id'], 'state_id is required')
ok( error['test1'], 'test1 is required')
ok( !error['test2'], 'test2 is not required')
});

View file

@ -46,6 +46,28 @@ class AAbUnitTest < TestCase
] ]
browser_single_test(tests) browser_single_test(tests)
end end
def test_model
tests = [
{
:name => 'start',
:instance => browser_instance,
:url => browser_url + '/tests-model',
: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 = [
{ {

View file

@ -111,8 +111,9 @@ class AgentTicketActionsLevel3Test < TestCase
{ {
:where => :instance2, :where => :instance2,
:execute => 'match', :execute => 'match',
:css => '.content_permanent.active', :css => '.content_permanent.active .reset-message',
:value => 'Discard your unsaved changes.', :value => '(Discard your unsaved changes.|Verwerfen der)',
:no_quote => true,
:match_result => true, :match_result => true,
}, },
{ {
@ -127,8 +128,9 @@ class AgentTicketActionsLevel3Test < TestCase
{ {
:where => :instance2, :where => :instance2,
:execute => 'match', :execute => 'match',
:css => '.content_permanent.active', :css => '.content_permanent.active .reset-message',
:value => 'Discard your unsaved changes.', :value => '(Discard your unsaved changes.|Verwerfen der)',
:no_quote => true,
:match_result => false, :match_result => false,
}, },
@ -150,8 +152,9 @@ class AgentTicketActionsLevel3Test < TestCase
{ {
:where => :instance1, :where => :instance1,
:execute => 'match', :execute => 'match',
:css => '.content_permanent.active', :css => '.content_permanent.active .reset-message',
:value => 'Discard your unsaved changes.', :value => '(Discard your unsaved changes.|Verwerfen der)',
:no_quote => true,
:match_result => true, :match_result => true,
}, },
@ -204,8 +207,9 @@ class AgentTicketActionsLevel3Test < TestCase
{ {
:where => :instance1, :where => :instance1,
:execute => 'match', :execute => 'match',
:css => '.content_permanent.active', :css => '.content_permanent.active .reset-message',
:value => 'Discard your unsaved changes.', :value => '(Discard your unsaved changes.|Verwerfen der)',
:no_quote => true,
:match_result => false, :match_result => false,
}, },
{ {
@ -219,8 +223,9 @@ class AgentTicketActionsLevel3Test < TestCase
{ {
:where => :instance2, :where => :instance2,
:execute => 'match', :execute => 'match',
:css => '.content_permanent.active', :css => '.content_permanent.active .reset-message',
:value => 'Discard your unsaved changes.', :value => '(Discard your unsaved changes.|Verwerfen der)',
:no_quote => true,
:match_result => false, :match_result => false,
}, },
@ -246,8 +251,9 @@ class AgentTicketActionsLevel3Test < TestCase
{ {
:where => :instance1, :where => :instance1,
:execute => 'match', :execute => 'match',
:css => '.content_permanent.active', :css => '.content_permanent.active .reset-message',
:value => 'Discard your unsaved changes.', :value => '(Discard your unsaved changes.|Verwerfen der)',
:no_quote => true,
:match_result => false, :match_result => false,
}, },
{ {
@ -261,8 +267,9 @@ class AgentTicketActionsLevel3Test < TestCase
{ {
:where => :instance2, :where => :instance2,
:execute => 'match', :execute => 'match',
:css => '.content_permanent.active', :css => '.content_permanent.active .reset-message',
:value => 'Discard your unsaved changes.', :value => '(Discard your unsaved changes.|Verwerfen der)',
:no_quote => true,
:match_result => false, :match_result => false,
}, },
@ -280,8 +287,9 @@ class AgentTicketActionsLevel3Test < TestCase
{ {
:where => :instance2, :where => :instance2,
:execute => 'match', :execute => 'match',
:css => '.content_permanent.active', :css => '.content_permanent.active .reset-message',
:value => 'Discard your unsaved changes.', :value => '(Discard your unsaved changes.|Verwerfen der)',
:no_quote => true,
:match_result => true, :match_result => true,
}, },
{ {
@ -298,8 +306,9 @@ class AgentTicketActionsLevel3Test < TestCase
{ {
:where => :instance2, :where => :instance2,
:execute => 'match', :execute => 'match',
:css => '.content_permanent.active', :css => '.content_permanent.active .reset-message',
:value => 'Discard your unsaved changes.', :value => '(Discard your unsaved changes.|Verwerfen der)',
:no_quote => true,
:match_result => true, :match_result => true,
}, },
{ {
@ -315,7 +324,9 @@ class AgentTicketActionsLevel3Test < TestCase
:where => :instance2, :where => :instance2,
:execute => 'match', :execute => 'match',
:css => '.content_permanent.active', :css => '.content_permanent.active',
:value => 'Discard your unsaved changes.', :css => '.content_permanent.active .reset-message',
:value => '(Discard your unsaved changes.|Verwerfen der)',
:no_quote => true,
:match_result => false, :match_result => false,
}, },
{ {

View file

@ -3,8 +3,8 @@ require 'browser_test_helper'
class AgentTicketActionLevel5Test < TestCase class AgentTicketActionLevel5Test < TestCase
def test_I def test_I
random = 'text_module_test_' + rand(999999).to_s random = 'text_module_test_' + rand(99999999).to_s
random2 = 'text_module_test_' + rand(999999).to_s random2 = 'text_module_test_' + rand(99999999).to_s
# user # user
tests = [ tests = [
@ -153,9 +153,9 @@ class AgentTicketActionLevel5Test < TestCase
browser_signle_test_with_login(tests, { :username => 'master@example.com' }) browser_signle_test_with_login(tests, { :username => 'master@example.com' })
end end
def test_II def test_II
random = 'text_II_module_test_' + rand(999999).to_s random = 'text_II_module_test_' + rand(99999999).to_s
user_rand = rand(999999).to_s user_rand = rand(99999999).to_s
login = 'agent-text-module-' + user_rand login = 'agent-text-module-' + user_rand
firstname = 'Text' + user_rand firstname = 'Text' + user_rand
lastname = 'Module' + user_rand lastname = 'Module' + user_rand
@ -191,7 +191,7 @@ class AgentTicketActionLevel5Test < TestCase
{ {
:where => :instance2, :where => :instance2,
:execute => 'set', :execute => 'set',
:css => '.active input[name=subject]', :css => '.active input[name=title]',
:value => 'A', :value => 'A',
}, },
{ {
@ -207,7 +207,7 @@ class AgentTicketActionLevel5Test < TestCase
{ {
:where => :instance2, :where => :instance2,
:execute => 'set', :execute => 'set',
:css => '.active input[name=subject]', :css => '.active input[name=title]',
:value => 'B', :value => 'B',
}, },
@ -330,7 +330,7 @@ class AgentTicketActionLevel5Test < TestCase
{ {
:where => :instance2, :where => :instance2,
:execute => 'set', :execute => 'set',
:css => '.active .ticket_create input[name="customer_id_autocompletion"]', :css => '.active .ticket-create input[name="customer_id_autocompletion"]',
:value => 'nicole', :value => 'nicole',
}, },
{ {
@ -340,13 +340,13 @@ class AgentTicketActionLevel5Test < TestCase
{ {
:where => :instance2, :where => :instance2,
:execute => 'sendkey', :execute => 'sendkey',
:css => '.active .ticket_create input[name="customer_id_autocompletion"]', :css => '.active .ticket-create input[name="customer_id_autocompletion"]',
:value => :arrow_down, :value => :arrow_down,
}, },
{ {
:where => :instance2, :where => :instance2,
:execute => 'sendkey', :execute => 'sendkey',
:css => '.active .ticket_create input[name="customer_id_autocompletion"]', :css => '.active .ticket-create input[name="customer_id_autocompletion"]',
:value => :tab, :value => :tab,
}, },
{ {
@ -425,7 +425,7 @@ class AgentTicketActionLevel5Test < TestCase
}, },
{ {
:execute => 'wait', :execute => 'wait',
:value => 4, :value => 2,
}, },
{ {
:where => :instance2, :where => :instance2,
@ -536,7 +536,7 @@ class AgentTicketActionLevel5Test < TestCase
}, },
{ {
:execute => 'wait', :execute => 'wait',
:value => 0.2, :value => 0.5,
}, },
# { # {
# :where => :instance2, # :where => :instance2,

View file

@ -142,7 +142,7 @@ class AgentUserManageTest < TestCase
}, },
{ {
:execute => 'set', :execute => 'set',
:css => '.active .ticket_create input[name="customer_id_autocompletion"]', :css => '.active .ticket-create input[name="customer_id_autocompletion"]',
:value => customer_user_email, :value => customer_user_email,
}, },
{ {
@ -151,12 +151,12 @@ class AgentUserManageTest < TestCase
}, },
{ {
:execute => 'sendkey', :execute => 'sendkey',
:css => '.active .ticket_create input[name="customer_id_autocompletion"]', :css => '.active .ticket-create input[name="customer_id_autocompletion"]',
:value => :arrow_down, :value => :arrow_down,
}, },
{ {
:execute => 'sendkey', :execute => 'sendkey',
:css => '.active .ticket_create input[name="customer_id_autocompletion"]', :css => '.active .ticket-create input[name="customer_id_autocompletion"]',
:value => :tab, :value => :tab,
}, },
{ {

View file

@ -27,7 +27,7 @@ class CustomerTicketCreateTest < TestCase
}, },
{ {
:execute => 'set', :execute => 'set',
:css => '.ticket-create input[name="subject"]', :css => '.ticket-create input[name="title"]',
:value => 'some subject 123äöü', :value => 'some subject 123äöü',
}, },
{ {

View file

@ -32,12 +32,12 @@ class TaskbarTaskTest < TestCase
}, },
{ {
:execute => 'check', :execute => 'check',
:css => '.active .ticket_create', :css => '.active .ticket-create',
:result => true, :result => true,
}, },
{ {
:execute => 'set', :execute => 'set',
:css => '.active .ticket_create input[name="subject"]', :css => '.active .ticket-create input[name="title"]',
:value => 'some test AAA', :value => 'some test AAA',
}, },
{ {
@ -113,7 +113,7 @@ class TaskbarTaskTest < TestCase
}, },
{ {
:execute => 'set', :execute => 'set',
:css => '.active .ticket_create input[name="subject"]', :css => '.active .ticket-create input[name="title"]',
:value => 'INBOUND TEST#1', :value => 'INBOUND TEST#1',
}, },
{ {
@ -122,7 +122,7 @@ class TaskbarTaskTest < TestCase
}, },
{ {
:execute => 'set', :execute => 'set',
:css => '.active .ticket_create textarea[name="body"]', :css => '.active .ticket-create textarea[name="body"]',
:value => 'INBOUND BODY TEST#1', :value => 'INBOUND BODY TEST#1',
}, },
{ {
@ -139,7 +139,7 @@ class TaskbarTaskTest < TestCase
}, },
{ {
:execute => 'set', :execute => 'set',
:css => '.active .ticket_create input[name="subject"]', :css => '.active .ticket-create input[name="title"]',
:value => 'OUTBOUND TEST#1', :value => 'OUTBOUND TEST#1',
}, },
{ {
@ -148,7 +148,7 @@ class TaskbarTaskTest < TestCase
}, },
{ {
:execute => 'set', :execute => 'set',
:css => '.active .ticket_create textarea[name="body"]', :css => '.active .ticket-create textarea[name="body"]',
:value => 'OUTBOUND BODY TEST#1', :value => 'OUTBOUND BODY TEST#1',
}, },
{ {

View file

@ -297,40 +297,40 @@ class TestCase < Test::Unit::TestCase
elsif action[:execute] == 'create_ticket' elsif action[:execute] == 'create_ticket'
instance.find_element( { :css => 'a[href="#new"]' } ).click instance.find_element( { :css => 'a[href="#new"]' } ).click
instance.find_element( { :css => 'a[href="#ticket/create/call_inbound"]' } ).click instance.find_element( { :css => 'a[href="#ticket/create/call_inbound"]' } ).click
element = instance.find_element( { :css => '.active .ticket_create' } ) element = instance.find_element( { :css => '.active .ticket-create' } )
if !element if !element
assert( false, "(#{test[:name]}) no ticket create screen found!" ) assert( false, "(#{test[:name]}) no ticket create screen found!" )
return return
end end
sleep 2 sleep 2
element = instance.find_element( { :css => '.active .ticket_create input[name="customer_id_autocompletion"]' } ) element = instance.find_element( { :css => '.active .ticket-create input[name="customer_id_autocompletion"]' } )
element.clear element.clear
element.send_keys( 'nico*' ) element.send_keys( 'nico*' )
sleep 4 sleep 4
element = instance.find_element( { :css => '.active .ticket_create input[name="customer_id_autocompletion"]' } ) element = instance.find_element( { :css => '.active .ticket-create input[name="customer_id_autocompletion"]' } )
element.send_keys( :arrow_down ) element.send_keys( :arrow_down )
sleep 0.2 sleep 0.2
element = instance.find_element( { :css => '.active .ticket_create input[name="customer_id_autocompletion"]' } ) element = instance.find_element( { :css => '.active .ticket-create input[name="customer_id_autocompletion"]' } )
element.send_keys( :tab ) element.send_keys( :tab )
sleep 0.1 sleep 0.1
element = instance.find_element( { :css => '.active .ticket_create select[name="group_id"]' } ) element = instance.find_element( { :css => '.active .ticket-create select[name="group_id"]' } )
dropdown = Selenium::WebDriver::Support::Select.new(element) dropdown = Selenium::WebDriver::Support::Select.new(element)
dropdown.select_by( :text, action[:group]) dropdown.select_by( :text, action[:group])
sleep 0.1 sleep 0.1
element = instance.find_element( { :css => '.active .ticket_create input[name="subject"]' } ) element = instance.find_element( { :css => '.active .ticket-create input[name="title"]' } )
element.clear element.clear
element.send_keys( action[:subject] ) element.send_keys( action[:subject] )
sleep 0.1 sleep 0.1
element = instance.find_element( { :css => '.active .ticket_create textarea[name="body"]' } ) element = instance.find_element( { :css => '.active .ticket-create textarea[name="body"]' } )
element.clear element.clear
element.send_keys( action[:body] ) element.send_keys( action[:body] )
if action[:do_not_submit] if action[:do_not_submit]
assert( true, "(#{test[:name]}) ticket created without submit" ) assert( true, "(#{test[:name]}) ticket created without submit" )
return return
end end
sleep 0.5 sleep 0.8
instance.find_element( { :css => '.active .form-actions button[type="submit"]' } ).click instance.find_element( { :css => '.active .form-actions button[type="submit"]' } ).click
sleep 2 sleep 1
(1..14).each {|loop| (1..14).each {|loop|
if instance.current_url =~ /#{Regexp.quote('#ticket/zoom/')}/ if instance.current_url =~ /#{Regexp.quote('#ticket/zoom/')}/
assert( true, "(#{test[:name]}) ticket created" ) assert( true, "(#{test[:name]}) ticket created" )
@ -338,7 +338,7 @@ class TestCase < Test::Unit::TestCase
end end
sleep 0.5 sleep 0.5
} }
assert( true, "(#{test[:name]}) ticket creation failed, can't get zoom url" ) assert( false, "(#{test[:name]}) ticket creation failed, can't get zoom url" )
return return
elsif action[:execute] == 'close_all_tasks' elsif action[:execute] == 'close_all_tasks'
for i in 1..100 for i in 1..100

View file

@ -74,26 +74,57 @@ class TagTest < ActiveSupport::TestCase
}, },
}, },
# test 5
{
:tag_remove => {
:item => 'tag1',
:object => 'Object1',
:o_id => 123,
:created_by_id => 1
},
:verify => {
:object => 'Object1',
:items => {
'tag1' => false,
'tag2' => true,
},
},
},
] ]
tests.each { |test| tests.each { |test|
success = Tag.tag_add( test[:tag_add] ) tags = nil
assert( success, "Tag.tag_add successful") if test[:tag_add]
list = Tag.tag_list( test[:tag_add] ) tags = test[:tag_add]
success = Tag.tag_add( tags )
assert( success, "Tag.tag_add successful")
else
tags = test[:tag_remove]
success = Tag.tag_remove( tags )
assert( success, "Tag.tag_remove successful")
end
list = Tag.tag_list( tags )
test[:verify][:items].each {|key, value| test[:verify][:items].each {|key, value|
if value == true if value == true
assert( list.include?( key ), "Tag verify #{ test[:tag_add][:item] }") assert( list.include?( key ), "Tag verify - should exists but exists #{ key }")
else else
assert( !list.include?( key ), "Tag verify #{ test[:tag_add][:item] }") assert( !list.include?( key ), "Tag verify - exists but should not #{ key }")
end end
} }
} }
# delete tags # delete tags
tests.each { |test| tests.each { |test|
success = Tag.tag_remove( test[:tag_add] ) tags = nil
if test[:tag_add]
tags = test[:tag_add]
else
tags = test[:tag_remove]
end
success = Tag.tag_remove( tags )
assert( success, "Tag.tag_remove successful") assert( success, "Tag.tag_remove successful")
list = Tag.tag_list( test[:tag_add] ) list = Tag.tag_list( tags )
assert( !list.include?( test[:tag_add][:item] ), "Tag entry destroyed") assert( !list.include?( tags[:item] ), "Tag entry destroyed")
} }
end end
end end