diff --git a/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee b/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee
index 35397afa9..5ff075c71 100644
--- a/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee
+++ b/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee
@@ -95,7 +95,7 @@ class App.ControllerForm extends App.Controller
for eventSelector, callback of @events
do (eventSelector, callback) =>
evs = eventSelector.split(' ')
- fieldset.find( evs[1] ).bind(evs[0], (e) => callback(e) )
+ fieldset.find( evs[1] ).bind( evs[0], (e) => callback(e) )
# return form
return fieldset
@@ -264,13 +264,13 @@ class App.ControllerForm extends App.Controller
{ name: 'inactive', value: false }
]
- # update boolean types
- for record in attribute.options
- record.value = '{boolean}::' + record.value
+ # set data type
+ if attribute.name
+ attribute.name = '{boolean}' + attribute.name
# finde selected item of list
for record in attribute.options
- if record.value is '{boolean}::' + attribute.value
+ if record.value is attribute.value
record.selected = 'selected'
# return item
@@ -283,7 +283,6 @@ class App.ControllerForm extends App.Controller
# date
else if attribute.tag is 'date'
attribute.type = 'text'
- item = $( App.view('generic/date')( attribute: attribute ) )
#item.datetimepicker({
# format: 'Y.m.d'
#});
@@ -291,10 +290,163 @@ class App.ControllerForm extends App.Controller
# 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'
- #});
+
+ # set data type
+ if attribute.name
+ attribute.nameRaw = attribute.name
+ attribute.name = '{datetime}' + attribute.name
+ if attribute.value
+ if typeof( attribute.value ) is 'string'
+ unixtime = new Date( Date.parse( attribute.value ) )
+ else
+ unixtime = new Date( attribute.value )
+ year = unixtime.getYear() + 1900
+ month = unixtime.getMonth() + 1
+ day = unixtime.getDate()
+ hour = unixtime.getHours()
+ minute = unixtime.getMinutes()
+ item = $( App.view('generic/datetime')(
+ attribute: attribute
+ year: year
+ month: month
+ day: day
+ hour: hour
+ minute: minute
+ ) )
+ item.find('.js-today').bind('click', (e) ->
+ e.preventDefault()
+ name = $(@).closest('.form-group').find('[data-name]').attr('data-name')
+ today = new Date();
+ item.closest('.form-group').find("[name=\"{datetime}#{name}___day\"]").val( today.getDate() )
+ item.closest('.form-group').find("[name=\"{datetime}#{name}___month\"]").val( today.getMonth()+1 )
+ item.closest('.form-group').find("[name=\"{datetime}#{name}___year\"]").val( today.getFullYear() )
+ item.closest('.form-group').find("[name=\"{datetime}#{name}___hour\"]").val( today.getHours() )
+ item.closest('.form-group').find("[name=\"{datetime}#{name}___minute\"]").val( today.getMinutes() )
+ )
+
+ setNewTime = (diff, el) ->
+ name = $(el).closest('.form-group').find('[data-name]').attr('data-name')
+
+ day = item.closest('.form-group').find("[name=\"{datetime}#{name}___day\"]").val()
+ month = item.closest('.form-group').find("[name=\"{datetime}#{name}___month\"]").val()
+ year = item.closest('.form-group').find("[name=\"{datetime}#{name}___year\"]").val()
+ hour = item.closest('.form-group').find("[name=\"{datetime}#{name}___hour\"]").val()
+ minute = item.closest('.form-group').find("[name=\"{datetime}#{name}___minute\"]").val()
+ format = (number) ->
+ if parseInt(number) < 10
+ number = "0#{number}"
+ number
+ #console.log('ph', diff, "#{year}-#{format(month)}-#{format(day)}T#{format(hour)}:#{format(minute)}:00Z")
+ time = new Date( Date.parse( "#{year}-#{format(month)}-#{format(day)}T#{format(hour)}:#{format(minute)}:00Z" ) )
+ time.setMinutes( time.getMinutes() + diff + time.getTimezoneOffset() )
+ #console.log('T', time, time.getHours(), time.getMinutes())
+ item.closest('.form-group').find("[name=\"{datetime}#{name}___day\"]").val( time.getDate() )
+ item.closest('.form-group').find("[name=\"{datetime}#{name}___month\"]").val( time.getMonth()+1 )
+ item.closest('.form-group').find("[name=\"{datetime}#{name}___year\"]").val( time.getFullYear() )
+ item.closest('.form-group').find("[name=\"{datetime}#{name}___hour\"]").val( time.getHours() )
+ item.closest('.form-group').find("[name=\"{datetime}#{name}___minute\"]").val( time.getMinutes() )
+
+ item.find('.js-plus-hour').bind('click', (e) ->
+ e.preventDefault()
+ setNewTime(60, @)
+ )
+ item.find('.js-minus-hour').bind('click', (e) ->
+ e.preventDefault()
+ setNewTime(-60, @)
+ )
+ item.find('.js-plus-day').bind('click', (e) ->
+ e.preventDefault()
+ setNewTime(60 * 24, @)
+ )
+ item.find('.js-minus-day').bind('click', (e) ->
+ e.preventDefault()
+ setNewTime(-60 * 24, @)
+ )
+ item.find('.js-plus-week').bind('click', (e) ->
+ e.preventDefault()
+ setNewTime(60 * 24 * 7, @)
+ )
+ item.find('.js-minus-week').bind('click', (e) ->
+ e.preventDefault()
+ setNewTime(-60 * 24 * 7, @)
+ )
+
+ item.find('input').bind('keyup blur focus', (e) ->
+
+ # do validation
+ name = $(@).attr('name')
+ if name
+ fieldPrefix = name.split('___')[0]
+
+ # remove old validation
+ item.find('.has-error').removeClass('has-error')
+ item.closest('.form-group').find('.help-inline').html('')
+
+ day = item.closest('.form-group').find("[name=\"#{fieldPrefix}___day\"]").val()
+ month = item.closest('.form-group').find("[name=\"#{fieldPrefix}___month\"]").val()
+ year = item.closest('.form-group').find("[name=\"#{fieldPrefix}___year\"]").val()
+ hour = item.closest('.form-group').find("[name=\"#{fieldPrefix}___hour\"]").val()
+ minute = item.closest('.form-group').find("[name=\"#{fieldPrefix}___minute\"]").val()
+
+ # validate exists
+ errors = {}
+ if !day
+ errors.day = 'missing'
+ if !month
+ errors.month = 'missing'
+ if !year
+ errors.year = 'missing'
+ if !hour
+ errors.hour = 'missing'
+ if !minute
+ errors.minute = 'missing'
+
+ # ranges
+ if day
+ daysInMonth = 31
+ if month && year
+ daysInMonth = new Date(year, month, 0).getDate();
+ console.log('222', month, year, daysInMonth)
+
+ if parseInt(day).toString() is 'NaN'
+ errors.day = 'invalid'
+ else if parseInt(day) > daysInMonth || parseInt(day) < 1
+ errors.day = 'invalid'
+
+ if month
+ if parseInt(month).toString() is 'NaN'
+ errors.month = 'invalid'
+ else if parseInt(month) > 12 || parseInt(month) < 1
+ errors.month = 'invalid'
+
+ if year
+ if parseInt(year).toString() is 'NaN'
+ errors.year = 'invalid'
+ else if parseInt(year) > 2100 || parseInt(year) < 2001
+ errors.year = 'invalid'
+
+ if hour
+ if parseInt(hour).toString() is 'NaN'
+ errors.hour = 'invalid'
+ else if parseInt(hour) > 23 || parseInt(hour) < 0
+ errors.hour = 'invalid'
+
+ if minute
+ if parseInt(minute).toString() is 'NaN'
+ errors.minute = 'invalid'
+ else if parseInt(minute) > 59
+ errors.minute = 'invalid'
+
+ if !_.isEmpty(errors)
+ for key, value of errors
+ item.closest('.form-group').addClass('has-error')
+ item.closest('.form-group').find("[name=\"#{fieldPrefix}___#{key}\"]").addClass('has-error')
+ #item.closest('.form-group').find('.help-inline').text( value )
+
+ e.preventDefault()
+ e.stopPropagation()
+ return
+ )
# timezone
else if attribute.tag is 'timezone'
@@ -615,95 +767,6 @@ class App.ControllerForm extends App.Controller
if listItem.value is "#{ attribute.name }::#{key}"
addItem( "#{ attribute.name }::#{key}", listItem.name, item.find('.add a'), value )
- # select
- else if attribute.tag is 'input_select'
- item = $('
')
-
- # select shown attributes
- loopData = {}
- if @params && @params[ attribute.name ]
- loopData = @params[ attribute.name ]
- loopData[''] = ''
-
- # show each attribote
- counter = 0
- for key of loopData
- counter =+ 1
-
- # clone to keep it untouched for next loop
- select = _.clone( attribute )
- input = _.clone( attribute )
-
- # set field ids - not needed in this case
- select.id = ''
- input.id = ''
-
- # rename to be able to identify this option later
- select.name = '{input_select}::' + select.name
- input.name = '{input_select}::' + input.name
-
- # set sub attributes
- for keysub of attribute.select
- select[keysub] = attribute.select[keysub]
- for keysub of attribute.input
- input[keysub] = attribute.input[keysub]
-
- # set hide for + options
- itemClass = ''
- if key is ''
- itemClass = 'hide'
- select['nulloption'] = true
-
- # set selected value
- select.value = key
- input.value = loopData[ key ]
-
- # build options list based on config
- @_getConfigOptionList( select )
-
- # build options list based on relation
- @_getRelationOptionList( select )
-
- # add null selection if needed
- @_addNullOption( select )
-
- # sort attribute.options
- @_sortOptions( select )
-
- # finde selected/checked item of list
- @_selectedOptions( select )
-
- pearItem = $("")
- pearItem.append $( App.view('generic/select')( attribute: select ) )
- pearItem.append $( App.view('generic/input')( attribute: input ) )
- itemRemote = $('')
- itemRemote.bind('click', (e) ->
- e.preventDefault()
- $(@).parent().remove()
- )
- pearItem.append( itemRemote )
- item.append( pearItem )
-
- if key is ''
- itemAdd = $('')
- itemAdd.bind('click', (e) ->
- e.preventDefault()
-
- # copy
- newElement = $(@).prev().clone()
- newElement.removeClass('hide')
-
- # bind on remove
- newElement.find('.input_select_remove').bind('click', (e) ->
- e.preventDefault()
- $(@).parent().remove()
- )
-
- # prepend
- $(@).parent().find('.add').before( newElement )
- )
- item.append( itemAdd )
-
# checkbox
else if attribute.tag is 'checkbox'
item = $( App.view('generic/checkbox')( attribute: attribute ) )
@@ -1792,6 +1855,8 @@ class App.ControllerForm extends App.Controller
for key in name
el.find('[name="' + key + '"]').closest('.form-group').removeClass('hide')
el.find('[name="' + key + '"]').removeClass('is-hidden')
+ el.find('[data-name="' + key + '"]').closest('.form-group').removeClass('hide')
+ el.find('[data-name="' + key + '"]').removeClass('is-hidden')
_hide: (name, el = @el) ->
if !_.isArray(name)
@@ -1799,6 +1864,8 @@ class App.ControllerForm extends App.Controller
for key in name
el.find('[name="' + key + '"]').closest('.form-group').addClass('hide')
el.find('[name="' + key + '"]').addClass('is-hidden')
+ el.find('[data-name="' + key + '"]').closest('.form-group').addClass('hide')
+ el.find('[data-name="' + key + '"]').addClass('is-hidden')
_mandantory: (name, el = @el) ->
if !_.isArray(name)
@@ -1819,8 +1886,13 @@ class App.ControllerForm extends App.Controller
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 params[refAttribute]
+ if _.isArray( refValue )
+ for item in refValue
+ if params[refAttribute].toString() is item.toString()
+ hit = true
+ else if params[refAttribute].toString() is refValue.toString()
+ hit = true
if hit
ui._show(attribute.name)
else
@@ -1831,8 +1903,13 @@ class App.ControllerForm extends App.Controller
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 params[refAttribute]
+ if _.isArray( refValue )
+ for item in refValue
+ if params[refAttribute].toString() is item.toString()
+ hit = true
+ else if params[refAttribute].toString() is refValue.toString()
+ hit = true
if hit
ui._mandantory(attribute.name)
else
@@ -2066,33 +2143,70 @@ class App.ControllerForm extends App.Controller
# get form elements
array = lookupForm.serializeArray()
- # 1:1 and boolean params
+ # array to names
for key in array
# check if item is-hidden and should not be used
if lookupForm.find('[name="' + key.name + '"]').hasClass('is-hidden')
+ param[key.name] = undefined
continue
- # collect all other params
+ # collect all params, push it to an array if already exists
if param[key.name]
if typeof param[key.name] is 'string'
param[key.name] = [ param[key.name], key.value]
else
param[key.name].push key.value
else
-
- # check boolean
- attributeType = key.value.split '::'
- if attributeType[0] is '{boolean}'
- if attributeType[1] is 'true'
- key.value = true
- else
- key.value = false
-# else if attributeType[0] is '{boolean}'
-
param[key.name] = key.value
- # check :: fields
+ # data type conversion
+ for key of param
+
+ # get boolean
+ if key.substr(0,9) is '{boolean}'
+ newKey = key.substr( 9, key.length )
+ param[ newKey ] = param[ key ]
+ delete param[ key ]
+ if param[ newKey ] && param[ newKey ].toString() is 'true'
+ param[ newKey ] = true
+ else
+ param[ newKey ] = false
+
+ # get {datetime}
+ else if key.substr(0,10) is '{datetime}'
+ newKey = key.substr( 10, key.length )
+ namespace = newKey.split '___'
+
+ if !param[ namespace[0] ]
+ datetimeKey = "{datetime}#{namespace[0]}___"
+ year = param[ "#{datetimeKey}year" ]
+ month = param[ "#{datetimeKey}month" ]
+ day = param[ "#{datetimeKey}day" ]
+ hour = param[ "#{datetimeKey}hour" ]
+ minute = param[ "#{datetimeKey}minute" ]
+ timezone = (new Date()).getTimezoneOffset()/60
+ if year && month && day && hour && minute
+ format = (number) ->
+ if parseInt(number) < 10
+ number = "0#{number}"
+ number
+ try
+ time = new Date( Date.parse( "#{year}-#{format(month)}-#{format(day)}T#{format(hour)}:#{format(minute)}:00Z" ) )
+ time.setMinutes( time.getMinutes() + time.getTimezoneOffset() )
+ param[ namespace[0] ] = time.toISOString()
+ catch err
+ console.log('ERR', err)
+
+ #console.log('T', time, time.getHours(), time.getMinutes())
+
+ delete param[ "#{datetimeKey}year" ]
+ delete param[ "#{datetimeKey}month" ]
+ delete param[ "#{datetimeKey}day" ]
+ delete param[ "#{datetimeKey}hour" ]
+ delete param[ "#{datetimeKey}minute" ]
+
+ # split :: fields, build objects
inputSelectObject = {}
for key of param
parts = key.split '::'
@@ -2109,25 +2223,7 @@ class App.ControllerForm extends App.Controller
inputSelectObject[ parts[0] ][ parts[1] ][ parts[2] ] = param[ key ]
delete param[ key ]
- # check {input_select}
- for key of param
- attributeType = key.split '::'
- name = attributeType[1]
-# console.log 'split', key, attributeType, param[ name ]
- if attributeType[0] is '{input_select}' && !param[ name ]
-
- # array need to be converted
- inputSelectData = param[ key ]
- inputSelectObject[ name ] = {}
- for x in [0..inputSelectData.length] by 2
-# console.log 'for by 111', x, inputSelectData, inputSelectData[x], inputSelectData[ x + 1 ]
- if inputSelectData[ x ]
- inputSelectObject[ name ][ inputSelectData[x] ] = inputSelectData[ x + 1 ]
-
- # remove {input_select} items
- delete param[ key ]
-
- # set new {input_select} items
+ # set new object params
for key of inputSelectObject
param[ key ] = inputSelectObject[ key ]
@@ -2203,8 +2299,13 @@ class App.ControllerForm extends App.Controller
# show new errors
for key, msg of data.errors
- lookupForm.find('[name="' + key + '"]').parents('div .form-group').addClass('has-error')
- lookupForm.find('[name="' + key + '"]').parent().find('.help-inline').html(msg)
+ item = lookupForm.find('[name="' + key + '"]').closest('.form-group')
+ item.addClass('has-error')
+ item.find('.help-inline').html(msg)
+
+ item = lookupForm.find('[data-name="' + key + '"]').closest('.form-group')
+ item.addClass('has-error')
+ item.find('.help-inline').html(msg)
# set autofocus
- lookupForm.find('.has-error').find('input, textarea').first().focus()
+ lookupForm.find('.has-error').find('input, textarea, select').first().focus()
diff --git a/app/assets/javascripts/app/views/generic/datetime.jst.eco b/app/assets/javascripts/app/views/generic/datetime.jst.eco
new file mode 100644
index 000000000..666d9e828
--- /dev/null
+++ b/app/assets/javascripts/app/views/generic/datetime.jst.eco
@@ -0,0 +1,19 @@
+
+
+ .
+
+ .
+
+
+ :
+
+
+
\ No newline at end of file
diff --git a/app/assets/stylesheets/zammad.css.scss b/app/assets/stylesheets/zammad.css.scss
index 9d18ab2a7..cae1fd802 100644
--- a/app/assets/stylesheets/zammad.css.scss
+++ b/app/assets/stylesheets/zammad.css.scss
@@ -757,6 +757,11 @@ textarea,
border-color: red !important;
}
+ input.has-error {
+ box-shadow: none;
+ border-color: red !important;
+ }
+
.help-inline:not(:empty) {
color: red;
padding: 2px;
diff --git a/app/controllers/tests_controller.rb b/app/controllers/tests_controller.rb
index 0d17c6e06..81bf09477 100644
--- a/app/controllers/tests_controller.rb
+++ b/app/controllers/tests_controller.rb
@@ -2,48 +2,6 @@
class TestsController < ApplicationController
- # GET /tests/core
- def core
- respond_to do |format|
- format.html # index.html.erb
- end
- end
-
- # GET /tests/ui
- def ui
- respond_to do |format|
- format.html # index.html.erb
- end
- end
-
- # GET /tests/from
- def form
- respond_to do |format|
- format.html # index.html.erb
- end
- end
-
- # GET /tests/from_extended
- def form
- respond_to do |format|
- format.html # index.html.erb
- end
- end
-
- # GET /tests/table
- def table
- respond_to do |format|
- format.html # index.html.erb
- end
- end
-
- # GET /tests/html_utils
- def html_utils
- respond_to do |format|
- format.html # index.html.erb
- end
- end
-
# GET /test/wait
def wait
sleep params[:sec].to_i
@@ -51,4 +9,4 @@ class TestsController < ApplicationController
render :json => result
end
-end
+end
\ No newline at end of file
diff --git a/config/routes/test.rb b/config/routes/test.rb
index 8faf95f01..bc85e8126 100644
--- a/config/routes/test.rb
+++ b/config/routes/test.rb
@@ -1,12 +1,13 @@
Zammad::Application.routes.draw do
- match '/tests-core', :to => 'tests#core', :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-extended', :to => 'tests#form_extended', :via => :get
- match '/tests-table', :to => 'tests#table', :via => :get
- match '/tests-html-utils', :to => 'tests#html_utils', :via => :get
- match '/tests/wait/:sec', :to => 'tests#wait', :via => :get
+ match '/tests-core', :to => 'tests#core', :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-extended', :to => 'tests#form_extended', :via => :get
+ match '/tests-form-validation', :to => 'tests#form_validation', :via => :get
+ match '/tests-table', :to => 'tests#table', :via => :get
+ match '/tests-html-utils', :to => 'tests#html_utils', :via => :get
+ match '/tests/wait/:sec', :to => 'tests#wait', :via => :get
end
\ No newline at end of file
diff --git a/db/seeds.rb b/db/seeds.rb
index 09cbe4a22..8ceb17f73 100644
--- a/db/seeds.rb
+++ b/db/seeds.rb
@@ -1345,10 +1345,11 @@ Ticket::StateType.create_if_not_exists( :id => 7, :name => 'removed', :updated_b
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( :id => 2, :name => 'open', :state_type_id => Ticket::StateType.where(:name => 'open').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( :id => 3, :name => 'pending reminder', :state_type_id => Ticket::StateType.where(:name => 'pending reminder').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( :id => 5, :name => 'merged', :state_type_id => Ticket::StateType.where(:name => 'merged').first.id )
-Ticket::State.create_if_not_exists( :id => 6, :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, :active => false )
+Ticket::State.create_if_not_exists( :id => 7, :name => 'pending close', :state_type_id => Ticket::StateType.where(:name => 'pending action').first.id, :next_state_id => 5 )
Ticket::Priority.create_if_not_exists( :name => '1 low' )
Ticket::Priority.create_if_not_exists( :name => '2 normal' )
@@ -1427,8 +1428,9 @@ Overview.create_if_not_exists(
:prio => 1010,
:role_id => overview_role.id,
:condition => {
- 'tickets.state_id' => [3],
- 'tickets.owner_id' => 'current_user.id',
+ 'tickets.state_id' => [3],
+ 'tickets.owner_id' => 'current_user.id',
+ 'tickets.pending_time' => { 'direction' => 'before', 'count'=> 1, 'area' => 'minute' },
},
:order => {
:by => 'created_at',
@@ -1483,13 +1485,34 @@ Overview.create_if_not_exists(
},
)
+Overview.create_if_not_exists(
+ :name => 'All pending reached Tickets',
+ :link => 'all_pending_reached',
+ :prio => 1035,
+ :role_id => overview_role.id,
+ :condition => {
+ 'tickets.state_id' => [3],
+ 'tickets.pending_time' => { 'direction' => 'before', 'count'=> 1, 'area' => 'minute' },
+ },
+ :order => {
+ :by => 'created_at',
+ :direction => 'ASC',
+ },
+ :view => {
+ :d => [ 'title', 'customer', 'group', 'created_at' ],
+ :s => [ 'title', 'customer', 'group', 'created_at' ],
+ :m => [ 'number', 'title', 'customer', 'group', 'created_at' ],
+ :view_mode_default => 's',
+ },
+)
+
Overview.create_if_not_exists(
:name => 'Escalated Tickets',
:link => 'all_escalated',
:prio => 1040,
:role_id => overview_role.id,
:condition => {
- 'tickets.escalation_time' =>{ 'direction' => 'before', 'count'=> 5, 'area' => 'minute' },
+ 'tickets.escalation_time' => { 'direction' => 'before', 'count'=> 5, 'area' => 'minute' },
},
:order => {
:by => 'escalation_time',
@@ -1510,8 +1533,8 @@ Overview.create_if_not_exists(
:prio => 1000,
:role_id => overview_role.id,
:condition => {
- 'tickets.state_id' => [ 1,2,3,4,6 ],
- 'tickets.customer_id' => 'current_user.id',
+ 'tickets.state_id' => [ 1,2,3,4,6 ],
+ 'tickets.customer_id' => 'current_user.id',
},
:order => {
:by => 'created_at',
diff --git a/public/assets/tests/form-validation.js b/public/assets/tests/form-validation.js
new file mode 100644
index 000000000..bca5d6f2c
--- /dev/null
+++ b/public/assets/tests/form-validation.js
@@ -0,0 +1,149 @@
+test( "form validation check", function() {
+
+ $('#forms').append('
form params check
')
+
+ var el = $('#form1')
+ var defaults = {}
+ var form = new App.ControllerForm({
+ el: el,
+ model: {
+ configure_attributes: [
+ { name: 'input1', display: 'Input1', tag: 'input', type: 'text', limit: 100, null: false },
+ { name: 'password1', display: 'Password1', tag: 'input', type: 'password', limit: 100, null: false },
+ { name: 'textarea1', display: 'Textarea1', tag: 'textarea', rows: 6, limit: 100, null: false, upload: true },
+ { name: 'select1', display: 'Select1', tag: 'select', null: false, nulloption: true, options: { true: 'internal', false: 'public' } },
+ { name: 'selectmulti1', display: 'SelectMulti1', tag: 'select', null: false, nulloption: true, multiple: true, options: { true: 'internal', false: 'public' } },
+ { name: 'autocompletion1', display: 'AutoCompletion1', tag: 'autocompletion', null: false, options: { true: 'internal', false: 'public' }, source: [ { label: "Choice1", value: "value1", id: "id1" }, { label: "Choice2", value: "value2", id: "id2" }, ], minLength: 1 },
+ { name: 'richtext1', display: 'Richtext1', tag: 'richtext', maxlength: 100, null: false, type: 'richtext', multiline: true, upload: true, default: defaults['richtext1'] },
+ { name: 'datetime1', display: 'Datetime1', tag: 'datetime', null: false, default: defaults['datetime1'] },
+ { name: 'active1', display: 'Active1', tag: 'boolean', type: 'boolean', default: defaults['active1'], null: false },
+ ],
+ },
+ params: defaults,
+ });
+ equal( el.find('[name="input1"]').val(), '', 'check input1 value')
+ equal( el.find('[name="input1"]').prop('required'), true, 'check input1 required')
+// equal( el.find('[name="input1"]').is(":focus"), true, 'check input1 focus')
+
+ equal( el.find('[name="password1"]').val(), '', 'check password1 value')
+ equal( el.find('[name="password1_confirm"]').val(), '', 'check password1 value')
+ equal( el.find('[name="password1"]').prop('required'), true, 'check password1 required')
+
+ equal( el.find('[name="textarea1"]').val(), '', 'check textarea1 value')
+ equal( el.find('[name="textarea1"]').prop('required'), true, 'check textarea1 required')
+
+ equal( el.find('[name="select1"]').val(), '', 'check select1 value')
+ equal( el.find('[name="select1"]').prop('required'), true, 'check select1 required')
+
+ equal( el.find('[name="selectmulti1"]').val(), null, 'check selectmulti1 value')
+ equal( el.find('[name="selectmulti1"]').prop('required'), true, 'check selectmulti1 required')
+
+ equal( el.find('[name="autocompletion1"]').val(), '', 'check autocompletion1 value')
+ equal( el.find('[name="autocompletion1"]').prop('required'), true, 'check autocompletion1 required')
+
+ equal( el.find('[data-name="richtext1"]').val(), '', 'check richtext1 value')
+ //equal( el.find('[data-name="richtext1"]').prop('required'), true, 'check richtext1 required')
+
+
+
+ params = App.ControllerForm.params( el )
+ errors = form.validate(params)
+
+ test_errors = {
+ input1: "is required",
+ password1: "is required",
+ textarea1: "is required",
+ select1: "is required",
+ selectmulti1: "is required",
+ autocompletion1: "is required",
+ richtext1: "is required",
+ datetime1: "is required",
+ }
+ deepEqual( errors, test_errors, 'validation errors check' )
+
+ App.ControllerForm.validate( { errors: errors, form: el } )
+
+ equal( el.find('[name="input1"]').closest('.form-group').hasClass('has-error'), true, 'check input1 has-error')
+ equal( el.find('[name="input1"]').closest('.form-group').find('.help-inline').text(), 'is required', 'check input1 error message')
+
+ equal( el.find('[name="password1"]').closest('.form-group').hasClass('has-error'), true, 'check password1 has-error')
+ equal( el.find('[name="password1"]').closest('.form-group').find('.help-inline').text(), 'is required', 'check password1 error message')
+
+ equal( el.find('[name="textarea1"]').closest('.form-group').hasClass('has-error'), true, 'check textarea1 has-error')
+ equal( el.find('[name="textarea1"]').closest('.form-group').find('.help-inline').text(), 'is required', 'check textarea1 error message')
+
+ equal( el.find('[name="select1"]').closest('.form-group').hasClass('has-error'), true, 'check select1 has-error')
+ equal( el.find('[name="select1"]').closest('.form-group').find('.help-inline').text(), 'is required', 'check select1 error message')
+
+ equal( el.find('[name="selectmulti1"]').closest('.form-group').hasClass('has-error'), true, 'check selectmulti1 has-error')
+ equal( el.find('[name="selectmulti1"]').closest('.form-group').find('.help-inline').text(), 'is required', 'check selectmulti1 error message')
+
+ equal( el.find('[name="autocompletion1"]').closest('.form-group').hasClass('has-error'), true, 'check autocompletion1 has-error')
+ equal( el.find('[name="autocompletion1"]').closest('.form-group').find('.help-inline').text(), 'is required', 'check autocompletion1 error message')
+
+ equal( el.find('[data-name="richtext1"]').closest('.form-group').hasClass('has-error'), true, 'check richtext1 has-error')
+ equal( el.find('[data-name="richtext1"]').closest('.form-group').find('.help-inline').text(), 'is required', 'check richtext1 error message')
+
+ equal( el.find('[data-name="datetime1"]').closest('.form-group').hasClass('has-error'), true, 'check datetime1 has-error')
+ equal( el.find('[data-name="datetime1"]').closest('.form-group').find('.help-inline').text(), 'is required', 'check datetime1 error message')
+
+});
+
+test( "datetime validation check", function() {
+
+ $('#forms').append('
datetime validation check
')
+
+ var el = $('#form2')
+ var defaults = {}
+ var form = new App.ControllerForm({
+ el: el,
+ model: {
+ configure_attributes: [
+ { name: 'datetime1', display: 'Datetime1', tag: 'datetime', null: false, default: defaults['datetime1'] },
+ ],
+ },
+ params: defaults,
+ });
+
+ params = App.ControllerForm.params( el )
+ errors = form.validate(params)
+ test_errors = {
+ datetime1: "is required",
+ }
+ deepEqual( errors, test_errors, 'validation errors check' )
+ App.ControllerForm.validate( { errors: errors, form: el } )
+
+ equal( el.find('[data-name="datetime1"]').closest('.form-group').hasClass('has-error'), true, 'check datetime1 has-error')
+ equal( el.find('[data-name="datetime1"]').closest('.form-group').find('.help-inline').text(), 'is required', 'check datetime1 error message')
+
+ el.find('[name="{datetime}datetime1___day"]').val('1')
+ el.find('[name="{datetime}datetime1___month"]').val('1')
+ el.find('[name="{datetime}datetime1___year"]').val('2015')
+ el.find('[name="{datetime}datetime1___hour"]').val('12')
+ el.find('[name="{datetime}datetime1___minute"]').val('42')
+ params = App.ControllerForm.params( el )
+ errors = form.validate(params)
+ test_errors = undefined
+// datetime1: "invalid",
+// }
+ deepEqual( errors, test_errors, 'validation errors check' )
+ App.ControllerForm.validate( { errors: errors, form: el } )
+ equal( el.find('[data-name="datetime1"]').closest('.form-group').hasClass('has-error'), false, 'check datetime1 has-error')
+ equal( el.find('[data-name="datetime1"]').closest('.form-group').find('.help-inline').text(), '', 'check datetime1 error message')
+
+ el.find('[name="{datetime}datetime1___day"]').val('47')
+ el.find('[name="{datetime}datetime1___month"]').val('1')
+ el.find('[name="{datetime}datetime1___year"]').val('2015')
+ el.find('[name="{datetime}datetime1___hour"]').val('12')
+ el.find('[name="{datetime}datetime1___minute"]').val('42')
+ params = App.ControllerForm.params( el )
+ errors = form.validate(params)
+ test_errors = {
+ datetime1: "is required",
+ }
+ deepEqual( errors, test_errors, 'validation errors check' )
+ App.ControllerForm.validate( { errors: errors, form: el } )
+ equal( el.find('[data-name="datetime1"]').closest('.form-group').hasClass('has-error'), true, 'check datetime1 has-error')
+ equal( el.find('[data-name="datetime1"]').closest('.form-group').find('.help-inline').text(), '', 'check datetime1 error message')
+
+});
\ No newline at end of file
diff --git a/public/assets/tests/form.js b/public/assets/tests/form.js
index b53592a03..270d35c2b 100644
--- a/public/assets/tests/form.js
+++ b/public/assets/tests/form.js
@@ -15,6 +15,7 @@ test( "form elements check", function() {
selectmultioption1: false,
selectmultioption2: [ false, true ],
richtext2: 'lalu lalu',
+ datetime1: Date.parse('2015-01-11T12:40:00Z'),
}
new App.ControllerForm({
el: el,
@@ -34,6 +35,8 @@ test( "form elements check", function() {
{ name: 'selectmultioption2', display: 'SelectMultiOption2', tag: 'select', null: false, multiple: true, options: [{ value: true, name: 'A' }, { value: 1, name: 'B'}, { value: false, name: 'C' }], default: defaults['selectmultioption2'] },
{ name: 'richtext1', display: 'Richtext1', tag: 'richtext', limit: 100, null: true, upload: true, default: defaults['richtext1'] },
{ name: 'richtext2', display: 'Richtext2', tag: 'richtext', limit: 100, null: true, upload: true, default: defaults['richtext2'] },
+ { name: 'datetime1', display: 'Datetime1', tag: 'datetime', null: true, default: defaults['datetime1'] },
+ { name: 'datetime2', display: 'Datetime2', tag: 'datetime', null: true, default: defaults['datetime2'] },
]
},
autofocus: true
@@ -115,6 +118,9 @@ test( "form params check", function() {
richtext6: 'lalu b lalu
',
richtext7: "",
richtext8: 'lalu b lalu
',
+ datetime1: new Date( Date.parse('2015-01-11T12:40:00Z') ),
+ active1: true,
+ active2: false,
}
new App.ControllerForm({
el: el,
@@ -142,6 +148,10 @@ test( "form params check", function() {
{ name: 'richtext6', display: 'Richtext6', tag: 'richtext', maxlength: 100, null: true, type: 'textonly', multiline: true, upload: true, default: defaults['richtext6'] },
{ name: 'richtext7', display: 'Richtext7', tag: 'richtext', maxlength: 100, null: true, type: 'textonly', multiline: false, default: defaults['richtext7'] },
{ name: 'richtext8', display: 'Richtext8', tag: 'richtext', maxlength: 100, null: true, type: 'textonly', multiline: false, default: defaults['richtext8'] },
+ { name: 'datetime1', display: 'Datetime1', tag: 'datetime', null: true, default: defaults['datetime1'] },
+ { name: 'datetime2', display: 'Datetime2', tag: 'datetime', null: true, default: defaults['datetime2'] },
+ { name: 'active1', display: 'Active1', tag: 'boolean', type: 'boolean', default: defaults['active1'], null: false },
+ { name: 'active2', display: 'Active2', tag: 'boolean', type: 'boolean', default: defaults['active2'], null: false },
],
},
params: defaults,
@@ -220,6 +230,9 @@ test( "form params check", function() {
richtext6: 'lalu b lalu
',
richtext7: '',
richtext8: 'lalu b lalu
',
+ datetime1: '2015-01-11T12:40:00.000Z',
+ active1: true,
+ active2: false,
}
deepEqual( params, test_params, 'form param check' );
@@ -405,6 +418,7 @@ test( "form dependend fields check", function() {
var test_params = {
input1: "",
input2: "some used default",
+ input3: undefined,
select1: "false",
select2: "false",
selectmulti2: [ "true", "false" ],
@@ -416,6 +430,7 @@ test( "form dependend fields check", function() {
params = App.ControllerForm.params( el )
test_params = {
input1: "",
+ input2: undefined,
input3: "some used default",
select1: "true",
select2: "false",
@@ -425,6 +440,143 @@ test( "form dependend fields check", function() {
deepEqual( params, test_params, 'form param check' );
});
+test( "form handler check with and without fieldset", function() {
+// deepEqual( item, test.value, 'group set/get tests' );
+
+// mix default and params -> check it -> add note
+// test auto completion
+// show/hide fields base on field values -> bind changed event
+// form validation
+// form params check
+
+// add signature only if form_state is empty
+ $('#forms').append('
form handler check with and without fieldset
')
+ var el = $('#form5')
+ var defaults = {
+ select1: 'a',
+ select2: '',
+ }
+
+ var formChanges = function(params, attribute, attributes, classname, form, ui) {
+ console.log('FROM', form)
+ if (params['select1'] === 'b') {
+ console.log('lala', params)
+ var item = {
+ name: 'select2',
+ display: 'Select2',
+ tag: 'select',
+ null: true,
+ options: { 1:'1', 2:'2', 3:'3' },
+ default: 3,
+ };
+ var newElement = ui.formGenItem( item, classname, form )
+ form.find('[name="select2"]').closest('.form-group').replaceWith( newElement )
+ }
+ if (params['select1'] === 'a') {
+ console.log('lala', params)
+ var item = {
+ name: 'select2',
+ display: 'Select2',
+ tag: 'select',
+ null: true,
+ options: { 1:'1', 2:'2', 3:'3' },
+ default: 1,
+ };
+ var newElement = ui.formGenItem( item, classname, form )
+ form.find('[name="select2"]').closest('.form-group').replaceWith( newElement )
+ }
+ }
+
+ new App.ControllerForm({
+ el: el,
+ model: {
+ configure_attributes: [
+ { name: 'select1', display: 'Select1', tag: 'select', null: true, options: { a: 'a', b: 'b' }, default: 'b'},
+ { name: 'select2', display: 'Select2', tag: 'select', null: true, options: { 1:'1', 2:'2', 3:'3' }, default: 2 },
+ ],
+ },
+ params: defaults,
+ handlers: [
+ formChanges,
+ ],
+ //noFieldset: true,
+ });
+ equal( el.find('[name="select1"]').val(), 'a', 'check select1 value')
+ equal( el.find('[name="select1"]').prop('required'), false, 'check select1 required')
+
+ equal( el.find('[name="select2"]').val(), '1', 'check select2 value')
+ equal( el.find('[name="select2"]').prop('required'), false, 'check select2 required')
+
+ var params = App.ControllerForm.params( el )
+ var test_params = {
+ select1: 'a',
+ select2: '1',
+ }
+ deepEqual( params, test_params, 'form param check' );
+ el.find('[name="select1"]').val('b')
+ el.find('[name="select1"]').trigger('change')
+ params = App.ControllerForm.params( el )
+ test_params = {
+ select1: 'b',
+ select2: '3',
+ }
+ deepEqual( params, test_params, 'form param check' );
+ el.find('[name="select1"]').val('a')
+ el.find('[name="select1"]').trigger('change')
+ params = App.ControllerForm.params( el )
+ test_params = {
+ select1: 'a',
+ select2: '1',
+ }
+ deepEqual( params, test_params, 'form param check' );
+
+ // test with noFieldset
+ el.empty()
+ new App.ControllerForm({
+ el: el,
+ model: {
+ configure_attributes: [
+ { name: 'select1', display: 'Select1', tag: 'select', null: true, options: { a: 'a', b: 'b' }, default: 'b'},
+ { name: 'select2', display: 'Select2', tag: 'select', null: true, options: { 1:'1', 2:'2', 3:'3' }, default: 2 },
+ ],
+ },
+ params: defaults,
+ handlers: [
+ formChanges,
+ ],
+ noFieldset: true,
+ });
+ equal( el.find('[name="select1"]').val(), 'a', 'check select1 value')
+ equal( el.find('[name="select1"]').prop('required'), false, 'check select1 required')
+
+ equal( el.find('[name="select2"]').val(), '1', 'check select2 value')
+ equal( el.find('[name="select2"]').prop('required'), false, 'check select2 required')
+
+ var params = App.ControllerForm.params( el )
+ var test_params = {
+ select1: 'a',
+ select2: '1',
+ }
+ deepEqual( params, test_params, 'form param check' );
+ el.find('[name="select1"]').val('b')
+ el.find('[name="select1"]').trigger('change')
+ params = App.ControllerForm.params( el )
+ test_params = {
+ select1: 'b',
+ select2: '3',
+ }
+ deepEqual( params, test_params, 'form param check' );
+ el.find('[name="select1"]').val('a')
+ el.find('[name="select1"]').trigger('change')
+ params = App.ControllerForm.params( el )
+ test_params = {
+ select1: 'a',
+ select2: '1',
+ }
+ deepEqual( params, test_params, 'form param check' );
+
+});
+
test( "form postmaster filter", function() {
// check match area
@@ -455,8 +607,8 @@ test( "form postmaster filter", function() {
},
] )
- $('#forms').append('
form postmaster filter
')
- var el = $('#form5')
+ $('#forms').append('
form postmaster filter
')
+ var el = $('#form6')
var defaults = {
input2: 'some name',
match: {
@@ -493,8 +645,8 @@ test( "form postmaster filter", function() {
set: {
'x-zammad-ticket-owner': 'owner',
'x-zammad-ticket-customer': 'customer',
- 'x-zammad-ticket-priority_id': "2",
- 'x-zammad-ticket-group_id': "1",
+ 'x-zammad-ticket-priority_id': '2',
+ 'x-zammad-ticket-group_id': '1',
},
};
deepEqual( params, test_params, 'form param check' );
@@ -512,7 +664,7 @@ test( "form postmaster filter", function() {
},
set: {
'x-zammad-ticket-owner': 'owner',
- 'x-zammad-ticket-group_id': "1",
+ 'x-zammad-ticket-group_id': '1',
},
};
deepEqual( params, test_params, 'form param check' );
@@ -524,8 +676,8 @@ test( "form postmaster filter", function() {
});
test( "form selector", function() {
- $('#forms').append('
form selector
')
- var el = $('#form6')
+ $('#forms').append('
form selector
')
+ var el = $('#form7')
var defaults = {
input2: 'some name66',
}
@@ -555,10 +707,12 @@ test( "form selector", function() {
});
test( "form required_if + shown_if", function() {
- $('#forms').append('
form required_if + shown_if
')
- var el = $('#form7')
+ $('#forms').append('
form required_if + shown_if
')
+ var el = $('#form8')
var defaults = {
input2: 'some name66',
+ input3: 'some name77',
+ input4: 'some name88',
}
new App.ControllerForm({
el: el,
@@ -566,6 +720,8 @@ test( "form required_if + shown_if", function() {
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: 'input3', display: 'Input3', tag: 'input', type: 'text', limit: 100, null: true, default: 'some used default', required_if: { active: [true,false] }, shown_if: { active: [true,false] } },
+ { name: 'input4', display: 'Input4', tag: 'input', type: 'text', limit: 100, null: true, default: 'some used default', required_if: { active: [55,66] }, shown_if: { active: [55,66] } },
{ name: 'active', display: 'Active', tag: 'boolean', type: 'boolean', 'default': true, null: false },
],
},
@@ -574,33 +730,49 @@ test( "form required_if + shown_if", function() {
test_params = {
input1: "some not used default33",
input2: "some name66",
- active: true
+ input3: "some name77",
+ input4: undefined,
+ 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 ')
+ equal( el.find('[name="input3"]').attr('required'), 'required', 'check required attribute of input3 ')
+ equal( el.find('[name="input3"]').is(":visible"), true, 'check visible attribute of input3 ')
+ equal( el.find('[name="input4"]').is(":visible"), false, 'check visible attribute of input4 ')
- el.find('[name="active"]').val('{boolean}::false').trigger('change')
+
+ el.find('[name="{boolean}active"]').val('false').trigger('change')
test_params = {
input1: "some not used default33",
- active: false
+ input2: undefined,
+ input3: undefined,
+ input4: undefined,
+ 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 ')
+ equal( el.find('[name="input3"]').is(":visible"), false, 'check visible attribute of input3 ')
+ equal( el.find('[name="input4"]').is(":visible"), false, 'check visible attribute of input4 ')
- el.find('[name="active"]').val('{boolean}::true').trigger('change')
+ el.find('[name="{boolean}active"]').val('true').trigger('change')
test_params = {
input1: "some not used default33",
input2: "some name66",
- active: true
+ input3: "some name77",
+ input4: undefined,
+ 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 ')
+ equal( el.find('[name="input3"]').attr('required'), 'required', 'check required attribute of input3 ')
+ equal( el.find('[name="input3"]').is(":visible"), true, 'check visible attribute of input3 ')
+ equal( el.find('[name="input4"]').is(":visible"), false, 'check visible attribute of input4 ')
});
\ No newline at end of file
diff --git a/test/browser/aab_unit_test.rb b/test/browser/aab_unit_test.rb
index a702c571a..cf8609337 100644
--- a/test/browser/aab_unit_test.rb
+++ b/test/browser/aab_unit_test.rb
@@ -112,6 +112,28 @@ class AAbUnitTest < TestCase
]
browser_single_test(tests)
end
+ def test_form_validation
+ tests = [
+ {
+ :name => 'start',
+ :instance => browser_instance,
+ :url => browser_url + '/tests-form-validation',
+ :action => [
+ {
+ :execute => 'wait',
+ :value => 8,
+ },
+ {
+ :execute => 'match',
+ :css => '.result .failed',
+ :value => '0',
+ :match_result => true,
+ },
+ ],
+ },
+ ]
+ browser_single_test(tests)
+ end
def test_table
tests = [
{