Fixes #3900 - Be able to select more than one owner or organization in condition for overviews/triggers/schedulers like you can do it for state, priority or group
This commit is contained in:
parent
50e3b98955
commit
bf3067d908
11 changed files with 746 additions and 91 deletions
|
@ -3,7 +3,7 @@ class App.UiElement.autocompletion_ajax
|
||||||
@render: (attribute, params = {}, form) ->
|
@render: (attribute, params = {}, form) ->
|
||||||
if params[attribute.name] || attribute.value
|
if params[attribute.name] || attribute.value
|
||||||
object = App[attribute.relation].find(params[attribute.name] || attribute.value)
|
object = App[attribute.relation].find(params[attribute.name] || attribute.value)
|
||||||
valueName = object.displayName()
|
valueName = object.displayName() if object
|
||||||
|
|
||||||
# selectable search
|
# selectable search
|
||||||
searchableAjaxSelectObject = new App.SearchableAjaxSelect(
|
searchableAjaxSelectObject = new App.SearchableAjaxSelect(
|
||||||
|
@ -17,5 +17,6 @@ class App.UiElement.autocompletion_ajax
|
||||||
limit: 40
|
limit: 40
|
||||||
object: attribute.relation
|
object: attribute.relation
|
||||||
ajax: true
|
ajax: true
|
||||||
|
multiple: attribute.multiple
|
||||||
)
|
)
|
||||||
searchableAjaxSelectObject.element()
|
searchableAjaxSelectObject.element()
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
# coffeelint: disable=camel_case_classes
|
||||||
|
class App.UiElement.autocompletion_ajax_search extends App.UiElement.autocompletion_ajax
|
||||||
|
@render: (attributeOrig, params = {}, form) ->
|
||||||
|
attribute = _.clone(attributeOrig)
|
||||||
|
attribute.multiple = true
|
||||||
|
super(attribute, params = {}, form)
|
|
@ -3,4 +3,5 @@ class App.UiElement.user_autocompletion_search
|
||||||
@render: (attributeOrig, params = {}) ->
|
@render: (attributeOrig, params = {}) ->
|
||||||
attribute = _.clone(attributeOrig)
|
attribute = _.clone(attributeOrig)
|
||||||
attribute.disableCreateObject = true
|
attribute.disableCreateObject = true
|
||||||
|
attribute.multiple = true
|
||||||
new App.UserOrganizationAutocompletion(attribute: attribute, params: params).element()
|
new App.UserOrganizationAutocompletion(attribute: attribute, params: params).element()
|
||||||
|
|
|
@ -27,7 +27,7 @@ class Overview extends App.ControllerSubContent
|
||||||
{ name: __('New Overview'), 'data-type': 'new', class: 'btn--success' }
|
{ name: __('New Overview'), 'data-type': 'new', class: 'btn--success' }
|
||||||
]
|
]
|
||||||
container: @el.closest('.content')
|
container: @el.closest('.content')
|
||||||
large: true
|
veryLarge: true
|
||||||
dndCallback: (e, item) =>
|
dndCallback: (e, item) =>
|
||||||
items = @el.find('table > tbody > tr')
|
items = @el.find('table > tbody > tr')
|
||||||
prios = []
|
prios = []
|
||||||
|
|
|
@ -80,10 +80,9 @@ class App.ObjectOrganizationAutocompletion extends App.Controller
|
||||||
|
|
||||||
onBlur: =>
|
onBlur: =>
|
||||||
selectObject = @objectSelect.val()
|
selectObject = @objectSelect.val()
|
||||||
if _.isEmpty(selectObject)
|
if _.isEmpty(selectObject) && !@attribute.multiple
|
||||||
@objectId.val('')
|
@objectId.val('')
|
||||||
return
|
else if @attribute.guess is true
|
||||||
if @attribute.guess is true
|
|
||||||
currentObjectId = @objectId.val()
|
currentObjectId = @objectId.val()
|
||||||
if _.isEmpty(currentObjectId) || currentObjectId.match(/^guess:/)
|
if _.isEmpty(currentObjectId) || currentObjectId.match(/^guess:/)
|
||||||
if !_.isEmpty(selectObject)
|
if !_.isEmpty(selectObject)
|
||||||
|
@ -95,31 +94,28 @@ class App.ObjectOrganizationAutocompletion extends App.Controller
|
||||||
|
|
||||||
onObjectClick: (e) =>
|
onObjectClick: (e) =>
|
||||||
objectId = $(e.currentTarget).data('object-id')
|
objectId = $(e.currentTarget).data('object-id')
|
||||||
@selectObject(objectId)
|
objectName = $(e.currentTarget).find('.recipientList-name').text().trim()
|
||||||
|
@selectObject(objectId, objectName)
|
||||||
@close()
|
@close()
|
||||||
|
|
||||||
selectObject: (objectId) =>
|
selectObject: (objectId, objectName) =>
|
||||||
if @attribute.multiple and @objectId.val()
|
if @attribute.multiple
|
||||||
# add objectId to end of comma separated list
|
@addValueToObjectInput(objectName, objectId)
|
||||||
objectId = _.chain( @objectId.val().split(',') ).push(objectId).join(',').value()
|
else
|
||||||
|
|
||||||
@objectSelect.val('')
|
@objectSelect.val('')
|
||||||
@objectId.val(objectId).trigger('change')
|
@objectId.val(objectId).trigger('change')
|
||||||
|
|
||||||
executeCallback: =>
|
executeCallback: =>
|
||||||
# with @attribute.multiple this can be several objects ids.
|
if @attribute.multiple
|
||||||
# Only work with the last one since its the newest one
|
# create token
|
||||||
objectId = @objectId.val().split(',').pop()
|
@createToken(@currentObject) if @currentObject
|
||||||
|
@currentObject = null
|
||||||
|
|
||||||
|
else
|
||||||
|
objectId = @objectId.val()
|
||||||
if objectId && App[@objectSingle].exists(objectId)
|
if objectId && App[@objectSingle].exists(objectId)
|
||||||
object = App[@objectSingle].find(objectId)
|
object = App[@objectSingle].find(objectId)
|
||||||
name = object.displayName()
|
name = object.displayName()
|
||||||
|
|
||||||
if @attribute.multiple
|
|
||||||
|
|
||||||
# create token
|
|
||||||
@createToken(name, objectId)
|
|
||||||
else
|
|
||||||
if object.email
|
if object.email
|
||||||
|
|
||||||
# quote name for special character
|
# quote name for special character
|
||||||
|
@ -132,10 +128,10 @@ class App.ObjectOrganizationAutocompletion extends App.Controller
|
||||||
if @callback
|
if @callback
|
||||||
@callback(objectId)
|
@callback(objectId)
|
||||||
|
|
||||||
createToken: (name, objectId) =>
|
createToken: ({name, value}) =>
|
||||||
@objectSelect.before App.view('generic/token')(
|
@objectSelect.before App.view('generic/token')(
|
||||||
name: name
|
name: name
|
||||||
value: objectId
|
value: value
|
||||||
)
|
)
|
||||||
|
|
||||||
removeThisToken: (e) =>
|
removeThisToken: (e) =>
|
||||||
|
@ -149,12 +145,9 @@ class App.ObjectOrganizationAutocompletion extends App.Controller
|
||||||
else
|
else
|
||||||
token = which
|
token = which
|
||||||
|
|
||||||
# remove objectId from input
|
id = token.data('value')
|
||||||
index = @$('.token').index(token)
|
@objectId.find("[value=#{id}]").remove()
|
||||||
ids = @objectId.val().split(',')
|
@objectId.trigger('change')
|
||||||
ids.splice(index, 1)
|
|
||||||
@objectId.val ids.join(',')
|
|
||||||
|
|
||||||
token.remove()
|
token.remove()
|
||||||
|
|
||||||
navigateByKeyboard: (e) =>
|
navigateByKeyboard: (e) =>
|
||||||
|
@ -170,7 +163,7 @@ class App.ObjectOrganizationAutocompletion extends App.Controller
|
||||||
@objectSelect.val('').trigger('change')
|
@objectSelect.val('').trigger('change')
|
||||||
# remove last token on backspace
|
# remove last token on backspace
|
||||||
when 8
|
when 8
|
||||||
if @objectSelect.val() is ''
|
if @objectSelect.val() is '' && @objectSelect.is(e.target)
|
||||||
@removeToken('last')
|
@removeToken('last')
|
||||||
# close on tab
|
# close on tab
|
||||||
when 9 then @close()
|
when 9 then @close()
|
||||||
|
@ -223,7 +216,8 @@ class App.ObjectOrganizationAutocompletion extends App.Controller
|
||||||
return
|
return
|
||||||
objectId = recipientListOrganizationMembers.find('li.is-active').data('object-id')
|
objectId = recipientListOrganizationMembers.find('li.is-active').data('object-id')
|
||||||
return if !objectId
|
return if !objectId
|
||||||
@selectObject(objectId)
|
objectName = recipientListOrganizationMembers.find('li.is-active .recipientList-name').text().trim()
|
||||||
|
@selectObject(objectId, objectName)
|
||||||
@close() if !@attribute.multiple
|
@close() if !@attribute.multiple
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -233,7 +227,8 @@ class App.ObjectOrganizationAutocompletion extends App.Controller
|
||||||
if objectId is 'new'
|
if objectId is 'new'
|
||||||
@newObject()
|
@newObject()
|
||||||
else
|
else
|
||||||
@selectObject(objectId)
|
objectName = @recipientList.find('li.is-active .recipientList-name').text().trim()
|
||||||
|
@selectObject(objectId, objectName)
|
||||||
@close() if !@attribute.multiple
|
@close() if !@attribute.multiple
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -242,6 +237,14 @@ class App.ObjectOrganizationAutocompletion extends App.Controller
|
||||||
@showOrganizationMembers(undefined, @recipientList.find('li.is-active'))
|
@showOrganizationMembers(undefined, @recipientList.find('li.is-active'))
|
||||||
|
|
||||||
|
|
||||||
|
addValueToObjectInput: (objectName, objectId) ->
|
||||||
|
@objectSelect.val('')
|
||||||
|
@currentObject = {name: objectName, value: objectId}
|
||||||
|
if @objectId.val()
|
||||||
|
return if @objectId.val().includes("#{objectId}") # cast objectId to string before check
|
||||||
|
@objectId.append("<option value=#{App.Utils.htmlEscape(@currentObject.value)} selected>#{App.Utils.htmlEscape(@currentObject.name)}</option>")
|
||||||
|
@objectId.trigger('change')
|
||||||
|
|
||||||
buildOrganizationItem: (organization) ->
|
buildOrganizationItem: (organization) ->
|
||||||
objectCount = 0
|
objectCount = 0
|
||||||
if organization[@referenceAttribute]
|
if organization[@referenceAttribute]
|
||||||
|
@ -315,17 +318,23 @@ class App.ObjectOrganizationAutocompletion extends App.Controller
|
||||||
# fallback for if the value is not an array
|
# fallback for if the value is not an array
|
||||||
if typeof @attribute.value isnt 'object'
|
if typeof @attribute.value isnt 'object'
|
||||||
@attribute.value = [@attribute.value]
|
@attribute.value = [@attribute.value]
|
||||||
value = @attribute.value.join ','
|
|
||||||
|
|
||||||
# create tokens
|
# create tokens and attribute values
|
||||||
|
values = []
|
||||||
for objectId in @attribute.value
|
for objectId in @attribute.value
|
||||||
if App[@objectSingle].exists objectId
|
if App[@objectSingle].exists objectId
|
||||||
|
objectName = App[@objectSingle].find(objectId).displayName()
|
||||||
|
objectValue = objectId
|
||||||
|
values.push({name: objectName, value: objectValue})
|
||||||
tokens += App.view('generic/token')(
|
tokens += App.view('generic/token')(
|
||||||
name: App[@objectSingle].find(objectId).displayName()
|
name: objectName
|
||||||
value: objectId
|
value: objectValue
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
@log 'objectId doesn\'t exist', objectId
|
@log 'objectId doesn\'t exist', objectId
|
||||||
|
|
||||||
|
@attribute.value = values
|
||||||
|
|
||||||
else
|
else
|
||||||
value = @attribute.value
|
value = @attribute.value
|
||||||
if value
|
if value
|
||||||
|
@ -369,7 +378,7 @@ class App.ObjectOrganizationAutocompletion extends App.Controller
|
||||||
@recipientList.append(@buildObjectNew())
|
@recipientList.append(@buildObjectNew())
|
||||||
|
|
||||||
# reset object selection
|
# reset object selection
|
||||||
@resetObjectSelection()
|
@resetObjectSelection() if !@attribute.multiple
|
||||||
return
|
return
|
||||||
|
|
||||||
# show dropdown
|
# show dropdown
|
||||||
|
|
|
@ -15,6 +15,7 @@ class App.SearchableSelect extends Spine.Controller
|
||||||
'shown.bs.dropdown': 'onDropdownShown'
|
'shown.bs.dropdown': 'onDropdownShown'
|
||||||
'hidden.bs.dropdown': 'onDropdownHidden'
|
'hidden.bs.dropdown': 'onDropdownHidden'
|
||||||
'keyup .js-input': 'onKeyUp'
|
'keyup .js-input': 'onKeyUp'
|
||||||
|
'click .js-remove': 'removeThisToken'
|
||||||
|
|
||||||
elements:
|
elements:
|
||||||
'.js-dropdown': 'dropdown'
|
'.js-dropdown': 'dropdown'
|
||||||
|
@ -38,10 +39,33 @@ class App.SearchableSelect extends Spine.Controller
|
||||||
render: ->
|
render: ->
|
||||||
@updateAttributeValueName()
|
@updateAttributeValueName()
|
||||||
|
|
||||||
|
tokens = ''
|
||||||
|
if @attribute.multiple && @attribute.value
|
||||||
|
object = @attribute.object
|
||||||
|
|
||||||
|
# fallback for if the value is not an array
|
||||||
|
if typeof @attribute.value isnt 'object'
|
||||||
|
@attribute.value = [@attribute.value]
|
||||||
|
|
||||||
|
# create tokens and attribute values
|
||||||
|
values = []
|
||||||
|
for dataId in @attribute.value
|
||||||
|
if App[object].exists dataId
|
||||||
|
name = App[object].find(dataId).displayName()
|
||||||
|
value = dataId
|
||||||
|
values.push({name: name, value: value})
|
||||||
|
tokens += App.view('generic/token')(
|
||||||
|
name: name
|
||||||
|
value: value
|
||||||
|
)
|
||||||
|
|
||||||
|
@attribute.value = values
|
||||||
|
|
||||||
@html App.view('generic/searchable_select')
|
@html App.view('generic/searchable_select')
|
||||||
attribute: @attribute
|
attribute: @attribute
|
||||||
options: @renderAllOptions('', @attribute.options, 0)
|
options: @renderAllOptions('', @attribute.options, 0)
|
||||||
submenus: @renderSubmenus(@attribute.options)
|
submenus: @renderSubmenus(@attribute.options)
|
||||||
|
tokens: tokens
|
||||||
|
|
||||||
# initial data
|
# initial data
|
||||||
@currentMenu = @findMenuContainingValue(@attribute.value)
|
@currentMenu = @findMenuContainingValue(@attribute.value)
|
||||||
|
@ -133,12 +157,12 @@ class App.SearchableSelect extends Spine.Controller
|
||||||
@unhighlightCurrentItem()
|
@unhighlightCurrentItem()
|
||||||
@isOpen = false
|
@isOpen = false
|
||||||
|
|
||||||
if !@input.val()
|
if !@input.val() && !@attribute.multiple
|
||||||
@updateAttributeValueName()
|
@updateAttributeValueName()
|
||||||
@input.val(@attribute.valueName)
|
@input.val(@attribute.valueName)
|
||||||
|
|
||||||
onKeyUp: =>
|
onKeyUp: =>
|
||||||
return if @input.val().trim() isnt ''
|
return if @input.val().trim() isnt '' || @attribute.multiple
|
||||||
@shadowInput.val('')
|
@shadowInput.val('')
|
||||||
|
|
||||||
toggle: =>
|
toggle: =>
|
||||||
|
@ -157,6 +181,9 @@ class App.SearchableSelect extends Spine.Controller
|
||||||
when 13 then @onEnter(event)
|
when 13 then @onEnter(event)
|
||||||
when 27 then @onEscape(event)
|
when 27 then @onEscape(event)
|
||||||
when 9 then @onTab(event)
|
when 9 then @onTab(event)
|
||||||
|
when 8 # remove last token on backspace
|
||||||
|
if @input.val() is '' && @input.is(event.target) && @attribute.multiple
|
||||||
|
@removeToken('last')
|
||||||
|
|
||||||
onEscape: ->
|
onEscape: ->
|
||||||
if @isOpen
|
if @isOpen
|
||||||
|
@ -192,7 +219,7 @@ class App.SearchableSelect extends Spine.Controller
|
||||||
@clearAutocomplete()
|
@clearAutocomplete()
|
||||||
|
|
||||||
autocompleteOrNavigateIn: (event) ->
|
autocompleteOrNavigateIn: (event) ->
|
||||||
if @currentItem.hasClass('js-enter')
|
if @currentItem && @currentItem.hasClass('js-enter')
|
||||||
@navigateIn(event)
|
@navigateIn(event)
|
||||||
else
|
else
|
||||||
@fillWithAutocompleteSuggestion(event)
|
@fillWithAutocompleteSuggestion(event)
|
||||||
|
@ -215,6 +242,9 @@ class App.SearchableSelect extends Spine.Controller
|
||||||
# current position
|
# current position
|
||||||
caretPosition = @invisiblePart.text().length + 1
|
caretPosition = @invisiblePart.text().length + 1
|
||||||
|
|
||||||
|
if @attribute.multiple
|
||||||
|
@addValueToShadowInput(@suggestion, @suggestionValue)
|
||||||
|
else
|
||||||
@input.val(@suggestion)
|
@input.val(@suggestion)
|
||||||
@shadowInput.val(@suggestionValue)
|
@shadowInput.val(@suggestionValue)
|
||||||
@clearAutocomplete()
|
@clearAutocomplete()
|
||||||
|
@ -242,9 +272,14 @@ class App.SearchableSelect extends Spine.Controller
|
||||||
selectItem: (event) ->
|
selectItem: (event) ->
|
||||||
currentText = event.currentTarget.querySelector('span.searchableSelect-option-text').textContent.trim()
|
currentText = event.currentTarget.querySelector('span.searchableSelect-option-text').textContent.trim()
|
||||||
return if !currentText
|
return if !currentText
|
||||||
|
|
||||||
|
dataId = event.currentTarget.getAttribute('data-value')
|
||||||
|
if @attribute.multiple
|
||||||
|
@addValueToShadowInput(currentText, dataId)
|
||||||
|
else
|
||||||
@input.val currentText
|
@input.val currentText
|
||||||
@input.trigger('change')
|
@input.trigger('change')
|
||||||
@shadowInput.val event.currentTarget.getAttribute('data-value')
|
@shadowInput.val dataId
|
||||||
@shadowInput.trigger('change')
|
@shadowInput.trigger('change')
|
||||||
|
|
||||||
navigateIn: (event) ->
|
navigateIn: (event) ->
|
||||||
|
@ -354,11 +389,14 @@ class App.SearchableSelect extends Spine.Controller
|
||||||
if @currentItem || !@attribute.unknown
|
if @currentItem || !@attribute.unknown
|
||||||
valueName = @currentItem.children('span.searchableSelect-option-text').text().trim()
|
valueName = @currentItem.children('span.searchableSelect-option-text').text().trim()
|
||||||
value = @currentItem.attr('data-value')
|
value = @currentItem.attr('data-value')
|
||||||
|
if @attribute.multiple
|
||||||
|
@addValueToShadowInput(valueName, value)
|
||||||
|
else
|
||||||
@input.val valueName
|
@input.val valueName
|
||||||
@shadowInput.val value
|
@shadowInput.val value
|
||||||
|
@shadowInput.trigger('change')
|
||||||
|
|
||||||
@input.trigger('change')
|
@input.trigger('change')
|
||||||
@shadowInput.trigger('change')
|
|
||||||
|
|
||||||
if @currentItem
|
if @currentItem
|
||||||
if @currentItem.hasClass('js-enter')
|
if @currentItem.hasClass('js-enter')
|
||||||
|
@ -386,17 +424,44 @@ class App.SearchableSelect extends Spine.Controller
|
||||||
onShadowChange: ->
|
onShadowChange: ->
|
||||||
value = @shadowInput.val()
|
value = @shadowInput.val()
|
||||||
|
|
||||||
|
if @attribute.multiple and @currentData
|
||||||
|
# create token
|
||||||
|
@createToken(@currentData)
|
||||||
|
@currentData = null
|
||||||
|
|
||||||
if Array.isArray(@attribute.options)
|
if Array.isArray(@attribute.options)
|
||||||
for option in @attribute.options
|
for option in @attribute.options
|
||||||
option.selected = (option.value + '') == value # makes sure option value is always a string
|
option.selected = (option.value + '') == value # makes sure option value is always a string
|
||||||
|
|
||||||
|
createToken: ({name, value}) =>
|
||||||
|
@input.before App.view('generic/token')(
|
||||||
|
name: name
|
||||||
|
value: value
|
||||||
|
)
|
||||||
|
|
||||||
|
removeThisToken: (e) =>
|
||||||
|
@removeToken $(e.currentTarget).parents('.token')
|
||||||
|
|
||||||
|
removeToken: (which) =>
|
||||||
|
switch which
|
||||||
|
when 'last'
|
||||||
|
token = @$('.token').last()
|
||||||
|
return if not token.size()
|
||||||
|
else
|
||||||
|
token = which
|
||||||
|
|
||||||
|
id = token.data('value')
|
||||||
|
@shadowInput.find("[value=#{id}]").remove()
|
||||||
|
@shadowInput.trigger('change')
|
||||||
|
token.remove()
|
||||||
|
|
||||||
onInput: (event) =>
|
onInput: (event) =>
|
||||||
@toggle() if not @isOpen
|
@toggle() if not @isOpen
|
||||||
|
|
||||||
@query = @input.val()
|
@query = @input.val()
|
||||||
@filterByQuery @query
|
@filterByQuery @query
|
||||||
|
|
||||||
if @attribute.unknown
|
if @attribute.unknown && !@attribute.multiple
|
||||||
@shadowInput.val @query
|
@shadowInput.val @query
|
||||||
|
|
||||||
filterByQuery: (query) ->
|
filterByQuery: (query) ->
|
||||||
|
@ -422,6 +487,14 @@ class App.SearchableSelect extends Spine.Controller
|
||||||
else
|
else
|
||||||
@highlightFirst(true)
|
@highlightFirst(true)
|
||||||
|
|
||||||
|
addValueToShadowInput: (currentText, dataId) ->
|
||||||
|
@input.val('')
|
||||||
|
@currentData = {name: currentText, value: dataId}
|
||||||
|
if @shadowInput.val()
|
||||||
|
return if @shadowInput.val().includes("#{dataId}") # cast dataId to string before check
|
||||||
|
@shadowInput.append($('<option/>').attr('selected', true).attr('value', @currentData.value).text(@currentData.name))
|
||||||
|
@shadowInput.trigger('change')
|
||||||
|
|
||||||
highlightFirst: (autocomplete) ->
|
highlightFirst: (autocomplete) ->
|
||||||
@unhighlightCurrentItem()
|
@unhighlightCurrentItem()
|
||||||
@currentItem = @getCurrentOptions().not('.is-hidden').first()
|
@currentItem = @getCurrentOptions().not('.is-hidden').first()
|
||||||
|
|
|
@ -1,9 +1,17 @@
|
||||||
<div class="tokenfield form-control u-positionOrigin">
|
<div class="tokenfield form-control u-positionOrigin">
|
||||||
<input class="js-objectId" type="hidden" value="<%= @value %>" name="<%- @attribute.name %>" tabindex="-1">
|
|
||||||
<% if @attribute.multiple: %>
|
<% if @attribute.multiple: %>
|
||||||
<%- @tokens %>
|
<select multiple class="js-objectId hide" name="<%= @attribute.name %>" tabindex="-1">
|
||||||
|
<% if @attribute.value: %>
|
||||||
|
<% for option in @attribute.value: %>
|
||||||
|
<option value="<%= option.value %>" selected><%= option.name %></option>
|
||||||
<% end %>
|
<% end %>
|
||||||
<input name="<%- @attribute.name %>_completion" class="user-select token-input js-objectSelect" autocapitalize="off" placeholder="<%- @Ti(@attribute.placeholder) %>" autocomplete="off" <%= @attribute.autofocus %> role="textbox" aria-autocomplete="list" value="<%= @name %>" aria-haspopup="true">
|
<% end %>
|
||||||
|
</select>
|
||||||
|
<%- @tokens %>
|
||||||
|
<% else: %>
|
||||||
|
<input class="js-objectId" type="hidden" value="<%= @value %>" name="<%= @attribute.name %>" tabindex="-1">
|
||||||
|
<% end %>
|
||||||
|
<input name="<%= @attribute.name %>_completion" class="user-select token-input js-objectSelect" autocapitalize="off" placeholder="<%- @Ti(@attribute.placeholder) %>" autocomplete="off" <%= @attribute.autofocus %> role="textbox" aria-autocomplete="list" value="<%= @name %>" aria-haspopup="true">
|
||||||
<% if @attribute.disableCreateObject isnt true: %><%- @Icon('arrow-down', 'dropdown-arrow') %><% end %>
|
<% if @attribute.disableCreateObject isnt true: %><%- @Icon('arrow-down', 'dropdown-arrow') %><% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,23 @@
|
||||||
<div class="dropdown-toggle" data-toggle="dropdown">
|
<div class="dropdown-toggle<%=" tokenfield form-control" if @attribute.multiple %>" data-toggle="dropdown">
|
||||||
|
<% if @attribute.multiple: %>
|
||||||
|
<select multiple class="js-shadow hide" name="<%- @attribute.name %>" tabindex="-1">
|
||||||
|
<% if @attribute.value: %>
|
||||||
|
<% for option in @attribute.value: %>
|
||||||
|
<option value="<%= option.value %>" selected><%= option.name %></option>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
</select>
|
||||||
|
<%- @tokens %>
|
||||||
|
<input
|
||||||
|
class="searchableSelect-main token-input form-control js-input<%= " #{ @attribute.class }" if @attribute.class %>"
|
||||||
|
placeholder="<%= @attribute.placeholder %>"
|
||||||
|
value
|
||||||
|
name="<%- @attribute.name %>_completion"
|
||||||
|
autocomplete="off"
|
||||||
|
<%= @attribute.required %>
|
||||||
|
<% if @attribute.disabled: %> disabled<% end %>
|
||||||
|
>
|
||||||
|
<% else: %>
|
||||||
<input
|
<input
|
||||||
class="searchableSelect-shadow form-control js-shadow"
|
class="searchableSelect-shadow form-control js-shadow"
|
||||||
<% if @attribute.id: %>id="<%= @attribute.id %>"<% end %>
|
<% if @attribute.id: %>id="<%= @attribute.id %>"<% end %>
|
||||||
|
@ -17,6 +36,7 @@
|
||||||
<%= @attribute.required %>
|
<%= @attribute.required %>
|
||||||
<% if @attribute.disabled: %> disabled<% end %>
|
<% if @attribute.disabled: %> disabled<% end %>
|
||||||
>
|
>
|
||||||
|
<% end %>
|
||||||
<div class="searchableSelect-autocomplete">
|
<div class="searchableSelect-autocomplete">
|
||||||
<span class="searchableSelect-autocomplete-invisible js-autocomplete-invisible"></span>
|
<span class="searchableSelect-autocomplete-invisible js-autocomplete-invisible"></span>
|
||||||
<span class="searchableSelect-autocomplete-visible js-autocomplete-visible"></span>
|
<span class="searchableSelect-autocomplete-visible js-autocomplete-visible"></span>
|
||||||
|
|
|
@ -531,17 +531,18 @@ QUnit.test('form checks', assert => {
|
||||||
operator: 'is not',
|
operator: 'is not',
|
||||||
pre_condition: 'specific',
|
pre_condition: 'specific',
|
||||||
value: '12',
|
value: '12',
|
||||||
|
value_completion: '',
|
||||||
},
|
},
|
||||||
'ticket.owner_id': {
|
'ticket.owner_id': {
|
||||||
operator: 'is',
|
operator: 'is',
|
||||||
pre_condition: 'specific',
|
pre_condition: 'specific',
|
||||||
value: '47',
|
value: '47',
|
||||||
value_completion: 'Bob Smith <bod@example.com>',
|
value_completion: '',
|
||||||
},
|
},
|
||||||
'ticket.created_by_id': {
|
'ticket.created_by_id': {
|
||||||
operator: 'is',
|
operator: 'is',
|
||||||
pre_condition: 'current_user.id',
|
pre_condition: 'current_user.id',
|
||||||
value: '',
|
value: null,
|
||||||
value_completion: ''
|
value_completion: ''
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -552,7 +553,7 @@ QUnit.test('form checks', assert => {
|
||||||
'ticket.owner_id': {
|
'ticket.owner_id': {
|
||||||
pre_condition: 'specific',
|
pre_condition: 'specific',
|
||||||
value: '47',
|
value: '47',
|
||||||
value_completion: 'Bob Smith <bod@example.com>'
|
value_completion: ''
|
||||||
},
|
},
|
||||||
'ticket.priority_id': {
|
'ticket.priority_id': {
|
||||||
value: '3',
|
value: '3',
|
||||||
|
@ -596,17 +597,18 @@ QUnit.test('form checks', assert => {
|
||||||
operator: 'is not',
|
operator: 'is not',
|
||||||
pre_condition: 'specific',
|
pre_condition: 'specific',
|
||||||
value: '12',
|
value: '12',
|
||||||
|
value_completion: '',
|
||||||
},
|
},
|
||||||
'ticket.owner_id': {
|
'ticket.owner_id': {
|
||||||
operator: 'is',
|
operator: 'is',
|
||||||
pre_condition: 'specific',
|
pre_condition: 'specific',
|
||||||
value: '47',
|
value: '47',
|
||||||
value_completion: 'Bob Smith <bod@example.com>',
|
value_completion: '',
|
||||||
},
|
},
|
||||||
'ticket.created_by_id': {
|
'ticket.created_by_id': {
|
||||||
operator: 'is',
|
operator: 'is',
|
||||||
pre_condition: 'current_user.id',
|
pre_condition: 'current_user.id',
|
||||||
value: '',
|
value: null,
|
||||||
value_completion: ''
|
value_completion: ''
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -617,7 +619,7 @@ QUnit.test('form checks', assert => {
|
||||||
'ticket.owner_id': {
|
'ticket.owner_id': {
|
||||||
pre_condition: 'specific',
|
pre_condition: 'specific',
|
||||||
value: '47',
|
value: '47',
|
||||||
value_completion: 'Bob Smith <bod@example.com>'
|
value_completion: ''
|
||||||
},
|
},
|
||||||
'ticket.tags': {
|
'ticket.tags': {
|
||||||
operator: 'remove',
|
operator: 'remove',
|
||||||
|
@ -657,17 +659,18 @@ QUnit.test('form checks', assert => {
|
||||||
operator: 'is not',
|
operator: 'is not',
|
||||||
pre_condition: 'specific',
|
pre_condition: 'specific',
|
||||||
value: '12',
|
value: '12',
|
||||||
|
value_completion: '',
|
||||||
},
|
},
|
||||||
'ticket.owner_id': {
|
'ticket.owner_id': {
|
||||||
operator: 'is',
|
operator: 'is',
|
||||||
pre_condition: 'specific',
|
pre_condition: 'specific',
|
||||||
value: '47',
|
value: '47',
|
||||||
value_completion: 'Bob Smith <bod@example.com>',
|
value_completion: '',
|
||||||
},
|
},
|
||||||
'ticket.created_by_id': {
|
'ticket.created_by_id': {
|
||||||
operator: 'is',
|
operator: 'is',
|
||||||
pre_condition: 'current_user.id',
|
pre_condition: 'current_user.id',
|
||||||
value: '',
|
value: null,
|
||||||
value_completion: ''
|
value_completion: ''
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -678,7 +681,7 @@ QUnit.test('form checks', assert => {
|
||||||
'ticket.owner_id': {
|
'ticket.owner_id': {
|
||||||
pre_condition: 'specific',
|
pre_condition: 'specific',
|
||||||
value: '47',
|
value: '47',
|
||||||
value_completion: 'Bob Smith <bod@example.com>'
|
value_completion: ''
|
||||||
},
|
},
|
||||||
'ticket.tags': {
|
'ticket.tags': {
|
||||||
operator: 'remove',
|
operator: 'remove',
|
||||||
|
@ -714,17 +717,18 @@ QUnit.test('form checks', assert => {
|
||||||
operator: 'is not',
|
operator: 'is not',
|
||||||
pre_condition: 'specific',
|
pre_condition: 'specific',
|
||||||
value: '12',
|
value: '12',
|
||||||
|
value_completion: '',
|
||||||
},
|
},
|
||||||
'ticket.owner_id': {
|
'ticket.owner_id': {
|
||||||
operator: 'is',
|
operator: 'is',
|
||||||
pre_condition: 'specific',
|
pre_condition: 'specific',
|
||||||
value: '47',
|
value: '47',
|
||||||
value_completion: 'Bob Smith <bod@example.com>',
|
value_completion: '',
|
||||||
},
|
},
|
||||||
'ticket.created_by_id': {
|
'ticket.created_by_id': {
|
||||||
operator: 'is',
|
operator: 'is',
|
||||||
pre_condition: 'current_user.id',
|
pre_condition: 'current_user.id',
|
||||||
value: '',
|
value: null,
|
||||||
value_completion: ''
|
value_completion: ''
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -735,7 +739,7 @@ QUnit.test('form checks', assert => {
|
||||||
'ticket.owner_id': {
|
'ticket.owner_id': {
|
||||||
pre_condition: 'specific',
|
pre_condition: 'specific',
|
||||||
value: '47',
|
value: '47',
|
||||||
value_completion: 'Bob Smith <bod@example.com>'
|
value_completion: ''
|
||||||
},
|
},
|
||||||
'notification.email': {
|
'notification.email': {
|
||||||
recipient: 'ticket_owner',
|
recipient: 'ticket_owner',
|
||||||
|
@ -849,4 +853,167 @@ QUnit.test('form checks', assert => {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
assert.deepEqual(params, test_params, 'form article body param check')
|
assert.deepEqual(params, test_params, 'form article body param check')
|
||||||
|
|
||||||
|
App.User.refresh([
|
||||||
|
{
|
||||||
|
id: 44,
|
||||||
|
login: 'bod@example.com',
|
||||||
|
email: 'bod@example.com',
|
||||||
|
firstname: 'Bob',
|
||||||
|
lastname: 'Smith',
|
||||||
|
active: true,
|
||||||
|
created_at: '2014-06-10T11:17:34.000Z',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 45,
|
||||||
|
login: 'john@example.com',
|
||||||
|
email: 'john@example.com',
|
||||||
|
firstname: 'John',
|
||||||
|
lastname: 'Doe',
|
||||||
|
active: true,
|
||||||
|
created_at: '2014-07-10T11:17:34.000Z',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 46,
|
||||||
|
login: 'sam@example.com',
|
||||||
|
email: 'sam@example.com',
|
||||||
|
firstname: 'Sam',
|
||||||
|
lastname: 'Bond',
|
||||||
|
active: true,
|
||||||
|
created_at: '2014-08-10T11:17:34.000Z',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 30,
|
||||||
|
login: 'clark@example.com',
|
||||||
|
email: 'clark@example.com',
|
||||||
|
firstname: 'Clark',
|
||||||
|
lastname: 'Olsen',
|
||||||
|
active: true,
|
||||||
|
created_at: '2016-02-10T11:17:34.000Z',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 31,
|
||||||
|
login: 'james@example.com',
|
||||||
|
email: 'james@example.com',
|
||||||
|
firstname: 'James',
|
||||||
|
lastname: 'Puth',
|
||||||
|
active: true,
|
||||||
|
created_at: '2016-03-10T11:17:34.000Z',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 32,
|
||||||
|
login: 'charles@example.com',
|
||||||
|
email: 'charles@example.com',
|
||||||
|
firstname: 'Charles',
|
||||||
|
lastname: 'Kent',
|
||||||
|
active: true,
|
||||||
|
created_at: '2016-04-10T11:17:34.000Z',
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
App.Organization.refresh([
|
||||||
|
{
|
||||||
|
id: 9,
|
||||||
|
name: 'Org 1',
|
||||||
|
active: true,
|
||||||
|
created_at: '2018-06-10T11:19:34.000Z',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 10,
|
||||||
|
name: 'Org 2',
|
||||||
|
active: true,
|
||||||
|
created_at: '2018-06-10T11:19:34.000Z',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 11,
|
||||||
|
name: 'Org 3',
|
||||||
|
active: true,
|
||||||
|
created_at: '2018-06-10T11:19:34.000Z',
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
/* with params or defaults */
|
||||||
|
$('#forms').append('<hr><h1>form condition check for multiple user and organisation selection</h1><form id="form6"></form>')
|
||||||
|
var el = $('#form6')
|
||||||
|
var defaults = {
|
||||||
|
condition: {
|
||||||
|
'ticket.title': {
|
||||||
|
operator: 'contains',
|
||||||
|
value: 'some title',
|
||||||
|
},
|
||||||
|
'ticket.organization_id': {
|
||||||
|
operator: 'is',
|
||||||
|
pre_condition: 'specific',
|
||||||
|
value: [9, 10, 11],
|
||||||
|
},
|
||||||
|
'ticket.owner_id': {
|
||||||
|
operator: 'is not',
|
||||||
|
pre_condition: 'specific',
|
||||||
|
value: [44, 45, 46],
|
||||||
|
},
|
||||||
|
'ticket.customer_id': {
|
||||||
|
operator: 'is',
|
||||||
|
pre_condition: 'specific',
|
||||||
|
value: [30, 31, 32],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
executions: {
|
||||||
|
'ticket.title': {
|
||||||
|
value: 'some title new',
|
||||||
|
},
|
||||||
|
'ticket.owner_id': {
|
||||||
|
pre_condition: 'specific',
|
||||||
|
value: [44, 46],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
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, notification: true },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
params: defaults,
|
||||||
|
autofocus: true
|
||||||
|
})
|
||||||
|
var params = App.ControllerForm.params(el)
|
||||||
|
var test_params = {
|
||||||
|
condition: {
|
||||||
|
'ticket.title': {
|
||||||
|
operator: 'contains',
|
||||||
|
value: 'some title',
|
||||||
|
},
|
||||||
|
'ticket.organization_id': {
|
||||||
|
operator: 'is',
|
||||||
|
pre_condition: 'specific',
|
||||||
|
value: ['9', '10', '11'],
|
||||||
|
value_completion: ''
|
||||||
|
},
|
||||||
|
'ticket.owner_id': {
|
||||||
|
operator: 'is not',
|
||||||
|
pre_condition: 'specific',
|
||||||
|
value: ['44', '45', '46'],
|
||||||
|
value_completion: ''
|
||||||
|
},
|
||||||
|
'ticket.customer_id': {
|
||||||
|
operator: 'is',
|
||||||
|
pre_condition: 'specific',
|
||||||
|
value: ['30', '31', '32'],
|
||||||
|
value_completion: ''
|
||||||
|
},
|
||||||
|
},
|
||||||
|
executions: {
|
||||||
|
'ticket.title': {
|
||||||
|
value: 'some title new',
|
||||||
|
},
|
||||||
|
'ticket.owner_id': {
|
||||||
|
pre_condition: 'specific',
|
||||||
|
value: ['44', '46'],
|
||||||
|
value_completion: ''
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.deepEqual(params, test_params, 'form param condition check for multiple users and organisation')
|
||||||
});
|
});
|
||||||
|
|
|
@ -595,7 +595,7 @@ QUnit.test( "ticket_perform_action check possible owner selection", assert => {
|
||||||
ticket_perform_action5: {
|
ticket_perform_action5: {
|
||||||
'ticket.owner_id': {
|
'ticket.owner_id': {
|
||||||
pre_condition: 'not_set',
|
pre_condition: 'not_set',
|
||||||
value: '',
|
value: null,
|
||||||
value_completion: ''
|
value_completion: ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -610,7 +610,7 @@ QUnit.test( "ticket_perform_action check possible owner selection", assert => {
|
||||||
ticket_perform_action5: {
|
ticket_perform_action5: {
|
||||||
'ticket.owner_id': {
|
'ticket.owner_id': {
|
||||||
pre_condition: 'specific',
|
pre_condition: 'specific',
|
||||||
value: '',
|
value: null,
|
||||||
value_completion: ''
|
value_completion: ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
370
spec/system/manage/overviews_spec.rb
Normal file
370
spec/system/manage/overviews_spec.rb
Normal file
|
@ -0,0 +1,370 @@
|
||||||
|
# Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe 'Manage > Overviews', type: :system do
|
||||||
|
let(:group) { create(:group) }
|
||||||
|
|
||||||
|
let(:owner_one) { create(:agent, groups: [group]) }
|
||||||
|
let(:owner_two) { create(:agent, groups: [group]) }
|
||||||
|
let(:owner_three) { create(:agent, groups: [group]) }
|
||||||
|
|
||||||
|
let(:customer_one) { create(:customer, organization_id: organization_one.id, groups: [group]) }
|
||||||
|
let(:customer_two) { create(:customer, organization_id: organization_two.id, groups: [group]) }
|
||||||
|
let(:customer_three) { create(:customer, organization_id: organization_three.id, groups: [group]) }
|
||||||
|
|
||||||
|
let(:organization_one) { create(:organization, name: 'Test Org One') }
|
||||||
|
let(:organization_two) { create(:organization, name: 'Test Org Two') }
|
||||||
|
let(:organization_three) { create(:organization, name: 'Test Org Three') }
|
||||||
|
|
||||||
|
let!(:ticket_one) do
|
||||||
|
create(:ticket,
|
||||||
|
title: 'Test Ticket One',
|
||||||
|
group: group,
|
||||||
|
owner_id: owner_one.id,
|
||||||
|
customer_id: customer_one.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
let!(:ticket_two) do
|
||||||
|
create(:ticket,
|
||||||
|
title: 'Test Ticket Two',
|
||||||
|
group: group,
|
||||||
|
owner_id: owner_two.id,
|
||||||
|
customer_id: customer_two.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
let!(:ticket_three) do
|
||||||
|
create(:ticket,
|
||||||
|
title: 'Test Ticket Three',
|
||||||
|
group: group,
|
||||||
|
owner_id: owner_three.id,
|
||||||
|
customer_id: customer_three.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:overview) { create(:overview, condition: condition) }
|
||||||
|
|
||||||
|
shared_examples 'previewing the correct ticket for single selected object' do
|
||||||
|
context "with 'is' operator" do
|
||||||
|
let(:operator) { 'is' }
|
||||||
|
|
||||||
|
it 'shows selected customer ticket' do
|
||||||
|
within '.js-preview .js-tableBody' do
|
||||||
|
expect(page).to have_selector('tr.item', text: ticket_one.title)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not show customer ticket that is not selected' do
|
||||||
|
within '.js-preview .js-tableBody' do
|
||||||
|
expect(page).to have_no_selector('tr.item', text: ticket_two.title)
|
||||||
|
expect(page).to have_no_selector('tr.item', text: ticket_three.title)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with 'is not' operator" do
|
||||||
|
let(:operator) { 'is not' }
|
||||||
|
|
||||||
|
it 'does not show selected customer ticket' do
|
||||||
|
within '.js-preview .js-tableBody' do
|
||||||
|
expect(page).to have_no_selector('tr.item', text: ticket_one.title)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not show customer ticket that is not selected' do
|
||||||
|
within '.js-preview .js-tableBody' do
|
||||||
|
expect(page).to have_selector('tr.item', text: ticket_two.title)
|
||||||
|
expect(page).to have_selector('tr.item', text: ticket_three.title)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
shared_examples 'previewing the correct ticket for multiple selected objects' do
|
||||||
|
context "with 'is' operator" do
|
||||||
|
let(:operator) { 'is' }
|
||||||
|
|
||||||
|
it 'shows selected customer ticket' do
|
||||||
|
within '.js-preview .js-tableBody' do
|
||||||
|
expect(page).to have_selector('tr.item', text: ticket_one.title)
|
||||||
|
expect(page).to have_selector('tr.item', text: ticket_two.title)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not show customer ticket that is not selected' do
|
||||||
|
within '.js-preview .js-tableBody' do
|
||||||
|
expect(page).to have_no_selector('tr.item', text: ticket_three.title)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with 'is not' operator" do
|
||||||
|
let(:operator) { 'is not' }
|
||||||
|
|
||||||
|
it 'does not show selected customer ticket' do
|
||||||
|
within '.js-preview .js-tableBody' do
|
||||||
|
expect(page).to have_no_selector('tr.item', text: ticket_one.title)
|
||||||
|
expect(page).to have_no_selector('tr.item', text: ticket_two.title)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not show customer ticket that is not selected' do
|
||||||
|
within '.js-preview .js-tableBody' do
|
||||||
|
expect(page).to have_selector('tr.item', text: ticket_three.title)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'conditions for shown tickets' do
|
||||||
|
context 'for customer' do
|
||||||
|
context 'for new overview' do
|
||||||
|
before do
|
||||||
|
visit '/#manage/overviews'
|
||||||
|
click_on 'New Overview'
|
||||||
|
|
||||||
|
modal_ready
|
||||||
|
|
||||||
|
within '.ticket_selector' do
|
||||||
|
ticket_select = find('.js-attributeSelector select .js-ticket')
|
||||||
|
ticket_select.select 'Customer'
|
||||||
|
select operator, from: 'condition::ticket.customer_id::operator'
|
||||||
|
select 'specific', from: 'condition::ticket.customer_id::pre_condition'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when single customer is selected' do
|
||||||
|
before do
|
||||||
|
within '.ticket_selector' do
|
||||||
|
fill_in 'condition::ticket.customer_id::value_completion', with: customer_one.firstname
|
||||||
|
|
||||||
|
find("[data-object-id='#{customer_one.id}'].js-object").click
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'previewing the correct ticket for single selected object'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when multiple customer is selected' do
|
||||||
|
before do
|
||||||
|
within '.ticket_selector' do
|
||||||
|
fill_in 'condition::ticket.customer_id::value_completion', with: customer_one.firstname
|
||||||
|
find("[data-object-id='#{customer_one.id}'].js-object").click
|
||||||
|
|
||||||
|
fill_in 'condition::ticket.customer_id::value_completion', with: customer_two.firstname
|
||||||
|
find("[data-object-id='#{customer_two.id}'].js-object").click
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'previewing the correct ticket for multiple selected objects'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'for existing overview' do
|
||||||
|
let(:condition) do
|
||||||
|
{ 'ticket.customer_id' => {
|
||||||
|
operator: operator,
|
||||||
|
pre_condition: 'specific',
|
||||||
|
value: condition_value
|
||||||
|
} }
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
overview
|
||||||
|
|
||||||
|
visit '/#manage/overviews'
|
||||||
|
|
||||||
|
within '.table-overview .js-tableBody' do
|
||||||
|
find("tr[data-id='#{overview.id}'] td.table-draggable").click
|
||||||
|
end
|
||||||
|
|
||||||
|
within '.ticket_selector' do
|
||||||
|
# trigger the preview
|
||||||
|
fill_in 'condition::ticket.customer_id::value_completion', with: customer_one.firstname
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when single customer exists' do
|
||||||
|
let(:condition_value) { customer_one.id }
|
||||||
|
|
||||||
|
it_behaves_like 'previewing the correct ticket for single selected object'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when multiple customer exists' do
|
||||||
|
let(:condition_value) { [customer_one.id, customer_two.id] }
|
||||||
|
|
||||||
|
it_behaves_like 'previewing the correct ticket for multiple selected objects'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'for owner' do
|
||||||
|
context 'for new overview' do
|
||||||
|
before do
|
||||||
|
visit '/#manage/overviews'
|
||||||
|
click_on 'New Overview'
|
||||||
|
|
||||||
|
modal_ready
|
||||||
|
|
||||||
|
within '.ticket_selector' do
|
||||||
|
ticket_select = find('.js-attributeSelector select .js-ticket')
|
||||||
|
ticket_select.select 'Owner'
|
||||||
|
select operator, from: 'condition::ticket.owner_id::operator'
|
||||||
|
select 'specific', from: 'condition::ticket.owner_id::pre_condition'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when single owner is selected' do
|
||||||
|
before do
|
||||||
|
within '.ticket_selector' do
|
||||||
|
fill_in 'condition::ticket.owner_id::value_completion', with: owner_one.firstname
|
||||||
|
|
||||||
|
first('.recipientList-entry.js-object').click
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'previewing the correct ticket for single selected object'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when multiple owner is selected' do
|
||||||
|
before do
|
||||||
|
within '.ticket_selector' do
|
||||||
|
fill_in 'condition::ticket.owner_id::value_completion', with: owner_one.firstname
|
||||||
|
find("[data-object-id='#{owner_one.id}'].js-object").click
|
||||||
|
|
||||||
|
fill_in 'condition::ticket.owner_id::value_completion', with: owner_two.firstname
|
||||||
|
find("[data-object-id='#{owner_two.id}'].js-object").click
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'previewing the correct ticket for multiple selected objects'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'for existing overview' do
|
||||||
|
let(:condition) do
|
||||||
|
{ 'ticket.owner_id' => {
|
||||||
|
operator: operator,
|
||||||
|
pre_condition: 'specific',
|
||||||
|
value: condition_value
|
||||||
|
} }
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
overview
|
||||||
|
|
||||||
|
visit '/#manage/overviews'
|
||||||
|
|
||||||
|
within '.table-overview .js-tableBody' do
|
||||||
|
find("tr[data-id='#{overview.id}'] td.table-draggable").click
|
||||||
|
end
|
||||||
|
|
||||||
|
within '.ticket_selector' do
|
||||||
|
# trigger the preview
|
||||||
|
fill_in 'condition::ticket.owner_id::value_completion', with: owner_one.firstname
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when single owner exists' do
|
||||||
|
let(:condition_value) { owner_one.id }
|
||||||
|
|
||||||
|
it_behaves_like 'previewing the correct ticket for single selected object'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when multiple owner exists' do
|
||||||
|
let(:condition_value) { [owner_one.id, owner_two.id] }
|
||||||
|
|
||||||
|
it_behaves_like 'previewing the correct ticket for multiple selected objects'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'for organization' do
|
||||||
|
# let(:condition) do
|
||||||
|
# { 'ticket.organization_id' => {
|
||||||
|
# operator: operator,
|
||||||
|
# pre_condition: 'specific',
|
||||||
|
# value: [101, 102, 103]
|
||||||
|
# } }
|
||||||
|
# end
|
||||||
|
|
||||||
|
context 'for new overview' do
|
||||||
|
before do
|
||||||
|
visit '/#manage/overviews'
|
||||||
|
click_on 'New Overview'
|
||||||
|
|
||||||
|
modal_ready
|
||||||
|
|
||||||
|
within '.ticket_selector' do
|
||||||
|
ticket_select = find('.js-attributeSelector select .js-ticket')
|
||||||
|
ticket_select.select 'Organization'
|
||||||
|
select operator, from: 'condition::ticket.organization_id::operator'
|
||||||
|
select 'specific', from: 'condition::ticket.organization_id::pre_condition'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when single organization is selected' do
|
||||||
|
before do
|
||||||
|
within '.ticket_selector' do
|
||||||
|
fill_in 'condition::ticket.organization_id::value_completion', with: organization_one.name
|
||||||
|
|
||||||
|
find(".js-optionsList [data-value='#{organization_one.id}'].js-option").click
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'previewing the correct ticket for single selected object'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when multiple organization is selected' do
|
||||||
|
before do
|
||||||
|
within '.ticket_selector' do
|
||||||
|
fill_in 'condition::ticket.organization_id::value_completion', with: organization_one.name
|
||||||
|
find(".js-optionsList [data-value='#{organization_one.id}'].js-option").click
|
||||||
|
|
||||||
|
fill_in 'condition::ticket.organization_id::value_completion', with: organization_two.name
|
||||||
|
find(".js-optionsList [data-value='#{organization_two.id}'].js-option").click
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'previewing the correct ticket for multiple selected objects'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'for existing overview' do
|
||||||
|
let(:condition) do
|
||||||
|
{ 'ticket.organization_id' => {
|
||||||
|
operator: operator,
|
||||||
|
pre_condition: 'specific',
|
||||||
|
value: condition_value
|
||||||
|
} }
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
overview
|
||||||
|
|
||||||
|
visit '/#manage/overviews'
|
||||||
|
|
||||||
|
within '.table-overview .js-tableBody' do
|
||||||
|
find("tr[data-id='#{overview.id}'] td.table-draggable").click
|
||||||
|
end
|
||||||
|
|
||||||
|
within '.ticket_selector' do
|
||||||
|
# trigger the preview
|
||||||
|
fill_in 'condition::ticket.organization_id::value_completion', with: organization_one.name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when single organization exists' do
|
||||||
|
let(:condition_value) { organization_one.id }
|
||||||
|
|
||||||
|
it_behaves_like 'previewing the correct ticket for single selected object'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when multiple organization exists' do
|
||||||
|
let(:condition_value) { [organization_one.id, organization_two.id] }
|
||||||
|
|
||||||
|
it_behaves_like 'previewing the correct ticket for multiple selected objects'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue