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:
Bola Ahmed Buari 2022-01-12 14:24:11 +01:00 committed by Rolf Schmidt
parent 50e3b98955
commit bf3067d908
11 changed files with 746 additions and 91 deletions

View file

@ -3,7 +3,7 @@ class App.UiElement.autocompletion_ajax
@render: (attribute, params = {}, form) ->
if 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
searchableAjaxSelectObject = new App.SearchableAjaxSelect(
@ -17,5 +17,6 @@ class App.UiElement.autocompletion_ajax
limit: 40
object: attribute.relation
ajax: true
multiple: attribute.multiple
)
searchableAjaxSelectObject.element()

View file

@ -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)

View file

@ -3,4 +3,5 @@ class App.UiElement.user_autocompletion_search
@render: (attributeOrig, params = {}) ->
attribute = _.clone(attributeOrig)
attribute.disableCreateObject = true
attribute.multiple = true
new App.UserOrganizationAutocompletion(attribute: attribute, params: params).element()

View file

@ -27,7 +27,7 @@ class Overview extends App.ControllerSubContent
{ name: __('New Overview'), 'data-type': 'new', class: 'btn--success' }
]
container: @el.closest('.content')
large: true
veryLarge: true
dndCallback: (e, item) =>
items = @el.find('table > tbody > tr')
prios = []

View file

@ -80,10 +80,9 @@ class App.ObjectOrganizationAutocompletion extends App.Controller
onBlur: =>
selectObject = @objectSelect.val()
if _.isEmpty(selectObject)
if _.isEmpty(selectObject) && !@attribute.multiple
@objectId.val('')
return
if @attribute.guess is true
else if @attribute.guess is true
currentObjectId = @objectId.val()
if _.isEmpty(currentObjectId) || currentObjectId.match(/^guess:/)
if !_.isEmpty(selectObject)
@ -95,31 +94,28 @@ class App.ObjectOrganizationAutocompletion extends App.Controller
onObjectClick: (e) =>
objectId = $(e.currentTarget).data('object-id')
@selectObject(objectId)
objectName = $(e.currentTarget).find('.recipientList-name').text().trim()
@selectObject(objectId, objectName)
@close()
selectObject: (objectId) =>
if @attribute.multiple and @objectId.val()
# add objectId to end of comma separated list
objectId = _.chain( @objectId.val().split(',') ).push(objectId).join(',').value()
@objectSelect.val('')
@objectId.val(objectId).trigger('change')
selectObject: (objectId, objectName) =>
if @attribute.multiple
@addValueToObjectInput(objectName, objectId)
else
@objectSelect.val('')
@objectId.val(objectId).trigger('change')
executeCallback: =>
# with @attribute.multiple this can be several objects ids.
# Only work with the last one since its the newest one
objectId = @objectId.val().split(',').pop()
if @attribute.multiple
# create token
@createToken(@currentObject) if @currentObject
@currentObject = null
if objectId && App[@objectSingle].exists(objectId)
object = App[@objectSingle].find(objectId)
name = object.displayName()
if @attribute.multiple
# create token
@createToken(name, objectId)
else
else
objectId = @objectId.val()
if objectId && App[@objectSingle].exists(objectId)
object = App[@objectSingle].find(objectId)
name = object.displayName()
if object.email
# quote name for special character
@ -132,10 +128,10 @@ class App.ObjectOrganizationAutocompletion extends App.Controller
if @callback
@callback(objectId)
createToken: (name, objectId) =>
createToken: ({name, value}) =>
@objectSelect.before App.view('generic/token')(
name: name
value: objectId
value: value
)
removeThisToken: (e) =>
@ -149,12 +145,9 @@ class App.ObjectOrganizationAutocompletion extends App.Controller
else
token = which
# remove objectId from input
index = @$('.token').index(token)
ids = @objectId.val().split(',')
ids.splice(index, 1)
@objectId.val ids.join(',')
id = token.data('value')
@objectId.find("[value=#{id}]").remove()
@objectId.trigger('change')
token.remove()
navigateByKeyboard: (e) =>
@ -170,7 +163,7 @@ class App.ObjectOrganizationAutocompletion extends App.Controller
@objectSelect.val('').trigger('change')
# remove last token on backspace
when 8
if @objectSelect.val() is ''
if @objectSelect.val() is '' && @objectSelect.is(e.target)
@removeToken('last')
# close on tab
when 9 then @close()
@ -223,7 +216,8 @@ class App.ObjectOrganizationAutocompletion extends App.Controller
return
objectId = recipientListOrganizationMembers.find('li.is-active').data('object-id')
return if !objectId
@selectObject(objectId)
objectName = recipientListOrganizationMembers.find('li.is-active .recipientList-name').text().trim()
@selectObject(objectId, objectName)
@close() if !@attribute.multiple
return
@ -233,7 +227,8 @@ class App.ObjectOrganizationAutocompletion extends App.Controller
if objectId is 'new'
@newObject()
else
@selectObject(objectId)
objectName = @recipientList.find('li.is-active .recipientList-name').text().trim()
@selectObject(objectId, objectName)
@close() if !@attribute.multiple
return
@ -242,6 +237,14 @@ class App.ObjectOrganizationAutocompletion extends App.Controller
@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) ->
objectCount = 0
if organization[@referenceAttribute]
@ -315,17 +318,23 @@ class App.ObjectOrganizationAutocompletion extends App.Controller
# fallback for if the value is not an array
if typeof @attribute.value isnt 'object'
@attribute.value = [@attribute.value]
value = @attribute.value.join ','
# create tokens
# create tokens and attribute values
values = []
for objectId in @attribute.value
if App[@objectSingle].exists objectId
objectName = App[@objectSingle].find(objectId).displayName()
objectValue = objectId
values.push({name: objectName, value: objectValue})
tokens += App.view('generic/token')(
name: App[@objectSingle].find(objectId).displayName()
value: objectId
name: objectName
value: objectValue
)
else
@log 'objectId doesn\'t exist', objectId
@attribute.value = values
else
value = @attribute.value
if value
@ -369,7 +378,7 @@ class App.ObjectOrganizationAutocompletion extends App.Controller
@recipientList.append(@buildObjectNew())
# reset object selection
@resetObjectSelection()
@resetObjectSelection() if !@attribute.multiple
return
# show dropdown

