Improved ticket selector. Added browser tests.

This commit is contained in:
Martin Edenhofer 2016-03-14 00:25:05 +01:00
parent df1420d5db
commit 4324db9b9f
9 changed files with 642 additions and 294 deletions

View file

@ -8,9 +8,6 @@ class App.UiElement.ticket_perform_action
name: 'Ticket' name: 'Ticket'
model: 'Ticket' model: 'Ticket'
operators =
'ticket.tags': ['add', 'remove']
# megre config # megre config
elements = {} elements = {}
for groupKey, groupMeta of groups for groupKey, groupMeta of groups
@ -22,13 +19,15 @@ class App.UiElement.ticket_perform_action
# ignore readonly attributes # ignore readonly attributes
if !row.readonly if !row.readonly
config = _.clone(row) config = _.clone(row)
if config.tag is 'tag'
config.operator = ['add', 'remove']
elements["#{groupKey}.#{config.name}"] = config elements["#{groupKey}.#{config.name}"] = config
[defaults, groups, operators, elements] [defaults, groups, elements]
@render: (attribute, params = {}) -> @render: (attribute, params = {}) ->
[defaults, groups, operators, elements] = @defaults() [defaults, groups, elements] = @defaults()
selector = @buildAttributeSelector(groups, elements) selector = @buildAttributeSelector(groups, elements)
@ -42,22 +41,22 @@ class App.UiElement.ticket_perform_action
elementClone = element.clone(true) elementClone = element.clone(true)
element.after(elementClone) element.after(elementClone)
elementClone.find('.js-attributeSelector select').trigger('change') elementClone.find('.js-attributeSelector select').trigger('change')
@updateAttributeSelectors(item)
) )
# remove filter # remove filter
item.find('.js-remove').bind('click', (e) => item.find('.js-remove').bind('click', (e) =>
return if $(e.currentTarget).hasClass('is-disabled')
$(e.target).closest('.js-filterElement').remove() $(e.target).closest('.js-filterElement').remove()
@rebuildAttributeSelectors(item) @updateAttributeSelectors(item)
) )
# change attribute selector # change attribute selector
item.find('.js-attributeSelector select').bind('change', (e) => item.find('.js-attributeSelector select').bind('change', (e) =>
groupAndAttribute = $(e.target).find('option:selected').attr('value')
elementRow = $(e.target).closest('.js-filterElement') elementRow = $(e.target).closest('.js-filterElement')
groupAndAttribute = elementRow.find('.js-attributeSelector option:selected').attr('value')
@rebuildAttributeSelectors(item, elementRow, groupAndAttribute) @rebuildAttributeSelectors(item, elementRow, groupAndAttribute, elements, {}, attribute)
@buildOperator(item, elementRow, groupAndAttribute, elements, undefined, attribute, operators) @updateAttributeSelectors(item)
@buildValue(item, elementRow, groupAndAttribute, elements, undefined, attribute)
) )
# build inital params # build inital params
@ -75,9 +74,7 @@ class App.UiElement.ticket_perform_action
# clone, rebuild and append # clone, rebuild and append
elementClone = elementFirst.clone(true) elementClone = elementFirst.clone(true)
@rebuildAttributeSelectors(item, elementClone, groupAndAttribute) @rebuildAttributeSelectors(item, elementClone, groupAndAttribute, elements, meta, attribute)
@buildOperator(item, elementClone, groupAndAttribute, elements, value, attribute, operators, operator)
@buildValue(item, elementClone, groupAndAttribute, elements, value, attribute)
elementLast.after(elementClone) elementLast.after(elementClone)
# remove first dummy row # remove first dummy row
@ -85,7 +82,7 @@ class App.UiElement.ticket_perform_action
item.find('.js-filterElement').first().remove() item.find('.js-filterElement').first().remove()
else else
for default_row in defaults for groupAndAttribute in defaults
# get selector rows # get selector rows
elementFirst = item.find('.js-filterElement').first() elementFirst = item.find('.js-filterElement').first()
@ -93,64 +90,28 @@ class App.UiElement.ticket_perform_action
# clone, rebuild and append # clone, rebuild and append
elementClone = elementFirst.clone(true) elementClone = elementFirst.clone(true)
@rebuildAttributeSelectors(item, elementClone, default_row) @rebuildAttributeSelectors(item, elementClone, groupAndAttribute, elements, {}, attribute)
elementLast.after(elementClone) elementLast.after(elementClone)
item.find('.js-filterElement').first().remove() item.find('.js-filterElement').first().remove()
# change attribute selector
item.find('.js-attributeSelector select').bind('change', (e) =>
elementRow = $(e.target).closest('.js-filterElement')
groupAndAttribute = elementRow.find('.js-attributeSelector option:selected').attr('value')
@rebuildAttributeSelectors(item, elementRow, groupAndAttribute, elements, {}, attribute)
@updateAttributeSelectors(item)
)
# change operator selector
item.on('change', '.js-operator select', (e) =>
elementRow = $(e.target).closest('.js-filterElement')
groupAndAttribute = elementRow.find('.js-attributeSelector option:selected').attr('value')
@buildOperator(item, elementRow, groupAndAttribute, elements, {}, attribute)
)
item item
@buildOperator: (elementFull, elementRow, groupAndAttribute, elements, value, attribute, operators, operator) ->
name = "#{attribute.name}::#{groupAndAttribute}::operator"
if !operators[groupAndAttribute]
elementRow.find('.js-operator').html('')
return
# get current operator
if !operator
operator = elementRow.find('.js-operator select').val()
# build new operator
selection = $("<select class=\"form-control\" name=\"#{name}\"></select>")
for operatorKey in operators[groupAndAttribute]
operatorKeyName = App.i18n.translateInline(operatorKey)
selected = ''
if operatorKey is operator
selected = 'selected'
selection.append("<option value=\"#{operatorKey}\" #{selected}>#{operatorKeyName}</option>")
elementRow.find('.js-operator').html(selection)
@buildValue: (elementFull, elementRow, groupAndAttribute, elements, value, attribute) ->
# do nothing if item already exists
name = "#{attribute.name}::#{groupAndAttribute}::value"
return if elementRow.find("[name=\"#{name}\"]").get(0)
return if elementRow.find("[data-name=\"#{name}\"]").get(0)
# build new item
attributeConfig = elements[groupAndAttribute]
config = _.clone(attributeConfig)
# force to use auto compition on user lookup
if config.relation is 'User'
config.tag = 'user_autocompletion'
# render ui element
item = ''
if config && App.UiElement[config.tag]
config['name'] = name
config['value'] = value
if 'multiple' of config
config.multiple = false
config.nulloption = false
if config.tag is 'checkbox'
config.tag = 'select'
tagSearch = "#{config.tag}_search"
if App.UiElement[tagSearch]
item = App.UiElement[tagSearch].render(config, {})
else
item = App.UiElement[config.tag].render(config, {})
elementRow.find('.js-value').html(item)
@buildAttributeSelector: (groups, elements) -> @buildAttributeSelector: (groups, elements) ->
selection = $('<select class="form-control"></select>') selection = $('<select class="form-control"></select>')
for groupKey, groupMeta of groups for groupKey, groupMeta of groups
@ -165,7 +126,7 @@ class App.UiElement.ticket_perform_action
optgroup.append("<option value=\"#{elementKey}\">#{displayName}</option>") optgroup.append("<option value=\"#{elementKey}\">#{displayName}</option>")
selection selection
@rebuildAttributeSelectors: (elementFull, elementRow, groupAndAttribute) -> @updateAttributeSelectors: (elementFull) ->
# enable all # enable all
elementFull.find('.js-attributeSelector select option').removeAttr('disabled') elementFull.find('.js-attributeSelector select option').removeAttr('disabled')
@ -182,10 +143,147 @@ class App.UiElement.ticket_perform_action
else else
elementFull.find('.js-remove').addClass('is-disabled') elementFull.find('.js-remove').addClass('is-disabled')
@rebuildAttributeSelectors: (elementFull, elementRow, groupAndAttribute, elements, meta, attribute) ->
console.log('aa', groupAndAttribute, meta)
# set attribute # set attribute
if groupAndAttribute if groupAndAttribute
elementRow.find('.js-attributeSelector select').val(groupAndAttribute) elementRow.find('.js-attributeSelector select').val(groupAndAttribute)
@buildOperator(elementFull, elementRow, groupAndAttribute, elements, meta, attribute)
@buildOperator: (elementFull, elementRow, groupAndAttribute, elements, meta, attribute) ->
currentOperator = elementRow.find('.js-operator option:selected').attr('value')
if !meta.operator
meta.operator = currentOperator
name = "#{attribute.name}::#{groupAndAttribute}::operator"
selection = $("<select class=\"form-control\" name=\"#{name}\"></select>")
attributeConfig = elements[groupAndAttribute]
if !attributeConfig.operator
elementRow.find('.js-operator').addClass('hide')
else
elementRow.find('.js-operator').removeClass('hide')
if attributeConfig.operator
for operator in attributeConfig.operator
operatorName = App.i18n.translateInline(operator)
selected = ''
if meta.operator is operator
selected = 'selected="selected"'
selection.append("<option value=\"#{operator}\" #{selected}>#{operatorName}</option>")
selection
elementRow.find('.js-operator select').replaceWith(selection)
@buildPreCondition(elementFull, elementRow, groupAndAttribute, elements, meta, attribute)
@buildPreCondition: (elementFull, elementRow, groupAndAttribute, elements, meta, attributeConfig) ->
currentOperator = elementRow.find('.js-operator option:selected').attr('value')
currentPreCondition = elementRow.find('.js-preCondition option:selected').attr('value')
if !meta.pre_condition
meta.pre_condition = currentPreCondition
toggleValue = =>
preCondition = elementRow.find('.js-preCondition option:selected').attr('value')
if preCondition isnt 'specific'
elementRow.find('.js-value select').html('')
elementRow.find('.js-value').addClass('hide')
else
elementRow.find('.js-value').removeClass('hide')
@buildValue(elementFull, elementRow, groupAndAttribute, elements, meta, attribute)
# force to use auto complition on user lookup
attribute = _.clone(attributeConfig)
name = "#{attribute.name}::#{groupAndAttribute}::value"
attributeSelected = elements[groupAndAttribute]
preCondition = false
if attributeSelected.relation is 'User'
preCondition = 'user'
attribute.tag = 'user_autocompletion'
if attributeSelected.relation is 'Organization'
preCondition = 'org'
attribute.tag = 'autocompletion_ajax'
if !preCondition
elementRow.find('.js-preCondition select').html('')
elementRow.find('.js-preCondition').addClass('hide')
toggleValue()
@buildValue(elementFull, elementRow, groupAndAttribute, elements, meta, attribute)
return
elementRow.find('.js-preCondition').removeClass('hide')
name = "#{attribute.name}::#{groupAndAttribute}::pre_condition"
selection = $("<select class=\"form-control\" name=\"#{name}\" ></select>")
options = {}
if preCondition is 'user'
options =
'current_user.id': App.i18n.translateInline('current user')
'specific': App.i18n.translateInline('specific user')
#'set': App.i18n.translateInline('set')
else if preCondition is 'org'
options =
'current_user.organization_id': App.i18n.translateInline('current user organization')
'specific': App.i18n.translateInline('specific organization')
#'set': App.i18n.translateInline('set')
for key, value of options
selected = ''
if key is meta.pre_condition
selected = 'selected="selected"'
selection.append("<option value=\"#{key}\" #{selected}>#{App.i18n.translateInline(value)}</option>")
elementRow.find('.js-preCondition').removeClass('hide')
elementRow.find('.js-preCondition select').replaceWith(selection)
elementRow.find('.js-preCondition select').bind('change', (e) ->
toggleValue()
)
@buildValue(elementFull, elementRow, groupAndAttribute, elements, meta, attribute)
toggleValue()
@buildValue: (elementFull, elementRow, groupAndAttribute, elements, meta, attribute) ->
name = "#{attribute.name}::#{groupAndAttribute}::value"
# build new item
attributeConfig = elements[groupAndAttribute]
config = _.clone(attributeConfig)
if config.relation is 'User'
config.tag = 'user_autocompletion'
if config.relation is 'Organization'
config.tag = 'autocompletion_ajax'
# render ui element
item = ''
if config && App.UiElement[config.tag]
config['name'] = name
if attribute.value && attribute.value[groupAndAttribute]
config['value'] = _.clone(attribute.value[groupAndAttribute]['value'])
config.multiple = false
config.nulloption = false
if config.tag is 'checkbox'
config.tag = 'select'
tagSearch = "#{config.tag}_search"
if App.UiElement[tagSearch]
item = App.UiElement[tagSearch].render(config, {})
else
item = App.UiElement[config.tag].render(config, {})
if meta.operator is 'before (relative)' || meta.operator is 'within next (relative)' || meta.operator is 'within last (relative)' || meta.operator is 'after (relative)'
config['name'] = "#{attribute.name}::#{groupAndAttribute}"
if attribute.value && attribute.value[groupAndAttribute]
config['value'] = _.clone(attribute.value[groupAndAttribute])
item = App.UiElement['time_range'].render(config, {})
elementRow.find('.js-value').removeClass('hide').html(item)
@humanText: (condition) -> @humanText: (condition) ->
none = App.i18n.translateContent('No filter.') none = App.i18n.translateContent('No filter.')
return [none] if _.isEmpty(condition) return [none] if _.isEmpty(condition)

