Moved to new query condition syntax to support is, is not, contains, contains not, ...
This commit is contained in:
parent
3d47199ec5
commit
d825cc288b
16 changed files with 618 additions and 333 deletions
|
@ -1,111 +1,58 @@
|
|||
class App.UiElement.ticket_selector
|
||||
@render: (attribute, params = {}) ->
|
||||
@defaults: ->
|
||||
defaults = ['ticket.state_id']
|
||||
|
||||
# list of attributes
|
||||
groups =
|
||||
tickets:
|
||||
ticket:
|
||||
name: 'Ticket'
|
||||
model: 'Ticket'
|
||||
users:
|
||||
customer:
|
||||
name: 'Customer'
|
||||
model: 'User'
|
||||
organizations:
|
||||
organization:
|
||||
name: 'Organization'
|
||||
model: 'Organization'
|
||||
|
||||
elements =
|
||||
tickets:
|
||||
title:
|
||||
tag: 'input'
|
||||
operator: ['contains', 'contains not']
|
||||
number:
|
||||
tag: 'input'
|
||||
operator: ['contains', 'contains not']
|
||||
group_id:
|
||||
relation: 'Group'
|
||||
tag: 'select'
|
||||
multible: true
|
||||
operator: ['is', 'is not']
|
||||
priority_id:
|
||||
relation: 'Priority'
|
||||
tag: 'select'
|
||||
multible: true
|
||||
operator: ['is', 'is not']
|
||||
state_id:
|
||||
relation: 'State'
|
||||
tag: 'select'
|
||||
multible: true
|
||||
operator: ['is', 'is not']
|
||||
owner_id:
|
||||
tag: 'user_selection'
|
||||
relation: 'User'
|
||||
operator: ['is', 'is not']
|
||||
customer_id:
|
||||
tag: 'user_selection'
|
||||
relation: 'User'
|
||||
operator: ['is', 'is not']
|
||||
organization_id:
|
||||
tag: ''
|
||||
relation: 'Organization'
|
||||
operator: ['is', 'is not']
|
||||
tag:
|
||||
tag: 'tag'
|
||||
multible: true
|
||||
operator: ['is', 'is not']
|
||||
created_at:
|
||||
tag: 'timestamp'
|
||||
operator: ['before', 'after']
|
||||
updated_at:
|
||||
tag: 'timestamp'
|
||||
operator: ['before', 'after']
|
||||
escalation_time:
|
||||
tag: 'timestamp'
|
||||
operator: ['before', 'after']
|
||||
users:
|
||||
firstname:
|
||||
tag: 'input'
|
||||
operator: ['contains', 'contains not']
|
||||
lastname:
|
||||
tag: 'input'
|
||||
operator: ['contains', 'contains not']
|
||||
email:
|
||||
tag: 'input'
|
||||
operator: ['contains', 'contains not']
|
||||
login:
|
||||
tag: 'input'
|
||||
operator: ['contains', 'contains not']
|
||||
created_at:
|
||||
tag: 'time_selector_enhanced'
|
||||
operator: ['before', 'after']
|
||||
updated_at:
|
||||
tag: 'time_selector_enhanced'
|
||||
operator: ['before', 'after']
|
||||
organizations:
|
||||
name:
|
||||
tag: 'input'
|
||||
operator: ['contains', 'contains not']
|
||||
shared:
|
||||
tag: 'boolean'
|
||||
operator: ['is', 'is not']
|
||||
created_at:
|
||||
tag: 'time_selector_enhanced'
|
||||
operator: ['before', 'after']
|
||||
updated_at:
|
||||
tag: 'time_selector_enhanced'
|
||||
operator: ['before', 'after']
|
||||
operators_type =
|
||||
'^datetime$': ['before (absolute)', 'after (absolute)', 'before (relative)', 'after (relative)']
|
||||
'^timestamp$': ['before (absolute)', 'after (absolute)', 'before (relative)', 'after (relative)']
|
||||
'boolean$': ['is', 'is not']
|
||||
'^input$': ['contains', 'contains not']
|
||||
'^textarea$': ['contains', 'contains not']
|
||||
|
||||
operators_name =
|
||||
'_id$': ['is', 'is not']
|
||||
'_ids$': ['is', 'is not']
|
||||
|
||||
# megre config
|
||||
elements = {}
|
||||
for groupKey, groupMeta of groups
|
||||
for elementKey, elementGroup of elements
|
||||
if elementKey is groupKey
|
||||
configure_attributes = App[groupMeta.model].configure_attributes
|
||||
for attributeName, attributeConfig of elementGroup
|
||||
for attribute in configure_attributes
|
||||
if attribute.name is attributeName
|
||||
attributeConfig.config = attribute
|
||||
for row in App[groupMeta.model].configure_attributes
|
||||
|
||||
# ignore passwords and relations
|
||||
if row.type isnt 'password' && row.name.substr(row.name.length-4,4) isnt '_ids'
|
||||
config = _.clone(row)
|
||||
for operatorRegEx, operator of operators_type
|
||||
myRegExp = new RegExp(operatorRegEx, 'i')
|
||||
if config.tag && config.tag.match(myRegExp)
|
||||
config.operator = operator
|
||||
elements["#{groupKey}.#{config.name}"] = config
|
||||
for operatorRegEx, operator of operators_name
|
||||
myRegExp = new RegExp(operatorRegEx, 'i')
|
||||
if config.name && config.name.match(myRegExp)
|
||||
config.operator = operator
|
||||
elements["#{groupKey}.#{config.name}"] = config
|
||||
[defaults, groups, elements]
|
||||
|
||||
@render: (attribute, params = {}) ->
|
||||
|
||||
[defaults, groups, elements] = @defaults()
|
||||
|
||||
selector = @buildAttributeSelector(groups, elements)
|
||||
|
||||
search = =>
|
||||
@preview(item)
|
||||
|
||||
# return item
|
||||
item = $( App.view('generic/ticket_selector')( attribute: attribute ) )
|
||||
item.find('.js-attributeSelector').prepend(selector)
|
||||
|
@ -116,12 +63,14 @@ class App.UiElement.ticket_selector
|
|||
elementClone = element.clone(true)
|
||||
element.after(elementClone)
|
||||
elementClone.find('.js-attributeSelector select').trigger('change')
|
||||
@preview(item)
|
||||
)
|
||||
|
||||
# remove filter
|
||||
item.find('.js-remove').bind('click', (e) =>
|
||||
$(e.target).closest('.js-filterElement').remove()
|
||||
@rebuildAttributeSelectors(item)
|
||||
@preview(item)
|
||||
)
|
||||
|
||||
# change filter
|
||||
|
@ -158,9 +107,20 @@ class App.UiElement.ticket_selector
|
|||
if selectorExists
|
||||
item.find('.js-filterElement').first().remove()
|
||||
|
||||
else
|
||||
for default_row in defaults
|
||||
|
||||
# get selector rows
|
||||
elementFirst = item.find('.js-filterElement').first()
|
||||
elementLast = item.find('.js-filterElement').last()
|
||||
|
||||
# clone, rebuild and append
|
||||
elementClone = elementFirst.clone(true)
|
||||
@rebuildAttributeSelectors(item, elementClone, default_row)
|
||||
elementLast.after(elementClone)
|
||||
item.find('.js-filterElement').first().remove()
|
||||
|
||||
# bind for preview
|
||||
search = =>
|
||||
@preview(item)
|
||||
item.on('change', 'select.form-control', (e) =>
|
||||
App.Delay.set(
|
||||
search,
|
||||
|
@ -168,7 +128,7 @@ class App.UiElement.ticket_selector
|
|||
'preview',
|
||||
)
|
||||
)
|
||||
item.on('keyup', 'input.form-control', (e) =>
|
||||
item.on('change keyup', 'input.form-control', (e) =>
|
||||
App.Delay.set(
|
||||
search,
|
||||
600,
|
||||
|
@ -200,13 +160,6 @@ class App.UiElement.ticket_selector
|
|||
ticket_ids: ticket_ids
|
||||
)
|
||||
|
||||
@getElementConfig: (groupAndAttribute, elements) ->
|
||||
for elementGroup, elementConfig of elements
|
||||
for elementKey, elementItem of elementConfig
|
||||
if "#{elementGroup}.#{elementKey}" is groupAndAttribute
|
||||
return elementItem
|
||||
false
|
||||
|
||||
@buildValue: (elementFull, elementRow, groupAndAttribute, elements, value) ->
|
||||
|
||||
# do nothing if item already exists
|
||||
|
@ -214,16 +167,32 @@ class App.UiElement.ticket_selector
|
|||
return if elementRow.find("[name=\"#{name}\"]").get(0)
|
||||
|
||||
# build new item
|
||||
attributeConfig = @getElementConfig(groupAndAttribute, elements)
|
||||
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 attributeConfig && attributeConfig.config && App.UiElement[attributeConfig.config.tag]
|
||||
config = _.clone(attributeConfig.config)
|
||||
if config && App.UiElement[config.tag]
|
||||
config['name'] = name
|
||||
config['value'] = value
|
||||
if 'multiple' of config
|
||||
config.multiple = true
|
||||
config.nulloption = false
|
||||
item = App.UiElement[attributeConfig.config.tag].render(config, {})
|
||||
if config.tag is 'checkbox'
|
||||
config.tag = 'select'
|
||||
#config.type = 'datetime-local'
|
||||
#if config.tag is 'datetime'
|
||||
# config.tag = 'input'
|
||||
# config.type = 'datetime-local'
|
||||
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) ->
|
||||
|
@ -233,13 +202,12 @@ class App.UiElement.ticket_selector
|
|||
selection.closest('select').append("<optgroup label=\"#{displayName}\" class=\"js-#{groupKey}\"></optgroup>")
|
||||
optgroup = selection.find("optgroup.js-#{groupKey}")
|
||||
for elementKey, elementGroup of elements
|
||||
if elementKey is groupKey
|
||||
for attributeName, attributeConfig of elementGroup
|
||||
if attributeConfig.config && attributeConfig.config.display
|
||||
displayName = App.i18n.translateInline(attributeConfig.config.display)
|
||||
else
|
||||
displayName = App.i18n.translateInline(attributeName)
|
||||
optgroup.append("<option value=\"#{groupKey}.#{attributeName}\">#{displayName}</option>")
|
||||
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) ->
|
||||
|
@ -267,14 +235,16 @@ class App.UiElement.ticket_selector
|
|||
|
||||
@buildOperator: (elementFull, elementRow, groupAndAttribute, elements, current_operator) ->
|
||||
selection = $("<select class=\"form-control\" name=\"condition::#{groupAndAttribute}::operator\"></select>")
|
||||
attributeConfig = @getElementConfig(groupAndAttribute, elements)
|
||||
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
|
||||
|
||||
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) ->
|
||||
return if !groupAndAttribute
|
||||
|
@ -290,16 +260,43 @@ class App.UiElement.ticket_selector
|
|||
@humanText: (condition) ->
|
||||
none = App.i18n.translateContent('No filter.')
|
||||
return [none] if _.isEmpty(condition)
|
||||
[defaults, groups, elements] = @defaults()
|
||||
rules = []
|
||||
for position of condition.attribute
|
||||
for attribute, meta of condition
|
||||
|
||||
objectAttribute = attribute.split(/\./)
|
||||
|
||||
# get stored params
|
||||
groupAndAttribute = condition.attribute[position]
|
||||
if condition[groupAndAttribute]
|
||||
if meta && objectAttribute[1]
|
||||
selectorExists = true
|
||||
operator = condition[groupAndAttribute].operator
|
||||
value = condition[groupAndAttribute].value
|
||||
rules.push "#{App.i18n.translateContent('Where')} <b>#{App.i18n.translateContent(groupAndAttribute)}</b> #{App.i18n.translateContent(operator)} <b>#{App.i18n.translateContent(value)}</b>."
|
||||
operator = meta.operator
|
||||
value = meta.value
|
||||
model = toCamelCase(objectAttribute[0])
|
||||
modelAttribute = objectAttribute[1]
|
||||
|
||||
config = elements[attribute]
|
||||
|
||||
if modelAttribute.substr(modelAttribute.length-4,4) is '_ids'
|
||||
modelAttribute = modelAttribute.substr(0, modelAttribute.length-4)
|
||||
if modelAttribute.substr(modelAttribute.length-3,3) is '_id'
|
||||
modelAttribute = modelAttribute.substr(0, modelAttribute.length-3)
|
||||
valueHuman = []
|
||||
if _.isArray(value)
|
||||
for data in value
|
||||
r = @humanTextLookup(config, data)
|
||||
valueHuman.push r
|
||||
else
|
||||
valueHuman.push @humanTextLookup(config, value)
|
||||
rules.push "#{App.i18n.translateContent('Where')} <b>#{App.i18n.translateContent(model)} -> #{App.i18n.translateContent(toCamelCase(modelAttribute))}</b> #{App.i18n.translateContent(operator)} <b>#{valueHuman}</b>."
|
||||
|
||||
return [none] if _.isEmpty(rules)
|
||||
rules
|
||||
rules
|
||||
|
||||
@humanTextLookup: (config, value) ->
|
||||
return value if !App[config.relation]
|
||||
return value if !App[config.relation].exists(value)
|
||||
data = App[config.relation].fullLocal(value)
|
||||
return value if !data
|
||||
if data.displayName
|
||||
return App.i18n.translateContent( data.displayName() )
|
||||
valueHuman.push App.i18n.translateContent( data.name )
|
||||
|
|
|
@ -22,6 +22,7 @@ class Index extends App.ControllerContent
|
|||
{ name: 'New Overview', 'data-type': 'new', class: 'btn--success' }
|
||||
]
|
||||
container: @el.closest('.content')
|
||||
large: true,
|
||||
)
|
||||
|
||||
App.Config.set( 'Overview', { prio: 2300, name: 'Overviews', parent: '#manage', target: '#manage/overviews', controller: Index, role: ['Admin'] }, 'NavBarAdmin' )
|
|
@ -1,16 +1,15 @@
|
|||
class App.Overview extends App.Model
|
||||
@configure 'Overview', 'name', 'link', 'prio', 'condition', 'order', 'group_by', 'view', 'user_id', 'organization_shared', 'role_id', 'order', 'group_by', 'active', 'updated_at'
|
||||
@configure 'Overview', 'name', 'prio', 'condition', 'order', 'group_by', 'view', 'user_id', 'organization_shared', 'role_id', 'order', 'group_by', 'active', 'updated_at'
|
||||
@extend Spine.Model.Ajax
|
||||
@url: @apiPath + '/overviews'
|
||||
@configure_attributes = [
|
||||
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, 'null': false, 'class': 'span4' },
|
||||
{ name: 'link', display: 'URL', tag: 'input', type: 'text', limit: 100, 'null': false, 'class': 'span4' },
|
||||
{ name: 'role_id', display: 'Available for Role', tag: 'select', multiple: false, nulloption: true, null: false, relation: 'Role', translate: true, class: 'span4' },
|
||||
{ name: 'user_id', display: 'Available for User', tag: 'select', multiple: true, nulloption: true, null: true, relation: 'User', sortBy: 'firstname', class: 'span4' },
|
||||
{ name: 'organization_shared', display: 'Only available for Users with shared Organization', tag: 'select', options: { true: 'yes', false: 'no' }, default: false, null: true, 'class': 'span4' },
|
||||
# { name: 'content', display: 'Content', tag: 'textarea', limit: 250, 'null': false, 'class': 'span4' },
|
||||
{ name: 'condition', display: 'Conditions for shown Tickets', tag: 'ticket_attribute_selection', null: true, class: 'span4' },
|
||||
{ name: 'prio', display: 'Prio', tag: 'input', type: 'text', limit: 10, 'null': false, 'class': 'span4' },
|
||||
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, 'null': false },
|
||||
{ name: 'role_id', display: 'Available for Role', tag: 'select', multiple: false, nulloption: true, null: false, relation: 'Role', translate: true },
|
||||
{ name: 'user_id', display: 'Available for User', tag: 'select', multiple: true, nulloption: true, null: true, relation: 'User', sortBy: 'firstname' },
|
||||
{ name: 'organization_shared', display: 'Only available for Users with shared Organization', tag: 'select', options: { true: 'yes', false: 'no' }, default: false, null: true },
|
||||
# { name: 'content', display: 'Content', tag: 'textarea', limit: 250, 'null': false },
|
||||
{ name: 'condition', display: 'Conditions for shown Tickets', tag: 'ticket_selector', null: false },
|
||||
{ name: 'prio', display: 'Prio', tag: 'input', type: 'text', limit: 10, 'null': false },
|
||||
{
|
||||
name: 'view::s'
|
||||
display: 'Attributes'
|
||||
|
|
|
@ -11,18 +11,18 @@ class App.Ticket extends App.Model
|
|||
{ name: 'title', display: 'Title', tag: 'input', type: 'text', limit: 100, null: false, parentClass: 'noTruncate' },
|
||||
{ name: 'state_id', display: 'State', tag: 'select', multiple: false, null: false, relation: 'TicketState', default: 'new', style: 'width: 12%', edit: true, customer: true, },
|
||||
{ name: 'priority_id', display: 'Priority', tag: 'select', multiple: false, null: false, relation: 'TicketPriority', default: '2 normal', style: 'width: 12%', edit: true, customer: true, },
|
||||
{ name: 'article_count', display: 'Article#', style: 'width: 12%' },
|
||||
{ name: 'escalation_time', display: 'Escalation', tag: 'datetime', null: true, style: 'width: 12%', class: 'escalation', parentClass: 'noTruncate' },
|
||||
{ name: 'last_contact', display: 'Last contact', tag: 'datetime', null: true, style: 'width: 12%', parentClass: 'noTruncate' },
|
||||
{ name: 'last_contact_agent', display: 'Last contact (Agent)', tag: 'datetime', null: true, style: 'width: 12%', parentClass: 'noTruncate' },
|
||||
{ name: 'last_contact_customer', display: 'Last contact (Customer)', tag: 'datetime', null: true, style: 'width: 12%', parentClass: 'noTruncate' },
|
||||
{ name: 'first_response', display: 'First response', tag: 'datetime', null: true, style: 'width: 12%', parentClass: 'noTruncate' },
|
||||
{ name: 'close_time', display: 'Close time', tag: 'datetime', null: true, style: 'width: 12%', parentClass: 'noTruncate' },
|
||||
{ name: 'pending_time', display: 'Pending Time', tag: 'datetime', null: true, style: 'width: 12%', parentClass: 'noTruncate' },
|
||||
{ name: 'escalation_time', display: 'Escalation', tag: 'datetime', null: true, style: 'width: 12%', class: 'escalation', parentClass: 'noTruncate' },
|
||||
{ name: 'article_count', display: 'Article#', style: 'width: 12%' },
|
||||
{ name: 'created_by_id', display: 'Created by', relation: 'User', readonly: 1 },
|
||||
{ name: 'created_at', display: 'Created', tag: 'datetime', style: 'width: 120px', readonly: 1, parentClass: 'noTruncate' },
|
||||
{ name: 'updated_by_id', display: 'Updated by', relation: 'User', readonly: 1 },
|
||||
{ name: 'updated_at', display: 'Updated', tag: 'datetime', style: 'width: 120px', readonly: 1, parentClass: 'noTruncate' },
|
||||
{ name: 'created_by_id', display: 'Created by', relation: 'User', readonly: 1 },
|
||||
{ name: 'created_at', display: 'Created at', tag: 'datetime', style: 'width: 120px', readonly: 1, parentClass: 'noTruncate' },
|
||||
{ name: 'updated_by_id', display: 'Updated by', relation: 'User', readonly: 1 },
|
||||
{ name: 'updated_at', display: 'Updated at', tag: 'datetime', style: 'width: 120px', readonly: 1, parentClass: 'noTruncate' },
|
||||
]
|
||||
|
||||
uiUrl: ->
|
||||
|
|
|
@ -9,15 +9,7 @@ class App.User extends App.Model
|
|||
{ name: 'firstname', display: 'Firstname', tag: 'input', type: 'text', limit: 100, null: false, signup: true, info: true, invite_agent: true },
|
||||
{ name: 'lastname', display: 'Lastname', tag: 'input', type: 'text', limit: 100, null: false, signup: true, info: true, invite_agent: true },
|
||||
{ name: 'email', display: 'Email', tag: 'input', type: 'email', limit: 100, null: false, signup: true, info: true, invite_agent: true },
|
||||
{ name: 'web', display: 'Web', tag: 'input', type: 'url', limit: 100, null: true, signup: false, info: true },
|
||||
{ name: 'phone', display: 'Phone', tag: 'input', type: 'phone', limit: 100, null: true, signup: false, info: true },
|
||||
{ name: 'mobile', display: 'Mobile', tag: 'input', type: 'phone', limit: 100, null: true, signup: false, info: true },
|
||||
{ name: 'fax', display: 'Fax', tag: 'input', type: 'phone', limit: 100, null: true, signup: false, info: true },
|
||||
{ name: 'organization_id', display: 'Organization', tag: 'select', multiple: false, nulloption: true, null: true, relation: 'Organization', signup: false, info: true },
|
||||
{ name: 'department', display: 'Department', tag: 'input', type: 'text', limit: 200, null: true, signup: false, info: true },
|
||||
{ name: 'street', display: 'Street', tag: 'input', type: 'text', limit: 100, null: true, signup: false, info: true },
|
||||
{ name: 'zip', display: 'Zip', tag: 'input', type: 'text', limit: 100, null: true, signup: false, info: true },
|
||||
{ name: 'city', display: 'City', tag: 'input', type: 'text', limit: 100, null: true, signup: false, info: true },
|
||||
{ name: 'password', display: 'Password', tag: 'input', type: 'password', limit: 50, null: true, autocomplete: 'off', signup: true, },
|
||||
{ name: 'note', display: 'Note', tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, null: true, info: true },
|
||||
{ name: 'role_ids', display: 'Roles', tag: 'checkbox', multiple: true, null: false, relation: 'Role' },
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
<div class="sub_attribute well">
|
||||
<div class="ticket_attribute_item"></div>
|
||||
<hr>
|
||||
<div class="ticket_attribute_list"></div>
|
||||
</div>
|
|
@ -208,6 +208,13 @@ function underscored (str) {
|
|||
return str.trim().replace(/([a-z\d])([A-Z]+)/g, '$1_$2').replace(/[-\s]+/g, '_').toLowerCase();
|
||||
}
|
||||
|
||||
function toCamelCase (str) {
|
||||
return str
|
||||
.replace(/\s(.)/g, function($1) { return $1.toUpperCase(); })
|
||||
.replace(/\s/g, '')
|
||||
.replace(/^(.)/, function($1) { return $1.toUpperCase(); });
|
||||
};
|
||||
|
||||
jQuery.event.special.remove = {
|
||||
remove: function(e) {
|
||||
if (e.handler) e.handler();
|
||||
|
|
|
@ -60,9 +60,33 @@ curl http://localhost/api/v1/slas.json -v -u #{login}:#{password}
|
|||
|
||||
# slas
|
||||
sla_ids = []
|
||||
models = Models.all
|
||||
Sla.all.order(:name).each {|sla|
|
||||
sla_ids.push sla.id
|
||||
assets = sla.assets(assets)
|
||||
|
||||
# get assets of condition
|
||||
sla.condition.each {|item, content|
|
||||
attribute = item.split(/\./)
|
||||
next if !attribute[1]
|
||||
attribute_class = attribute[0].to_classname.constantize
|
||||
reflection = attribute[1].sub(/_id$/, '')
|
||||
reflection = reflection.to_sym
|
||||
next if !models[attribute_class]
|
||||
next if !models[attribute_class][:reflections]
|
||||
next if !models[attribute_class][:reflections][reflection]
|
||||
next if !models[attribute_class][:reflections][reflection].klass
|
||||
attribute_ref_class = models[attribute_class][:reflections][reflection].klass
|
||||
if content['value'].class == Array
|
||||
content['value'].each {|item_id|
|
||||
attribute_object = attribute_ref_class.find_by(id: item_id)
|
||||
assets = attribute_object.assets(assets)
|
||||
}
|
||||
else
|
||||
attribute_object = attribute_ref_class.find_by(id: content['value'])
|
||||
assets = attribute_object.assets(assets)
|
||||
end
|
||||
}
|
||||
}
|
||||
|
||||
render json: {
|
||||
|
|
|
@ -389,8 +389,14 @@ class TicketsController < ApplicationController
|
|||
if params[:user_id]
|
||||
user = User.find( params[:user_id] )
|
||||
condition = {
|
||||
'tickets.state_id' => Ticket::State.by_category('open'),
|
||||
'tickets.customer_id' => user.id,
|
||||
'tickets.state_id' => {
|
||||
operator: 'is',
|
||||
value: Ticket::State.by_category('open').map(&:id),
|
||||
},
|
||||
'tickets.customer_id' => {
|
||||
operator: 'is',
|
||||
value: user.id,
|
||||
},
|
||||
}
|
||||
user_tickets_open = Ticket.search(
|
||||
limit: limit,
|
||||
|
@ -401,8 +407,14 @@ class TicketsController < ApplicationController
|
|||
|
||||
# lookup closed user tickets
|
||||
condition = {
|
||||
'tickets.state_id' => Ticket::State.by_category('closed'),
|
||||
'tickets.customer_id' => user.id,
|
||||
'tickets.state_id' => {
|
||||
operator: 'is',
|
||||
value: Ticket::State.by_category('closed').map(&:id),
|
||||
},
|
||||
'tickets.customer_id' => {
|
||||
operator: 'is',
|
||||
value: user.id,
|
||||
},
|
||||
}
|
||||
user_tickets_closed = Ticket.search(
|
||||
limit: limit,
|
||||
|
@ -451,8 +463,14 @@ class TicketsController < ApplicationController
|
|||
if params[:organization_id] && !params[:organization_id].empty?
|
||||
|
||||
condition = {
|
||||
'tickets.state_id' => Ticket::State.by_category('open'),
|
||||
'tickets.organization_id' => params[:organization_id],
|
||||
'tickets.state_id' => {
|
||||
operator: 'is',
|
||||
value: Ticket::State.by_category('open').map(&:id),
|
||||
},
|
||||
'tickets.organization_id' => {
|
||||
operator: 'is',
|
||||
value: params[:organization_id],
|
||||
},
|
||||
}
|
||||
org_tickets_open = Ticket.search(
|
||||
limit: limit,
|
||||
|
@ -463,8 +481,14 @@ class TicketsController < ApplicationController
|
|||
|
||||
# lookup closed org tickets
|
||||
condition = {
|
||||
'tickets.state_id' => Ticket::State.by_category('closed'),
|
||||
'tickets.organization_id' => params[:organization_id],
|
||||
'tickets.state_id' => {
|
||||
operator: 'is',
|
||||
value: Ticket::State.by_category('closed').map(&:id),
|
||||
},
|
||||
'tickets.organization_id' => {
|
||||
operator: 'is',
|
||||
value: params[:organization_id],
|
||||
},
|
||||
}
|
||||
org_tickets_closed = Ticket.search(
|
||||
limit: limit,
|
||||
|
|
|
@ -6,5 +6,19 @@ class Overview < ApplicationModel
|
|||
store :view
|
||||
validates :name, presence: true
|
||||
validates :prio, presence: true
|
||||
validates :link, presence: true
|
||||
|
||||
before_create :fill_link
|
||||
before_update :fill_link
|
||||
|
||||
private
|
||||
|
||||
# fill link
|
||||
def fill_link
|
||||
return true if link && !link.empty?
|
||||
self.link = name.downcase
|
||||
link.gsub!(/\s/, '_')
|
||||
link.gsub!(/[^0-9a-z]/i, '_')
|
||||
link.gsub!(/_+/, '_')
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -270,9 +270,10 @@ returns
|
|||
|
||||
def self.selectors(selectors, limit = 10)
|
||||
return if !selectors
|
||||
query, bind_params = _selectors(selectors)
|
||||
ticket_count = Ticket.where(query, *bind_params).count
|
||||
tickets = Ticket.where(query, *bind_params).limit(limit)
|
||||
query, bind_params, tables = _selectors(selectors)
|
||||
return [] if !query
|
||||
ticket_count = Ticket.where(query, *bind_params).joins(tables).count
|
||||
tickets = Ticket.where(query, *bind_params).joins(tables).limit(limit)
|
||||
[ticket_count, tickets]
|
||||
end
|
||||
|
||||
|
@ -281,6 +282,15 @@ returns
|
|||
query = ''
|
||||
bind_params = []
|
||||
|
||||
tables = []
|
||||
selectors.each {|attribute, selector|
|
||||
selector = attribute.split(/\./)
|
||||
next if !selector[1]
|
||||
next if selector[0] == 'ticket'
|
||||
next if tables.include?(selector[0])
|
||||
tables.push selector[0].to_sym
|
||||
}
|
||||
|
||||
selectors.each {|attribute, selector|
|
||||
if query != ''
|
||||
query += ' AND '
|
||||
|
@ -289,7 +299,9 @@ returns
|
|||
next if !selector.respond_to?(:key?)
|
||||
next if !selector['operator']
|
||||
return nil if !selector['value']
|
||||
return nil if selector['value'].respond_to?(:key?) && selector['value'].empty?
|
||||
return nil if selector['value'].respond_to?(:empty?) && selector['value'].empty?
|
||||
attributes = attribute.split(/\./)
|
||||
attribute = "#{attributes[0]}s.#{attributes[1]}"
|
||||
if selector['operator'] == 'is'
|
||||
query += "#{attribute} IN (?)"
|
||||
bind_params.push selector['value']
|
||||
|
@ -304,14 +316,23 @@ returns
|
|||
query += "#{attribute} NOT LIKE (?)"
|
||||
value = "%#{selector['value']}%"
|
||||
bind_params.push value
|
||||
elsif selector['operator'] == 'before'
|
||||
query += "#{attribute} <= (?)"
|
||||
elsif selector['operator'] == 'before (absolute)'
|
||||
query += "#{attribute} <= ?"
|
||||
bind_params.push selector['value']
|
||||
elsif selector['operator'] == 'after (absolute)'
|
||||
query += "#{attribute} >= ?"
|
||||
bind_params.push selector['value']
|
||||
elsif selector['operator'] == 'before (relative)'
|
||||
query += "#{attribute} <= ?"
|
||||
bind_params.push Time.zone.now - selector['value'].to_i.minutes
|
||||
elsif selector['operator'] == 'after (relative)'
|
||||
query += "#{attribute} >= ?"
|
||||
bind_params.push Time.zone.now + selector['value'].to_i.minutes
|
||||
else
|
||||
fail "Invalid operator '#{selector['operator']}' for '#{selector['value'].inspect}'"
|
||||
end
|
||||
}
|
||||
[query, bind_params]
|
||||
[query, bind_params, tables]
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -39,16 +39,16 @@ returns
|
|||
selected overview by user
|
||||
|
||||
result = Ticket::Overviews.list(
|
||||
:current_user => User.find(123),
|
||||
:view => 'some_view_url',
|
||||
current_user: User.find(123),
|
||||
view: 'some_view_url',
|
||||
)
|
||||
|
||||
returns
|
||||
|
||||
result = {
|
||||
:tickets => tickets, # [ticket1, ticket2, ticket3]
|
||||
:tickets_count => tickets_count, # count of tickets
|
||||
:overview => overview_selected_raw, # overview attributes
|
||||
tickets: tickets, # [ticket1, ticket2, ticket3]
|
||||
tickets_count: tickets_count, # count of tickets
|
||||
overview: overview_selected_raw, # overview attributes
|
||||
}
|
||||
|
||||
=end
|
||||
|
@ -71,18 +71,29 @@ returns
|
|||
end
|
||||
|
||||
# replace e.g. 'current_user.id' with current_user.id
|
||||
overview.condition.each { |item, value|
|
||||
overview.condition.each { |attribute, content|
|
||||
next if !content
|
||||
next if !content.respond_to?(:key?)
|
||||
next if !content['value']
|
||||
next if content['value'].class != String && content['value'].class != Array
|
||||
|
||||
next if !value
|
||||
next if value.class.to_s != 'String'
|
||||
if content['value'].class == String
|
||||
parts = content['value'].split( '.', 2 )
|
||||
next if !parts[0]
|
||||
next if !parts[1]
|
||||
next if parts[0] != 'current_user'
|
||||
overview.condition[attribute]['value'] = data[:current_user][parts[1].to_sym]
|
||||
next
|
||||
end
|
||||
|
||||
parts = value.split( '.', 2 )
|
||||
|
||||
next if !parts[0]
|
||||
next if !parts[1]
|
||||
next if parts[0] != 'current_user'
|
||||
|
||||
overview.condition[item] = data[:current_user][parts[1].to_sym]
|
||||
content['value'].each {|item|
|
||||
next if item.class != String
|
||||
parts = item.split('.', 2)
|
||||
next if !parts[0]
|
||||
next if !parts[1]
|
||||
next if parts[0] != 'current_user'
|
||||
item = data[:current_user][parts[1].to_sym]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,37 +101,8 @@ returns
|
|||
fail "No such view '#{data[:view]}'"
|
||||
end
|
||||
|
||||
# sortby
|
||||
# prio
|
||||
# state
|
||||
# group
|
||||
# customer
|
||||
|
||||
# order
|
||||
# asc
|
||||
# desc
|
||||
|
||||
# groupby
|
||||
# prio
|
||||
# state
|
||||
# group
|
||||
# customer
|
||||
|
||||
# all = attributes[:myopenassigned]
|
||||
# all.merge( { :group_id => groups } )
|
||||
|
||||
# @tickets = Ticket.where(:group_id => groups, attributes[:myopenassigned] ).limit(params[:limit])
|
||||
# get only tickets with permissions
|
||||
if data[:current_user].role?('Customer')
|
||||
group_ids = Group.select( 'groups.id' )
|
||||
.where( 'groups.active = ?', true )
|
||||
.map( &:id )
|
||||
else
|
||||
group_ids = Group.select( 'groups.id' ).joins(:users)
|
||||
.where( 'groups_users.user_id = ?', [ data[:current_user].id ] )
|
||||
.where( 'groups.active = ?', true )
|
||||
.map( &:id )
|
||||
end
|
||||
access_condition = Ticket.access_condition( data[:current_user] )
|
||||
|
||||
# overview meta for navbar
|
||||
if !overview_selected
|
||||
|
@ -129,8 +111,10 @@ returns
|
|||
result = []
|
||||
overviews.each { |overview|
|
||||
|
||||
query_condition, bind_condition = Ticket._selectors(overview.condition)
|
||||
|
||||
# get count
|
||||
count = Ticket.where( group_id: group_ids ).where( _condition( overview.condition ) ).count()
|
||||
count = Ticket.where( access_condition ).where( query_condition, *bind_condition ).count()
|
||||
|
||||
# get meta info
|
||||
all = {
|
||||
|
@ -151,9 +135,12 @@ returns
|
|||
if overview_selected.group_by && !overview_selected.group_by.empty?
|
||||
order_by = overview_selected.group_by + '_id, ' + order_by
|
||||
end
|
||||
tickets = Ticket.select( 'id' )
|
||||
.where( group_id: group_ids )
|
||||
.where( _condition( overview_selected.condition ) )
|
||||
|
||||
query_condition, bind_condition = Ticket._selectors(overview_selected.condition)
|
||||
|
||||
tickets = Ticket.select('id')
|
||||
.where( access_condition )
|
||||
.where( query_condition, *bind_condition )
|
||||
.order( order_by )
|
||||
.limit( 500 )
|
||||
|
||||
|
@ -162,9 +149,7 @@ returns
|
|||
ticket_ids.push ticket.id
|
||||
}
|
||||
|
||||
tickets_count = Ticket.where( group_id: group_ids )
|
||||
.where( _condition( overview_selected.condition ) )
|
||||
.count()
|
||||
tickets_count = Ticket.where( access_condition ).where( query_condition, *bind_condition ).count()
|
||||
|
||||
return {
|
||||
ticket_ids: ticket_ids,
|
||||
|
@ -175,15 +160,12 @@ returns
|
|||
|
||||
# get tickets for overview
|
||||
data[:start_page] ||= 1
|
||||
tickets = Ticket.where( group_id: group_ids )
|
||||
.where( _condition( overview_selected.condition ) )
|
||||
query_condition, bind_condition = Ticket._selectors(overview_selected.condition)
|
||||
tickets = Ticket.where( access_condition )
|
||||
.where( query_condition, *bind_condition )
|
||||
.order( overview_selected[:order][:by].to_s + ' ' + overview_selected[:order][:direction].to_s )
|
||||
# .limit( overview_selected.view[ data[:view_mode].to_sym ][:per_page] )
|
||||
# .offset( overview_selected.view[ data[:view_mode].to_sym ][:per_page].to_i * ( data[:start_page].to_i - 1 ) )
|
||||
|
||||
tickets_count = Ticket.where( group_id: group_ids )
|
||||
.where( _condition( overview_selected.condition ) )
|
||||
.count()
|
||||
tickets_count = Ticket.where( access_condition ).where( query_condition, *bind_condition ).count()
|
||||
|
||||
{
|
||||
tickets: tickets,
|
||||
|
@ -192,64 +174,4 @@ returns
|
|||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self._condition(condition)
|
||||
sql = ''
|
||||
bind = [nil]
|
||||
condition.each {|key, value|
|
||||
if sql != ''
|
||||
sql += ' AND '
|
||||
end
|
||||
if value.class == Array
|
||||
sql += " #{key} IN (?)"
|
||||
bind.push value
|
||||
elsif value.class == Hash || value.class == ActiveSupport::HashWithIndifferentAccess
|
||||
time = Time.zone.now
|
||||
if value['area'] == 'minute'
|
||||
if value['direction'] == 'last'
|
||||
time -= value['count'].to_i * 60
|
||||
else
|
||||
time += value['count'].to_i * 60
|
||||
end
|
||||
elsif value['area'] == 'hour'
|
||||
if value['direction'] == 'last'
|
||||
time -= value['count'].to_i * 60 * 60
|
||||
else
|
||||
time += value['count'].to_i * 60 * 60
|
||||
end
|
||||
elsif value['area'] == 'day'
|
||||
if value['direction'] == 'last'
|
||||
time -= value['count'].to_i * 60 * 60 * 24
|
||||
else
|
||||
time += value['count'].to_i * 60 * 60 * 24
|
||||
end
|
||||
elsif value['area'] == 'month'
|
||||
if value['direction'] == 'last'
|
||||
time -= value['count'].to_i * 60 * 60 * 24 * 31
|
||||
else
|
||||
time += value['count'].to_i * 60 * 60 * 24 * 31
|
||||
end
|
||||
elsif value['area'] == 'year'
|
||||
if value['direction'] == 'last'
|
||||
time -= value['count'].to_i * 60 * 60 * 24 * 365
|
||||
else
|
||||
time += value['count'].to_i * 60 * 60 * 24 * 365
|
||||
end
|
||||
end
|
||||
if value['direction'] == 'last'
|
||||
sql += " #{key} > ?"
|
||||
bind.push time
|
||||
else
|
||||
sql += " #{key} < ?"
|
||||
bind.push time
|
||||
end
|
||||
else
|
||||
sql += " #{key} = ?"
|
||||
bind.push value
|
||||
end
|
||||
}
|
||||
bind[0] = sql
|
||||
bind
|
||||
end
|
||||
end
|
||||
|
|
|
@ -59,14 +59,20 @@ search tickets via database
|
|||
result = Ticket.search(
|
||||
current_user: User.find(123),
|
||||
condition: {
|
||||
'tickets.owner_id' => user.id,
|
||||
'tickets.state_id' => Ticket::State.where(
|
||||
state_type_id: Ticket::StateType.where(
|
||||
name: [
|
||||
'pending reminder',
|
||||
'pending action',
|
||||
],
|
||||
),
|
||||
'tickets.owner_id' => {
|
||||
operator: 'is',
|
||||
value: user.id,
|
||||
},
|
||||
'tickets.state_id' => {
|
||||
operator: 'is',
|
||||
value: Ticket::State.where(
|
||||
state_type_id: Ticket::StateType.where(
|
||||
name: [
|
||||
'pending reminder',
|
||||
'pending action',
|
||||
],
|
||||
).map(&:id),
|
||||
},
|
||||
),
|
||||
},
|
||||
limit: 15,
|
||||
|
@ -154,9 +160,10 @@ returns
|
|||
.order('`tickets`.`created_at` DESC')
|
||||
.limit(limit)
|
||||
else
|
||||
query_condition, bind_condition = _selectors(params[:condition])
|
||||
tickets_all = Ticket.select('DISTINCT(tickets.id)')
|
||||
.where(access_condition)
|
||||
.where(params[:condition])
|
||||
.where(query_condition, *bind_condition)
|
||||
.order('`tickets`.`created_at` DESC')
|
||||
.limit(limit)
|
||||
end
|
||||
|
|
218
db/migrate/20150973000001_update_overview3.rb
Normal file
218
db/migrate/20150973000001_update_overview3.rb
Normal file
|
@ -0,0 +1,218 @@
|
|||
class UpdateOverview3 < ActiveRecord::Migration
|
||||
def up
|
||||
UserInfo.current_user_id = 1
|
||||
overview_role = Role.where( name: 'Agent' ).first
|
||||
Overview.create_or_update(
|
||||
name: 'My assigned Tickets',
|
||||
link: 'my_assigned',
|
||||
prio: 1000,
|
||||
role_id: overview_role.id,
|
||||
condition: {
|
||||
'ticket.state_id' => {
|
||||
operator: 'is',
|
||||
value: [ 1, 2, 3, 7 ],
|
||||
},
|
||||
'ticket.owner_id' => {
|
||||
operator: 'is',
|
||||
value: 'current_user.id',
|
||||
},
|
||||
},
|
||||
order: {
|
||||
by: 'created_at',
|
||||
direction: 'ASC',
|
||||
},
|
||||
view: {
|
||||
d: %w(title customer group created_at),
|
||||
s: %w(title customer group created_at),
|
||||
m: %w(number title customer group created_at),
|
||||
view_mode_default: 's',
|
||||
},
|
||||
)
|
||||
|
||||
Overview.create_or_update(
|
||||
name: 'My pending reached Tickets',
|
||||
link: 'my_pending_reached',
|
||||
prio: 1010,
|
||||
role_id: overview_role.id,
|
||||
condition: {
|
||||
'ticket.state_id' => {
|
||||
operator: 'is',
|
||||
value: 3,
|
||||
},
|
||||
'ticket.owner_id' => {
|
||||
operator: 'is',
|
||||
value: 'current_user.id',
|
||||
},
|
||||
'ticket.pending_time' => {
|
||||
operator: 'after (relative)',
|
||||
value: '1',
|
||||
},
|
||||
},
|
||||
order: {
|
||||
by: 'created_at',
|
||||
direction: 'ASC',
|
||||
},
|
||||
view: {
|
||||
d: %w(title customer group created_at),
|
||||
s: %w(title customer group created_at),
|
||||
m: %w(number title customer group created_at),
|
||||
view_mode_default: 's',
|
||||
},
|
||||
)
|
||||
|
||||
Overview.create_or_update(
|
||||
name: 'Unassigned & Open Tickets',
|
||||
link: 'all_unassigned',
|
||||
prio: 1020,
|
||||
role_id: overview_role.id,
|
||||
condition: {
|
||||
'ticket.state_id' => {
|
||||
operator: 'is',
|
||||
value: [1, 2, 3],
|
||||
},
|
||||
'ticket.owner_id' => {
|
||||
operator: 'is',
|
||||
value: 1,
|
||||
},
|
||||
},
|
||||
order: {
|
||||
by: 'created_at',
|
||||
direction: 'ASC',
|
||||
},
|
||||
view: {
|
||||
d: %w(title customer group created_at),
|
||||
s: %w(title customer group created_at),
|
||||
m: %w(number title customer group created_at),
|
||||
view_mode_default: 's',
|
||||
},
|
||||
)
|
||||
|
||||
Overview.create_or_update(
|
||||
name: 'All Open Tickets',
|
||||
link: 'all_open',
|
||||
prio: 1030,
|
||||
role_id: overview_role.id,
|
||||
condition: {
|
||||
'ticket.state_id' => {
|
||||
operator: 'is',
|
||||
value: [1, 2, 3],
|
||||
},
|
||||
},
|
||||
order: {
|
||||
by: 'created_at',
|
||||
direction: 'ASC',
|
||||
},
|
||||
view: {
|
||||
d: %w(title customer group state owner created_at),
|
||||
s: %w(title customer group state owner created_at),
|
||||
m: %w(number title customer group state owner created_at),
|
||||
view_mode_default: 's',
|
||||
},
|
||||
)
|
||||
|
||||
Overview.create_or_update(
|
||||
name: 'All pending reached Tickets',
|
||||
link: 'all_pending_reached',
|
||||
prio: 1035,
|
||||
role_id: overview_role.id,
|
||||
condition: {
|
||||
'ticket.state_id' => {
|
||||
operator: 'is',
|
||||
value: [3],
|
||||
},
|
||||
'ticket.pending_time' => {
|
||||
operator: 'after (relative)',
|
||||
value: 1,
|
||||
},
|
||||
},
|
||||
order: {
|
||||
by: 'created_at',
|
||||
direction: 'ASC',
|
||||
},
|
||||
view: {
|
||||
d: %w(title customer group owner created_at),
|
||||
s: %w(title customer group owner created_at),
|
||||
m: %w(number title customer group owner created_at),
|
||||
view_mode_default: 's',
|
||||
},
|
||||
)
|
||||
|
||||
Overview.create_or_update(
|
||||
name: 'Escalated Tickets',
|
||||
link: 'all_escalated',
|
||||
prio: 1040,
|
||||
role_id: overview_role.id,
|
||||
condition: {
|
||||
'ticket.escalation_time' => {
|
||||
operator: 'before (relative)',
|
||||
value: 5,
|
||||
},
|
||||
},
|
||||
order: {
|
||||
by: 'escalation_time',
|
||||
direction: 'ASC',
|
||||
},
|
||||
view: {
|
||||
d: %w(title customer group owner escalation_time),
|
||||
s: %w(title customer group owner escalation_time),
|
||||
m: %w(number title customer group owner escalation_time),
|
||||
view_mode_default: 's',
|
||||
},
|
||||
)
|
||||
|
||||
overview_role = Role.where( name: 'Customer' ).first
|
||||
Overview.create_or_update(
|
||||
name: 'My Tickets',
|
||||
link: 'my_tickets',
|
||||
prio: 1000,
|
||||
role_id: overview_role.id,
|
||||
condition: {
|
||||
'ticket.state_id' => {
|
||||
operator: 'is',
|
||||
value: [ 1, 2, 3, 4, 6 ],
|
||||
},
|
||||
'ticket.customer_id' => {
|
||||
operator: 'is',
|
||||
value: 'current_user.id',
|
||||
},
|
||||
},
|
||||
order: {
|
||||
by: 'created_at',
|
||||
direction: 'DESC',
|
||||
},
|
||||
view: {
|
||||
d: %w(title customer state created_at),
|
||||
s: %w(number title state created_at),
|
||||
m: %w(number title state created_at),
|
||||
view_mode_default: 's',
|
||||
},
|
||||
)
|
||||
Overview.create_or_update(
|
||||
name: 'My Organization Tickets',
|
||||
link: 'my_organization_tickets',
|
||||
prio: 1100,
|
||||
role_id: overview_role.id,
|
||||
organization_shared: true,
|
||||
condition: {
|
||||
'ticket.state_id' => {
|
||||
operator: 'is',
|
||||
value: [ 1, 2, 3, 4, 6 ],
|
||||
},
|
||||
'ticket.organization_id' => {
|
||||
operator: 'is',
|
||||
value: 'current_user.organization_id',
|
||||
},
|
||||
},
|
||||
order: {
|
||||
by: 'created_at',
|
||||
direction: 'DESC',
|
||||
},
|
||||
view: {
|
||||
d: %w(title customer state created_at),
|
||||
s: %w(number title customer state created_at),
|
||||
m: %w(number title customer state created_at),
|
||||
view_mode_default: 's',
|
||||
},
|
||||
)
|
||||
end
|
||||
end
|
75
db/seeds.rb
75
db/seeds.rb
|
@ -1575,8 +1575,14 @@ Overview.create_if_not_exists(
|
|||
prio: 1000,
|
||||
role_id: overview_role.id,
|
||||
condition: {
|
||||
'tickets.state_id' => [ 1, 2, 3, 7 ],
|
||||
'tickets.owner_id' => 'current_user.id',
|
||||
'ticket.state_id' => {
|
||||
operator: 'is',
|
||||
value: [ 1, 2, 3, 7 ],
|
||||
},
|
||||
'ticket.owner_id' => {
|
||||
operator: 'is',
|
||||
value: current_user.id,
|
||||
},
|
||||
},
|
||||
order: {
|
||||
by: 'created_at',
|
||||
|
@ -1596,9 +1602,18 @@ Overview.create_if_not_exists(
|
|||
prio: 1010,
|
||||
role_id: overview_role.id,
|
||||
condition: {
|
||||
'tickets.state_id' => [3],
|
||||
'tickets.owner_id' => 'current_user.id',
|
||||
'tickets.pending_time' => { 'direction' => 'before', 'count' => 1, 'area' => 'minute' },
|
||||
'ticket.state_id' => {
|
||||
operator: 'is',
|
||||
value: 3,
|
||||
},
|
||||
'ticket.owner_id' => {
|
||||
operator: 'is',
|
||||
value: 'current_user.id',
|
||||
},
|
||||
'ticket.pending_time' => {
|
||||
operator: 'after (relative)',
|
||||
value: '1',
|
||||
},
|
||||
},
|
||||
order: {
|
||||
by: 'created_at',
|
||||
|
@ -1618,8 +1633,14 @@ Overview.create_if_not_exists(
|
|||
prio: 1020,
|
||||
role_id: overview_role.id,
|
||||
condition: {
|
||||
'tickets.state_id' => [1, 2, 3],
|
||||
'tickets.owner_id' => 1,
|
||||
'ticket.state_id' => {
|
||||
operator: 'is',
|
||||
value: [1, 2, 3],
|
||||
},
|
||||
'ticket.owner_id' => {
|
||||
operator: 'is',
|
||||
value: 1,
|
||||
},
|
||||
},
|
||||
order: {
|
||||
by: 'created_at',
|
||||
|
@ -1639,7 +1660,10 @@ Overview.create_if_not_exists(
|
|||
prio: 1030,
|
||||
role_id: overview_role.id,
|
||||
condition: {
|
||||
'tickets.state_id' => [1, 2, 3],
|
||||
'ticket.state_id' => {
|
||||
operator: 'is',
|
||||
value: [1, 2, 3],
|
||||
},
|
||||
},
|
||||
order: {
|
||||
by: 'created_at',
|
||||
|
@ -1659,8 +1683,14 @@ Overview.create_if_not_exists(
|
|||
prio: 1035,
|
||||
role_id: overview_role.id,
|
||||
condition: {
|
||||
'tickets.state_id' => [3],
|
||||
'tickets.pending_time' => { 'direction' => 'before', 'count' => 1, 'area' => 'minute' },
|
||||
'ticket.state_id' => {
|
||||
operator: 'is',
|
||||
value: [3],
|
||||
},
|
||||
'ticket.pending_time' => {
|
||||
operator: 'after (relative)',
|
||||
value: 1,
|
||||
},
|
||||
},
|
||||
order: {
|
||||
by: 'created_at',
|
||||
|
@ -1680,7 +1710,10 @@ Overview.create_if_not_exists(
|
|||
prio: 1040,
|
||||
role_id: overview_role.id,
|
||||
condition: {
|
||||
'tickets.escalation_time' => { 'direction' => 'before', 'count' => 5, 'area' => 'minute' },
|
||||
'ticket.escalation_time' => {
|
||||
operator: 'before (relative)',
|
||||
value: 5,
|
||||
},
|
||||
},
|
||||
order: {
|
||||
by: 'escalation_time',
|
||||
|
@ -1701,8 +1734,14 @@ Overview.create_if_not_exists(
|
|||
prio: 1000,
|
||||
role_id: overview_role.id,
|
||||
condition: {
|
||||
'tickets.state_id' => [ 1, 2, 3, 4, 6 ],
|
||||
'tickets.customer_id' => 'current_user.id',
|
||||
'ticket.state_id' => {
|
||||
operator: 'is',
|
||||
value: [ 1, 2, 3, 4, 6 ],
|
||||
},
|
||||
'ticket.customer_id' => {
|
||||
operator: 'is',
|
||||
value: 'current_user.id',
|
||||
},
|
||||
},
|
||||
order: {
|
||||
by: 'created_at',
|
||||
|
@ -1722,8 +1761,14 @@ Overview.create_if_not_exists(
|
|||
role_id: overview_role.id,
|
||||
organization_shared: true,
|
||||
condition: {
|
||||
'tickets.state_id' => [ 1, 2, 3, 4, 6 ],
|
||||
'tickets.organization_id' => 'current_user.organization_id',
|
||||
'ticket.state_id' => {
|
||||
operator: 'is',
|
||||
value: [ 1, 2, 3, 4, 6 ],
|
||||
},
|
||||
'ticket.organization_id' => {
|
||||
operator: 'is',
|
||||
value: 'current_user.organization_id',
|
||||
},
|
||||
},
|
||||
order: {
|
||||
by: 'created_at',
|
||||
|
|
|
@ -46,12 +46,18 @@ class CalendarSubscriptions::Tickets
|
|||
return events_data if owner_ids.empty?
|
||||
|
||||
condition = {
|
||||
'tickets.owner_id' => owner_ids,
|
||||
'tickets.state_id' => Ticket::State.where(
|
||||
state_type_id: Ticket::StateType.where(
|
||||
name: %w(new open),
|
||||
),
|
||||
),
|
||||
'tickets.owner_id' => {
|
||||
operator: 'is',
|
||||
value: owner_ids,
|
||||
},
|
||||
'tickets.state_id' => {
|
||||
operator: 'is',
|
||||
value: Ticket::State.where(
|
||||
state_type_id: Ticket::StateType.where(
|
||||
name: %w(new open),
|
||||
),
|
||||
).map(&:id),
|
||||
},
|
||||
}
|
||||
|
||||
tickets = Ticket.search(
|
||||
|
@ -87,15 +93,21 @@ class CalendarSubscriptions::Tickets
|
|||
return events_data if owner_ids.empty?
|
||||
|
||||
condition = {
|
||||
'tickets.owner_id' => owner_ids,
|
||||
'tickets.state_id' => Ticket::State.where(
|
||||
state_type_id: Ticket::StateType.where(
|
||||
name: [
|
||||
'pending reminder',
|
||||
'pending action',
|
||||
],
|
||||
),
|
||||
),
|
||||
'tickets.owner_id' => {
|
||||
operator: 'is',
|
||||
value: owner_ids,
|
||||
},
|
||||
'tickets.state_id' => {
|
||||
operator: 'is',
|
||||
value: Ticket::State.where(
|
||||
state_type_id: Ticket::StateType.where(
|
||||
name: [
|
||||
'pending reminder',
|
||||
'pending action',
|
||||
],
|
||||
),
|
||||
).map(&:id),
|
||||
},
|
||||
}
|
||||
|
||||
tickets = Ticket.search(
|
||||
|
@ -137,9 +149,16 @@ class CalendarSubscriptions::Tickets
|
|||
owner_ids = owner_ids(:escalation)
|
||||
return events_data if owner_ids.empty?
|
||||
|
||||
condition = [
|
||||
'tickets.owner_id IN (?) AND tickets.escalation_time IS NOT NULL', owner_ids
|
||||
]
|
||||
condition = {
|
||||
'tickets.owner_id' => {
|
||||
operator: 'is',
|
||||
value: owner_ids,
|
||||
},
|
||||
'tickets.escalation_time' => {
|
||||
operator: 'is not',
|
||||
value: nil,
|
||||
}
|
||||
}
|
||||
|
||||
tickets = Ticket.search(
|
||||
current_user: @user,
|
||||
|
|
Loading…
Reference in a new issue