View file

@ -15,6 +15,7 @@ class App.SearchableSelect extends Spine.Controller
'shown.bs.dropdown': 'onDropdownShown'
'hidden.bs.dropdown': 'onDropdownHidden'
'keyup .js-input': 'onKeyUp'
'click .js-remove': 'removeThisToken'
elements:
'.js-dropdown': 'dropdown'
@ -38,10 +39,33 @@ class App.SearchableSelect extends Spine.Controller
render: ->
@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')
attribute: @attribute
options: @renderAllOptions('', @attribute.options, 0)
submenus: @renderSubmenus(@attribute.options)
tokens: tokens
# initial data
@currentMenu = @findMenuContainingValue(@attribute.value)
@ -133,12 +157,12 @@ class App.SearchableSelect extends Spine.Controller
@unhighlightCurrentItem()
@isOpen = false
if !@input.val()
if !@input.val() && !@attribute.multiple
@updateAttributeValueName()
@input.val(@attribute.valueName)
onKeyUp: =>
return if @input.val().trim() isnt ''
return if @input.val().trim() isnt '' || @attribute.multiple
@shadowInput.val('')
toggle: =>
@ -157,6 +181,9 @@ class App.SearchableSelect extends Spine.Controller
when 13 then @onEnter(event)
when 27 then @onEscape(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: ->
if @isOpen
@ -192,7 +219,7 @@ class App.SearchableSelect extends Spine.Controller
@clearAutocomplete()
autocompleteOrNavigateIn: (event) ->
if @currentItem.hasClass('js-enter')
if @currentItem && @currentItem.hasClass('js-enter')
@navigateIn(event)
else
@fillWithAutocompleteSuggestion(event)
@ -215,8 +242,11 @@ class App.SearchableSelect extends Spine.Controller
# current position
caretPosition = @invisiblePart.text().length + 1
@input.val(@suggestion)
@shadowInput.val(@suggestionValue)
if @attribute.multiple
@addValueToShadowInput(@suggestion, @suggestionValue)
else
@input.val(@suggestion)
@shadowInput.val(@suggestionValue)
@clearAutocomplete()
@toggle()
@ -242,10 +272,15 @@ class App.SearchableSelect extends Spine.Controller
selectItem: (event) ->
currentText = event.currentTarget.querySelector('span.searchableSelect-option-text').textContent.trim()
return if !currentText
@input.val currentText
@input.trigger('change')
@shadowInput.val event.currentTarget.getAttribute('data-value')
@shadowInput.trigger('change')
dataId = event.currentTarget.getAttribute('data-value')
if @attribute.multiple
@addValueToShadowInput(currentText, dataId)
else
@input.val currentText
@input.trigger('change')
@shadowInput.val dataId
@shadowInput.trigger('change')
navigateIn: (event) ->
event.stopPropagation()
@ -354,11 +389,14 @@ class App.SearchableSelect extends Spine.Controller
if @currentItem || !@attribute.unknown
valueName = @currentItem.children('span.searchableSelect-option-text').text().trim()
value = @currentItem.attr('data-value')
@input.val valueName
@shadowInput.val value
if @attribute.multiple
@addValueToShadowInput(valueName, value)
else
@input.val valueName
@shadowInput.val value
@shadowInput.trigger('change')
@input.trigger('change')
@shadowInput.trigger('change')
if @currentItem
if @currentItem.hasClass('js-enter')
@ -386,17 +424,44 @@ class App.SearchableSelect extends Spine.Controller
onShadowChange: ->
value = @shadowInput.val()
if @attribute.multiple and @currentData
# create token
@createToken(@currentData)
@currentData = null
if Array.isArray(@attribute.options)
for option in @attribute.options
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) =>
@toggle() if not @isOpen
@query = @input.val()
@filterByQuery @query
if @attribute.unknown
if @attribute.unknown && !@attribute.multiple
@shadowInput.val @query
filterByQuery: (query) ->
@ -422,6 +487,14 @@ class App.SearchableSelect extends Spine.Controller
else
@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) ->
@unhighlightCurrentItem()
@currentItem = @getCurrentOptions().not('.is-hidden').first()

View file

@ -1,12 +1,20 @@
<div class="tokenfield form-control u-positionOrigin">
<input class="js-objectId" type="hidden" value="<%= @value %>" name="<%- @attribute.name %>" tabindex="-1">
<% if @attribute.multiple: %>
<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 %>
</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">
<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 %>
</div>
<div class="dropdown-menu" aria-labelledby="customer_id">
<ul class="recipientList" role="menu"></ul>
</div>
</div>

View file

@ -1,22 +1,42 @@
<div class="dropdown-toggle" data-toggle="dropdown">
<input
class="searchableSelect-shadow form-control js-shadow"
<% if @attribute.id: %>id="<%= @attribute.id %>"<% end %>
name="<%= @attribute.name %>"
<%= @attribute.required %>
<%= @attribute.autofocus %>
value="<%= @attribute.value %>"
tabindex="-1"
<% if @attribute.disabled: %> disabled<% end %>
>
<input
class="searchableSelect-main form-control js-input<%= " #{ @attribute.class }" if @attribute.class %>"
placeholder="<%= @attribute.placeholder %>"
value="<%= @attribute.valueName %>"
autocomplete="off"
<%= @attribute.required %>
<% if @attribute.disabled: %> disabled<% end %>
>
<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
class="searchableSelect-shadow form-control js-shadow"
<% if @attribute.id: %>id="<%= @attribute.id %>"<% end %>
name="<%= @attribute.name %>"
<%= @attribute.required %>
<%= @attribute.autofocus %>
value="<%= @attribute.value %>"
tabindex="-1"
<% if @attribute.disabled: %> disabled<% end %>
>
<input
class="searchableSelect-main form-control js-input<%= " #{ @attribute.class }" if @attribute.class %>"
placeholder="<%= @attribute.placeholder %>"
value="<%= @attribute.valueName %>"
autocomplete="off"
<%= @attribute.required %>
<% if @attribute.disabled: %> disabled<% end %>
>
<% end %>
<div class="searchableSelect-autocomplete">
<span class="searchableSelect-autocomplete-invisible js-autocomplete-invisible"></span>
<span class="searchableSelect-autocomplete-visible js-autocomplete-visible"></span>
@ -29,4 +49,4 @@
<%- @options %>
</ul>
<%- @submenus %>
</div>
</div>

View file

@ -531,17 +531,18 @@ QUnit.test('form checks', assert => {
operator: 'is not',
pre_condition: 'specific',
value: '12',
value_completion: '',
},
'ticket.owner_id': {
operator: 'is',
pre_condition: 'specific',
value: '47',
value_completion: 'Bob Smith <bod@example.com>',
value_completion: '',
},
'ticket.created_by_id': {
operator: 'is',
pre_condition: 'current_user.id',
value: '',
value: null,
value_completion: ''
},
},
@ -552,7 +553,7 @@ QUnit.test('form checks', assert => {
'ticket.owner_id': {
pre_condition: 'specific',
value: '47',
value_completion: 'Bob Smith <bod@example.com>'
value_completion: ''
},
'ticket.priority_id': {
value: '3',
@ -596,17 +597,18 @@ QUnit.test('form checks', assert => {
operator: 'is not',
pre_condition: 'specific',
value: '12',
value_completion: '',
},
'ticket.owner_id': {
operator: 'is',
pre_condition: 'specific',
value: '47',
value_completion: 'Bob Smith <bod@example.com>',
value_completion: '',
},
'ticket.created_by_id': {
operator: 'is',
pre_condition: 'current_user.id',
value: '',
value: null,
value_completion: ''
},
},
@ -617,7 +619,7 @@ QUnit.test('form checks', assert => {
'ticket.owner_id': {
pre_condition: 'specific',
value: '47',
value_completion: 'Bob Smith <bod@example.com>'
value_completion: ''
},
'ticket.tags': {
operator: 'remove',
@ -657,17 +659,18 @@ QUnit.test('form checks', assert => {
operator: 'is not',
pre_condition: 'specific',
value: '12',
value_completion: '',
},
'ticket.owner_id': {
operator: 'is',
pre_condition: 'specific',
value: '47',
value_completion: 'Bob Smith <bod@example.com>',
value_completion: '',
},
'ticket.created_by_id': {
operator: 'is',
pre_condition: 'current_user.id',
value: '',
value: null,
value_completion: ''
},
},
@ -678,7 +681,7 @@ QUnit.test('form checks', assert => {
'ticket.owner_id': {
pre_condition: 'specific',
value: '47',
value_completion: 'Bob Smith <bod@example.com>'
value_completion: ''
},
'ticket.tags': {
operator: 'remove',
@ -714,17 +717,18 @@ QUnit.test('form checks', assert => {
operator: 'is not',
pre_condition: 'specific',
value: '12',
value_completion: '',
},
'ticket.owner_id': {
operator: 'is',
pre_condition: 'specific',
value: '47',
value_completion: 'Bob Smith <bod@example.com>',
value_completion: '',
},
'ticket.created_by_id': {
operator: 'is',
pre_condition: 'current_user.id',
value: '',
value: null,
value_completion: ''
},
},
@ -735,7 +739,7 @@ QUnit.test('form checks', assert => {
'ticket.owner_id': {
pre_condition: 'specific',
value: '47',
value_completion: 'Bob Smith <bod@example.com>'
value_completion: ''
},
'notification.email': {
recipient: 'ticket_owner',
@ -849,4 +853,167 @@ QUnit.test('form checks', assert => {
},
}
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')
});

View file

@ -595,7 +595,7 @@ QUnit.test( "ticket_perform_action check possible owner selection", assert => {
ticket_perform_action5: {
'ticket.owner_id': {
pre_condition: 'not_set',
value: '',
value: null,
value_completion: ''
}
}
@ -610,7 +610,7 @@ QUnit.test( "ticket_perform_action check possible owner selection", assert => {
ticket_perform_action5: {
'ticket.owner_id': {
pre_condition: 'specific',
value: '',
value: null,
value_completion: ''
}
}

View 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