View file

@ -64,34 +64,23 @@ class App.UiElement.ticket_selector
elementClone = element.clone(true) elementClone = element.clone(true)
element.after(elementClone) element.after(elementClone)
elementClone.find('.js-attributeSelector select').trigger('change') elementClone.find('.js-attributeSelector select').trigger('change')
@updateAttributeSelectors(item)
@preview(item) @preview(item)
) )
# remove filter # remove filter
item.find('.js-remove').bind('click', (e) => item.find('.js-remove').bind('click', (e) =>
return if $(e.currentTarget).hasClass('is-disabled')
$(e.target).closest('.js-filterElement').remove() $(e.target).closest('.js-filterElement').remove()
@rebuildAttributeSelectors(item) @updateAttributeSelectors(item)
@preview(item) @preview(item)
) )
# change attribute selector
item.find('.js-attributeSelector select').bind('change', (e) =>
groupAndAttribute = $(e.target).find('option:selected').attr('value')
elementRow = $(e.target).closest('.js-filterElement')
@rebuildAttributeSelectors(item, elementRow, groupAndAttribute)
@rebuildOperater(item, elementRow, groupAndAttribute, elements, undefined, attribute)
@buildValue(item, elementRow, groupAndAttribute, elements, undefined, undefined, attribute)
)
# build inital params # build inital params
if !_.isEmpty(params[attribute.name]) if !_.isEmpty(params[attribute.name])
selectorExists = false selectorExists = false
for groupAndAttribute, meta of params[attribute.name] for groupAndAttribute, meta of params[attribute.name]
selectorExists = true selectorExists = true
operator = meta.operator
value = meta.value
# get selector rows # get selector rows
elementFirst = item.find('.js-filterElement').first() elementFirst = item.find('.js-filterElement').first()
@ -99,9 +88,7 @@ class App.UiElement.ticket_selector
# clone, rebuild and append # clone, rebuild and append
elementClone = elementFirst.clone(true) elementClone = elementFirst.clone(true)
@rebuildAttributeSelectors(item, elementClone, groupAndAttribute) @rebuildAttributeSelectors(item, elementClone, groupAndAttribute, elements, meta, attribute)
@rebuildOperater(item, elementClone, groupAndAttribute, elements, operator, attribute)
@buildValue(item, elementClone, groupAndAttribute, elements, value, operator, attribute)
elementLast.after(elementClone) elementLast.after(elementClone)
# remove first dummy row # remove first dummy row
@ -109,7 +96,7 @@ class App.UiElement.ticket_selector
item.find('.js-filterElement').first().remove() item.find('.js-filterElement').first().remove()
else else
for default_row in defaults for groupAndAttribute in defaults
# get selector rows # get selector rows
elementFirst = item.find('.js-filterElement').first() elementFirst = item.find('.js-filterElement').first()
@ -117,7 +104,7 @@ class App.UiElement.ticket_selector
# clone, rebuild and append # clone, rebuild and append
elementClone = elementFirst.clone(true) elementClone = elementFirst.clone(true)
@rebuildAttributeSelectors(item, elementClone, default_row) @rebuildAttributeSelectors(item, elementClone, groupAndAttribute, elements, {}, attribute)
elementLast.after(elementClone) elementLast.after(elementClone)
item.find('.js-filterElement').first().remove() item.find('.js-filterElement').first().remove()
@ -138,12 +125,25 @@ class App.UiElement.ticket_selector
triggerSearch() triggerSearch()
) )
# change attribute selector
item.find('.js-attributeSelector select').bind('change', (e) =>
elementRow = $(e.target).closest('.js-filterElement')
groupAndAttribute = elementRow.find('.js-attributeSelector option:selected').attr('value')
@rebuildAttributeSelectors(item, elementRow, groupAndAttribute, elements, {}, attribute)
@updateAttributeSelectors(item)
)
# change operator selector
item.on('change', '.js-operator select', (e) =>
elementRow = $(e.target).closest('.js-filterElement')
groupAndAttribute = elementRow.find('.js-attributeSelector option:selected').attr('value')
@buildOperator(item, elementRow, groupAndAttribute, elements, {}, attribute)
)
item item
@preview: (item) -> @preview: (item) ->
params = App.ControllerForm.params(item) params = App.ControllerForm.params(item)
# ajax call
App.Ajax.request( App.Ajax.request(
id: 'ticket_selector' id: 'ticket_selector'
type: 'POST' type: 'POST'
@ -164,26 +164,149 @@ class App.UiElement.ticket_selector
ticket_ids: ticket_ids ticket_ids: ticket_ids
) )
@buildValue: (elementFull, elementRow, groupAndAttribute, elements, value, operator, attribute) -> @buildAttributeSelector: (groups, elements) ->
selection = $('<select class="form-control"></select>')
for groupKey, groupMeta of groups
displayName = App.i18n.translateInline(groupMeta.name)
selection.closest('select').append("<optgroup label=\"#{displayName}\" class=\"js-#{groupKey}\"></optgroup>")
optgroup = selection.find("optgroup.js-#{groupKey}")
for elementKey, elementGroup of elements
spacer = elementKey.split(/\./)
if spacer[0] is groupKey
attributeConfig = elements[elementKey]
if attributeConfig.operator
displayName = App.i18n.translateInline(attributeConfig.display)
optgroup.append("<option value=\"#{elementKey}\">#{displayName}</option>")
selection
# do nothing if item already exists @updateAttributeSelectors: (elementFull) ->
operator = elementRow.find('.js-operator option:selected').attr('value')
# enable all
elementFull.find('.js-attributeSelector select option').removeAttr('disabled')
# disable all used attributes
elementFull.find('.js-attributeSelector select').each(->
keyLocal = $(@).val()
elementFull.find('.js-attributeSelector select option[value="' + keyLocal + '"]').attr('disabled', true)
)
# disable - if we only have one attribute
if elementFull.find('.js-attributeSelector select').length > 1
elementFull.find('.js-remove').removeClass('is-disabled')
else
elementFull.find('.js-remove').addClass('is-disabled')
@rebuildAttributeSelectors: (elementFull, elementRow, groupAndAttribute, elements, meta, attribute) ->
# set attribute
if groupAndAttribute
elementRow.find('.js-attributeSelector select').val(groupAndAttribute)
@buildOperator(elementFull, elementRow, groupAndAttribute, elements, meta, attribute)
@buildOperator: (elementFull, elementRow, groupAndAttribute, elements, meta, attribute) ->
currentOperator = elementRow.find('.js-operator option:selected').attr('value')
if !meta.operator
meta.operator = currentOperator
name = "#{attribute.name}::#{groupAndAttribute}::operator"
selection = $("<select class=\"form-control\" name=\"#{name}\"></select>")
attributeConfig = elements[groupAndAttribute]
if attributeConfig.operator
for operator in attributeConfig.operator
operatorName = App.i18n.translateInline(operator)
selected = ''
if meta.operator is operator
selected = 'selected="selected"'
selection.append("<option value=\"#{operator}\" #{selected}>#{operatorName}</option>")
selection
elementRow.find('.js-operator select').replaceWith(selection)
@buildPreCondition(elementFull, elementRow, groupAndAttribute, elements, meta, attribute)
@buildPreCondition: (elementFull, elementRow, groupAndAttribute, elements, meta, attributeConfig) ->
currentOperator = elementRow.find('.js-operator option:selected').attr('value')
currentPreCondition = elementRow.find('.js-preCondition option:selected').attr('value')
if !meta.pre_condition
meta.pre_condition = currentPreCondition
toggleValue = =>
preCondition = elementRow.find('.js-preCondition option:selected').attr('value')
if preCondition isnt 'specific'
elementRow.find('.js-value select').html('')
elementRow.find('.js-value').addClass('hide')
else
elementRow.find('.js-value').removeClass('hide')
@buildValue(elementFull, elementRow, groupAndAttribute, elements, meta, attribute)
# force to use auto complition on user lookup
attribute = _.clone(attributeConfig)
name = "#{attribute.name}::#{groupAndAttribute}::value"
attributeSelected = elements[groupAndAttribute]
preCondition = false
if attributeSelected.relation is 'User'
preCondition = 'user'
attribute.tag = 'user_autocompletion'
if attributeSelected.relation is 'Organization'
preCondition = 'org'
attribute.tag = 'autocompletion_ajax'
if !preCondition
elementRow.find('.js-preCondition select').html('')
elementRow.find('.js-preCondition').addClass('hide')
toggleValue()
@buildValue(elementFull, elementRow, groupAndAttribute, elements, meta, attribute)
return
elementRow.find('.js-preCondition').removeClass('hide')
name = "#{attribute.name}::#{groupAndAttribute}::pre_condition"
selection = $("<select class=\"form-control\" name=\"#{name}\" ></select>")
options = {}
if preCondition is 'user'
options =
'current_user.id': App.i18n.translateInline('current user')
'specific': App.i18n.translateInline('specific user')
#'set': App.i18n.translateInline('set')
else if preCondition is 'org'
options =
'current_user.organization_id': App.i18n.translateInline('current user organization')
'specific': App.i18n.translateInline('specific organization')
#'set': App.i18n.translateInline('set')
for key, value of options
selected = ''
if key is meta.pre_condition
selected = 'selected="selected"'
selection.append("<option value=\"#{key}\" #{selected}>#{App.i18n.translateInline(value)}</option>")
elementRow.find('.js-preCondition').removeClass('hide')
elementRow.find('.js-preCondition select').replaceWith(selection)
elementRow.find('.js-preCondition select').bind('change', (e) ->
toggleValue()
)
@buildValue(elementFull, elementRow, groupAndAttribute, elements, meta, attribute)
toggleValue()
@buildValue: (elementFull, elementRow, groupAndAttribute, elements, meta, attribute) ->
name = "#{attribute.name}::#{groupAndAttribute}::value" name = "#{attribute.name}::#{groupAndAttribute}::value"
# build new item # build new item
attributeConfig = elements[groupAndAttribute] attributeConfig = elements[groupAndAttribute]
config = _.clone(attributeConfig) config = _.clone(attributeConfig)
# force to use auto complition on user lookup
config.preCondition = false
if config.relation is 'User' if config.relation is 'User'
config.preCondition = 'user'
config.tag = 'user_autocompletion' config.tag = 'user_autocompletion'
if config.relation is 'Organization' if config.relation is 'Organization'
config.tag = 'autocompletion_ajax' config.tag = 'autocompletion_ajax'
config.preCondition = 'org'
@buildPreCondition(config, elementFull, elementRow, groupAndAttribute, attribute)
# render ui element # render ui element
item = '' item = ''
@ -201,121 +324,13 @@ class App.UiElement.ticket_selector
item = App.UiElement[tagSearch].render(config, {}) item = App.UiElement[tagSearch].render(config, {})
else else
item = App.UiElement[config.tag].render(config, {}) item = App.UiElement[config.tag].render(config, {})
if meta.operator is 'before (relative)' || meta.operator is 'within next (relative)' || meta.operator is 'within last (relative)' || meta.operator is 'after (relative)'
if operator is 'before (relative)' || operator is 'within next (relative)' || operator is 'within last (relative)' || operator is 'after (relative)'
config['name'] = "#{attribute.name}::#{groupAndAttribute}" config['name'] = "#{attribute.name}::#{groupAndAttribute}"
if attribute.value && attribute.value[groupAndAttribute]
config['value'] = _.clone(attribute.value[groupAndAttribute]) config['value'] = _.clone(attribute.value[groupAndAttribute])
item = App.UiElement['time_range'].render(config, {}) item = App.UiElement['time_range'].render(config, {})
elementRow.find('.js-value').html(item) elementRow.find('.js-value').removeClass('hide').html(item)
@buildPreCondition: (config, elementFull, elementRow, groupAndAttribute, attribute) ->
if !config.preCondition
elementRow.find('.js-preCondition').addClass('hide')
return
name = "#{attribute.name}::#{groupAndAttribute}::pre_condition"
preConditionCurrent = elementRow.find('.js-preCondition option:selected').attr('value')
if !preCondition && attribute.value && attribute.value[groupAndAttribute]
preCondition = attribute.value[groupAndAttribute].pre_condition
selection = $("<select class=\"form-control\" name=\"#{name}\" ></select>")
options = {}
if config.preCondition is 'user'
options =
'set': App.i18n.translateInline('set')
'current_user.id': App.i18n.translateInline('current user')
'specific': App.i18n.translateInline('specific user')
else if config.preCondition is 'org'
options =
'set': App.i18n.translateInline('set')
'current_user.organization_id': App.i18n.translateInline('current user organization')
'specific': App.i18n.translateInline('specific organization')
for key, value of options
selected = preConditionCurrent
if key is preCondition
selected = 'selected="selected"'
selection.append("<option value=\"#{key}\" #{selected}>#{App.i18n.translateInline(value)}</option>")
elementRow.find('.js-preCondition').removeClass('hide')
elementRow.find('.js-preCondition select').replaceWith(selection)
toggle = ->
preCondition = elementRow.find('.js-preCondition option:selected').attr('value')
if preCondition is 'specific'
elementRow.find('.js-value').removeClass('hide')
else
elementRow.find('.js-value').addClass('hide')
toggle()
elementRow.find('.js-preCondition select').bind('change', (e) ->
toggle()
)
@buildAttributeSelector: (groups, elements) ->
selection = $('<select class="form-control"></select>')
for groupKey, groupMeta of groups
displayName = App.i18n.translateInline(groupMeta.name)
selection.closest('select').append("<optgroup label=\"#{displayName}\" class=\"js-#{groupKey}\"></optgroup>")
optgroup = selection.find("optgroup.js-#{groupKey}")
for elementKey, elementGroup of elements
spacer = elementKey.split(/\./)
if spacer[0] is groupKey
attributeConfig = elements[elementKey]
if attributeConfig.operator
displayName = App.i18n.translateInline(attributeConfig.display)
optgroup.append("<option value=\"#{elementKey}\">#{displayName}</option>")
selection
@rebuildAttributeSelectors: (elementFull, elementRow, groupAndAttribute) ->
# enable all
elementFull.find('.js-attributeSelector select option').removeAttr('disabled')
# disable all used attributes
elementFull.find('.js-attributeSelector select').each(->
keyLocal = $(@).val()
elementFull.find('.js-attributeSelector select option[value="' + keyLocal + '"]').attr('disabled', true)
)
# disable - if we only have one attribute
if elementFull.find('.js-attributeSelector select').length > 1
elementFull.find('.js-remove').removeClass('is-disabled')
else
elementFull.find('.js-remove').addClass('is-disabled')
# set attribute
if groupAndAttribute
elementRow.find('.js-attributeSelector select').val(groupAndAttribute)
@buildOperator: (elementFull, elementRow, groupAndAttribute, elements, current_operator, attribute) ->
selection = $("<select class=\"form-control\" name=\"#{attribute.name}::#{groupAndAttribute}::operator\"></select>")
attributeConfig = elements[groupAndAttribute]
if attributeConfig.operator
for operator in attributeConfig.operator
operatorName = App.i18n.translateInline(operator)
selected = ''
if current_operator is operator
selected = 'selected="selected"'
selection.append("<option value=\"#{operator}\" #{selected}>#{operatorName}</option>")
selection
@rebuildOperater: (elementFull, elementRow, groupAndAttribute, elements, current_operator, attribute) ->
return if !groupAndAttribute
# do nothing if item already exists
name = "#{attribute.name}::#{groupAndAttribute}::operator"
return if elementRow.find("[name=\"#{name}\"]").get(0)
# render new operator
operator = @buildOperator(elementFull, elementRow, groupAndAttribute, elements, current_operator, attribute)
elementRow.find('.js-operator select').replaceWith(operator)
# render not value option
elementRow.find('.js-operator select').bind('change', (e) =>
groupAndAttribute = elementRow.find('.js-attributeSelector option:selected').attr('value')
operator = elementRow.find('.js-operator option:selected').attr('value')
@buildValue(elementFull, elementRow, groupAndAttribute, elements, undefined, operator, attribute)
)
@humanText: (condition) -> @humanText: (condition) ->
none = App.i18n.translateContent('No filter.') none = App.i18n.translateContent('No filter.')

View file

@ -6,7 +6,18 @@
<%- @Icon('arrow-down', 'dropdown-arrow') %> <%- @Icon('arrow-down', 'dropdown-arrow') %>
</div> </div>
</div> </div>
<div class="controls js-operator"></div> <div class="controls">
<div class="u-positionOrigin js-operator">
<select></select>
<%- @Icon('arrow-down', 'dropdown-arrow') %>
</div>
</div>
<div class="controls">
<div class="u-positionOrigin js-preCondition">
<select></select>
<%- @Icon('arrow-down', 'dropdown-arrow') %>
</div>
</div>
<div class="controls js-value"></div> <div class="controls js-value"></div>
</div> </div>
<div class="filter-controls"> <div class="filter-controls">

View file

@ -1,7 +1,7 @@
<div class="controls u-positionOrigin"> <div class="controls u-positionOrigin">
<select class="form-control js-value" name="<%= @attribute.name %>::value"> <select class="form-control js-value" name="<%= @attribute.name %>::value">
<% for key, value of @values: %> <% for key, value of @values: %>
<option value="<%= key %>" <% if @attribute.value && @attribute.value.value is key: %>selected<% end %>><%- value %></option> <option value="<%= key %>" <% if @attribute.value && @attribute.value.value.toString() is key.toString(): %>selected<% end %>><%- value %></option>
<% end %> <% end %>
</select> </select>
<%- @Icon('arrow-down', 'dropdown-arrow') %> <%- @Icon('arrow-down', 'dropdown-arrow') %>

View file

@ -5,7 +5,6 @@ class Overview < ApplicationModel
store :order store :order
store :view store :view
validates :name, presence: true validates :name, presence: true
validates :prio, presence: true
before_create :fill_link_on_create, :fill_prio before_create :fill_link_on_create, :fill_prio
before_update :fill_link_on_update before_update :fill_link_on_update
@ -16,8 +15,8 @@ class Overview < ApplicationModel
private private
def fill_prio def fill_prio
return true if prio return true if !prio.empty?
prio = 9999 self.prio = 9999
end end
def fill_link_on_create def fill_link_on_create

View file

@ -54,8 +54,9 @@ test( 'form checks', function() {
}, },
]) ])
$('#forms').append('<hr><h1>form time check</h1><form id="form1"></form>')
/* working hours and escalation_times */
$('#forms').append('<hr><h1>form condition check</h1><form id="form1"></form>')
var el = $('#form1') var el = $('#form1')
var defaults = { var defaults = {
working_hours: { working_hours: {
@ -106,42 +107,6 @@ test( 'form checks', function() {
first_response_time: 150, first_response_time: 150,
solution_time: '', solution_time: '',
update_time: 45, update_time: 45,
conditions: {
'ticket.title': {
operator: 'contains',
value: 'some title',
},
'ticket.priority_id': {
operator: 'is',
value: [1,2,3],
},
'ticket.created_at': {
operator: 'before (absolute)',
value: '2015-09-20T03:41:00.000Z',
},
'ticket.organization_id': {
operator: 'is not',
pre_condition: 'specific',
value: 12,
},
'ticket.owner_id': {
operator: 'is',
pre_condition: 'specific',
value: 47,
},
},
executions: {
'ticket.title': {
value: 'some title new',
},
'ticket.priority_id': {
value: 3,
},
'ticket.tags': {
operator: 'remove',
value: 'tag1, tag2',
},
},
} }
new App.ControllerForm({ new App.ControllerForm({
el: el, el: el,
@ -149,14 +114,11 @@ test( 'form checks', function() {
configure_attributes: [ configure_attributes: [
{ name: 'escalation_times', display: 'Times', tag: 'sla_times', null: true }, { name: 'escalation_times', display: 'Times', tag: 'sla_times', null: true },
{ name: 'working_hours', display: 'Hours', tag: 'business_hours', null: true }, { name: 'working_hours', display: 'Hours', tag: 'business_hours', null: true },
{ name: 'conditions', display: 'Conditions', tag: 'ticket_selector', null: true },
{ name: 'executions', display: 'Executions', tag: 'ticket_perform_action', null: true },
] ]
}, },
params: defaults, params: defaults,
autofocus: true autofocus: true
}); })
var params = App.ControllerForm.params(el) var params = App.ControllerForm.params(el)
var test_params = { var test_params = {
first_response_time: '150', first_response_time: '150',
@ -165,43 +127,6 @@ test( 'form checks', function() {
solution_time_in_text: '', solution_time_in_text: '',
update_time: '45', update_time: '45',
update_time_in_text: '00:45', update_time_in_text: '00:45',
conditions: {
'ticket.title': {
operator: 'contains',
value: 'some title',
},
'ticket.priority_id': {
operator: 'is',
value: ['1', '3'],
},
'ticket.created_at': {
operator: 'before (absolute)',
value: '2015-09-20T03:41:00.000Z',
},
'ticket.organization_id': {
operator: 'is not',
pre_condition: 'specific',
value: '12',
},
'ticket.owner_id': {
operator: 'is',
pre_condition: 'specific',
value: '47',
value_completion: 'Bob Smith <bod@example.com>',
},
},
executions: {
'ticket.title': {
value: 'some title new',
},
'ticket.priority_id': {
value: '3',
},
'ticket.tags': {
operator: 'remove',
value: 'tag1, tag2',
},
},
working_hours: { working_hours: {
mon: { mon: {
active: true, active: true,
@ -248,16 +173,12 @@ test( 'form checks', function() {
}, },
}, },
} }
deepEqual( params, test_params, 'form param check' ); deepEqual(params, test_params, 'form param check')
// change sla times // change sla times
el.find('[name="first_response_time_in_text"]').val('0:30').trigger('blur') el.find('[name="first_response_time_in_text"]').val('0:30').trigger('blur')
el.find('#update_time').click() el.find('#update_time').click()
// change selector
el.find('[name="conditions::ticket.priority_id::value"]').closest('.js-filterElement').find('.js-remove').click()
el.find('[name="executions::ticket.title::value"]').closest('.js-filterElement').find('.js-remove').click()
var params = App.ControllerForm.params(el) var params = App.ControllerForm.params(el)
var test_params = { var test_params = {
working_hours: { working_hours: {
@ -311,15 +232,125 @@ test( 'form checks', function() {
solution_time_in_text: '', solution_time_in_text: '',
update_time: '', update_time: '',
update_time_in_text: '', update_time_in_text: '',
conditions: { }
deepEqual(params, test_params, 'form param check')
/* empty params or defaults */
$('#forms').append('<hr><h1>form condition check</h1><form id="form2"></form>')
var el = $('#form2')
new App.ControllerForm({
el: el,
model: {
configure_attributes: [
{ name: 'condition', display: 'Conditions', tag: 'ticket_selector', null: true },
{ name: 'executions', display: 'Executions', tag: 'ticket_perform_action', null: true },
]
},
autofocus: true
})
var params = App.ControllerForm.params(el)
var test_params = {
condition: {
'ticket.state_id': {
operator: 'is',
value: '2',
},
},
executions: {
'ticket.state_id': {
value: '2',
},
},
}
deepEqual(params, test_params, 'form param check');
/* with params or defaults */
$('#forms').append('<hr><h1>form time check</h1><form id="form3"></form>')
var el = $('#form3')
var defaults = {
condition: {
'ticket.title': { 'ticket.title': {
operator: 'contains', operator: 'contains',
value: 'some title', value: 'some title',
}, },
'ticket.priority_id': {
operator: 'is',
value: [1,2,3],
},
'ticket.created_at': { 'ticket.created_at': {
operator: 'before (absolute)', operator: 'before (absolute)',
value: '2015-09-20T03:41:00.000Z', value: '2015-09-20T03:41:00.000Z',
}, },
'ticket.updated_at': {
operator: 'within last (relative)',
range: 'year',
value: 2,
},
'ticket.organization_id': {
operator: 'is not',
pre_condition: 'specific',
value: 12,
},
'ticket.owner_id': {
operator: 'is',
pre_condition: 'specific',
value: 47,
},
'ticket.created_by_id': {
operator: 'is',
pre_condition: 'current_user.id',
value: '',
},
},
executions: {
'ticket.title': {
value: 'some title new',
},
'ticket.priority_id': {
value: 3,
},
'ticket.owner_id': {
pre_condition: 'specific',
value: 47,
},
'ticket.tags': {
operator: 'remove',
value: 'tag1, tag2',
},
},
}
new App.ControllerForm({
el: el,
model: {
configure_attributes: [
{ name: 'condition', display: 'Conditions', tag: 'ticket_selector', null: true },
{ name: 'executions', display: 'Executions', tag: 'ticket_perform_action', null: true },
]
},
params: defaults,
autofocus: true
})
var params = App.ControllerForm.params(el)
var test_params = {
condition: {
'ticket.title': {
operator: 'contains',
value: 'some title',
},
'ticket.priority_id': {
operator: 'is',
value: ['1', '3'],
},
'ticket.created_at': {
operator: 'before (absolute)',
value: '2015-09-20T03:41:00.000Z',
},
'ticket.updated_at': {
operator: 'within last (relative)',
range: 'year',
value: '2',
},
'ticket.organization_id': { 'ticket.organization_id': {
operator: 'is not', operator: 'is not',
pre_condition: 'specific', pre_condition: 'specific',
@ -331,8 +362,22 @@ test( 'form checks', function() {
value: '47', value: '47',
value_completion: 'Bob Smith <bod@example.com>', value_completion: 'Bob Smith <bod@example.com>',
}, },
'ticket.created_by_id': {
operator: 'is',
pre_condition: 'current_user.id',
value: '',
value_completion: ''
},
}, },
executions: { executions: {
'ticket.title': {
value: 'some title new',
},
'ticket.owner_id': {
pre_condition: 'specific',
value: '47',
value_completion: 'Bob Smith <bod@example.com>'
},
'ticket.priority_id': { 'ticket.priority_id': {
value: '3', value: '3',
}, },
@ -342,7 +387,63 @@ test( 'form checks', function() {
}, },
}, },
} }
deepEqual( params, test_params, 'form param check' ); deepEqual(params, test_params, 'form param check')
// change selector
el.find('[name="condition::ticket.priority_id::value"]').closest('.js-filterElement').find('.js-remove').click()
el.find('[name="executions::ticket.title::value"]').closest('.js-filterElement').find('.js-remove').click()
var params = App.ControllerForm.params(el)
var test_params = {
condition: {
'ticket.title': {
operator: 'contains',
value: 'some title',
},
'ticket.created_at': {
operator: 'before (absolute)',
value: '2015-09-20T03:41:00.000Z',
},
'ticket.updated_at': {
operator: 'within last (relative)',
range: 'year',
value: '2',
},
'ticket.organization_id': {
operator: 'is not',
pre_condition: 'specific',
value: '12',
},
'ticket.owner_id': {
operator: 'is',
pre_condition: 'specific',
value: '47',
value_completion: 'Bob Smith <bod@example.com>',
},
'ticket.created_by_id': {
operator: 'is',
pre_condition: 'current_user.id',
value: '',
value_completion: ''
},
},
executions: {
'ticket.priority_id': {
value: '3',
},
'ticket.owner_id': {
pre_condition: 'specific',
value: '47',
value_completion: 'Bob Smith <bod@example.com>'
},
'ticket.tags': {
operator: 'remove',
value: 'tag1, tag2',
},
},
}
deepEqual(params, test_params, 'form param check')
console.log('APO3', App.Organization.find(12))
//deepEqual(el.find('[name="times::days"]').val(), ['mon', 'wed'], 'check times::days value') //deepEqual(el.find('[name="times::days"]').val(), ['mon', 'wed'], 'check times::days value')
//equal(el.find('[name="times::hours"]').val(), 2, 'check times::hours value') //equal(el.find('[name="times::hours"]').val(), 2, 'check times::hours value')

View file

@ -6,6 +6,7 @@ if [ "$LEVEL" == '1' ]; then
# no ticket action # no ticket action
rm test/browser/admin_channel_email_test.rb rm test/browser/admin_channel_email_test.rb
rm test/browser/admin_overview_test.rb
rm test/browser/agent_user_profile_test.rb rm test/browser/agent_user_profile_test.rb
rm test/browser/agent_organization_profile_test.rb rm test/browser/agent_organization_profile_test.rb
rm test/browser/agent_ticket_*.rb rm test/browser/agent_ticket_*.rb
@ -23,6 +24,7 @@ elif [ "$LEVEL" == '2' ]; then
rm test/browser/aac_basic_richtext_test.rb rm test/browser/aac_basic_richtext_test.rb
rm test/browser/aab_basic_urls_test.rb rm test/browser/aab_basic_urls_test.rb
rm test/browser/admin_channel_email_test.rb rm test/browser/admin_channel_email_test.rb
rm test/browser/admin_overview_test.rb
rm test/browser/agent_organization_profile_test.rb rm test/browser/agent_organization_profile_test.rb
rm test/browser/agent_user_*.rb rm test/browser/agent_user_*.rb
rm test/browser/auth_test.rb rm test/browser/auth_test.rb

View file

@ -0,0 +1,41 @@
# encoding: utf-8
require 'browser_test_helper'
class AdminOverviewTest < TestCase
def test_account_add
name = "some overview #{rand(99_999_999)}"
@browser = browser_instance
login(
username: 'master@example.com',
password: 'test',
url: browser_url,
)
tasks_close_all()
# add new overview
overview_create(
data: {
name: name,
role: 'Agent',
selector: {
'Priority' => '1 low',
},
'order::direction' => 'down',
}
)
# edit overview
overview_update(
data: {
name: name,
role: 'Agent',
selector: {
'State' => 'new',
},
'order::direction' => 'up',
}
)
end
end

View file

@ -1233,7 +1233,7 @@ wait untill text in selector disabppears
=begin =begin
username = overview_create( overview_create(
browser: browser1, browser: browser1,
data: { data: {
name: name, name: name,
@ -1241,7 +1241,6 @@ wait untill text in selector disabppears
selector: { selector: {
'Priority': '1 low', 'Priority': '1 low',
}, },
prio: 1000,
'order::direction' => 'down', 'order::direction' => 'down',
} }
) )
@ -1278,6 +1277,7 @@ wait untill text in selector disabppears
element = instance.find_elements(css: '.modal .ticket_selector .js-attributeSelector select')[0] element = instance.find_elements(css: '.modal .ticket_selector .js-attributeSelector select')[0]
dropdown = Selenium::WebDriver::Support::Select.new(element) dropdown = Selenium::WebDriver::Support::Select.new(element)
dropdown.select_by(:text, key) dropdown.select_by(:text, key)
sleep 0.5
element = instance.find_elements(css: '.modal .ticket_selector .js-value select')[0] element = instance.find_elements(css: '.modal .ticket_selector .js-value select')[0]
dropdown = Selenium::WebDriver::Support::Select.new(element) dropdown = Selenium::WebDriver::Support::Select.new(element)
dropdown.deselect_all dropdown.deselect_all
@ -1309,6 +1309,87 @@ wait untill text in selector disabppears
raise 'overview creation failed' raise 'overview creation failed'
end end
=begin
overview_update(
browser: browser1,
data: {
name: name,
role: 'Agent',
selector: {
'Priority': '1 low',
},
'order::direction' => 'down',
}
)
=end
def overview_update(params)
switch_window_focus(params)
log('overview_create', params)
instance = params[:browser] || @browser
data = params[:data]
instance.find_elements(css: 'a[href="#manage"]')[0].click
sleep 0.2
instance.find_elements(css: 'a[href="#manage/overviews"]')[0].click
sleep 0.2
#instance.find_elements(css: '#content a[data-type="new"]')[0].click
#sleep 2
instance.execute_script("$(\"#content td:contains('#{params[:name]}')\").first().click()")
sleep 2
if data[:name]
element = instance.find_elements(css: '.modal input[name=name]')[0]
element.clear
element.send_keys(data[:name])
end
if data[:role]
element = instance.find_elements(css: '.modal select[name="role_id"]')[0]
dropdown = Selenium::WebDriver::Support::Select.new(element)
dropdown.select_by(:text, data[:role])
end
if data[:selector]
data[:selector].each {|key, value|
element = instance.find_elements(css: '.modal .ticket_selector .js-attributeSelector select')[0]
dropdown = Selenium::WebDriver::Support::Select.new(element)
dropdown.select_by(:text, key)
instance.execute_script("$('#content .modal .ticket_selector .js-attributeSelector select').first().trigger('change')")
element = instance.find_elements(css: '.modal .ticket_selector .js-value select')[0]
dropdown = Selenium::WebDriver::Support::Select.new(element)
dropdown.deselect_all
dropdown.select_by(:text, value)
}
end
if data['order::direction']
element = instance.find_elements(css: '.modal select[name="order::direction"]')[0]
dropdown = Selenium::WebDriver::Support::Select.new(element)
dropdown.select_by(:text, data['order::direction'])
end
instance.find_elements(css: '.modal button.js-submit')[0].click
(1..12).each {
element = instance.find_elements(css: 'body')[0]
text = element.text
if text =~ /#{Regexp.quote(data[:name])}/
assert(true, 'overview updated')
overview = {
name: name,
}
sleep 1
return overview
end
sleep 1
}
screenshot(browser: instance, comment: 'overview_update_failed')
raise 'overview update failed'
end
=begin =begin
ticket = ticket_create( ticket = ticket_create(