Moved to generic App.CollectionController for Tasks and OnlineNotifications controller.
This commit is contained in:
parent
ada5538e1b
commit
0af243514b
14 changed files with 1057 additions and 279 deletions
|
@ -487,25 +487,28 @@ class App.Controller extends Spine.Controller
|
||||||
|
|
||||||
prepareForObjectList: (items) ->
|
prepareForObjectList: (items) ->
|
||||||
for item in items
|
for item in items
|
||||||
|
item = @prepareForObjectListItem(item)
|
||||||
item.link = ''
|
|
||||||
item.title = '???'
|
|
||||||
|
|
||||||
# convert backend name space to local name space
|
|
||||||
item.object = item.object.replace('::', '')
|
|
||||||
|
|
||||||
# lookup real data
|
|
||||||
if App[item.object] && App[item.object].exists(item.o_id)
|
|
||||||
object = App[item.object].find(item.o_id)
|
|
||||||
item.objectNative = object
|
|
||||||
item.link = object.uiUrl()
|
|
||||||
item.title = object.displayName()
|
|
||||||
item.object_name = object.objectDisplayName()
|
|
||||||
item.cssIcon = object.iconActivity(@Session.get())
|
|
||||||
|
|
||||||
item.created_by = App.User.find(item.created_by_id)
|
|
||||||
items
|
items
|
||||||
|
|
||||||
|
prepareForObjectListItem: (item) ->
|
||||||
|
item.link = ''
|
||||||
|
item.title = '???'
|
||||||
|
|
||||||
|
# convert backend name space to local name space
|
||||||
|
item.object = item.object.replace('::', '')
|
||||||
|
|
||||||
|
# lookup real data
|
||||||
|
if App[item.object] && App[item.object].exists(item.o_id)
|
||||||
|
object = App[item.object].find(item.o_id)
|
||||||
|
item.objectNative = object
|
||||||
|
item.link = object.uiUrl()
|
||||||
|
item.title = object.displayName()
|
||||||
|
item.object_name = object.objectDisplayName()
|
||||||
|
item.cssIcon = object.iconActivity(@Session.get())
|
||||||
|
|
||||||
|
item.created_by = App.User.find(item.created_by_id)
|
||||||
|
item
|
||||||
|
|
||||||
# central method, is getting called on every ticket form change
|
# central method, is getting called on every ticket form change
|
||||||
ticketFormChanges: (params, attribute, attributes, classname, form, ui) =>
|
ticketFormChanges: (params, attribute, attributes, classname, form, ui) =>
|
||||||
if @formMeta.dependencies && @formMeta.dependencies[attribute.name]
|
if @formMeta.dependencies && @formMeta.dependencies[attribute.name]
|
||||||
|
|
|
@ -740,3 +740,311 @@ class App.WizardFullScreen extends App.WizardModal
|
||||||
super
|
super
|
||||||
$('.content').addClass('hide')
|
$('.content').addClass('hide')
|
||||||
$('#content').removeClass('hide')
|
$('#content').removeClass('hide')
|
||||||
|
|
||||||
|
class App.CollectionController extends App.Controller
|
||||||
|
events:
|
||||||
|
'click .js-remove': 'remove'
|
||||||
|
'click .js-item': 'click'
|
||||||
|
'click .js-locationVerify': 'location'
|
||||||
|
observe:
|
||||||
|
field1: true
|
||||||
|
field2: false
|
||||||
|
#currentItems: {}
|
||||||
|
#1:
|
||||||
|
# a: 123
|
||||||
|
# b: 'some string'
|
||||||
|
#2:
|
||||||
|
# a: 123
|
||||||
|
# b: 'some string'
|
||||||
|
#renderList: {}
|
||||||
|
#1: ..dom..ref..
|
||||||
|
#2: ..dom..ref..
|
||||||
|
template: '_need_to_be_defined_'
|
||||||
|
uniqKey: 'id'
|
||||||
|
model: '_need_to_be_defined_'
|
||||||
|
sortBy: 'name'
|
||||||
|
order: 'ASC',
|
||||||
|
|
||||||
|
constructor: ->
|
||||||
|
@events = @constructor.events unless @events
|
||||||
|
@observe = @constructor.observe unless @observe
|
||||||
|
@currentItems = {}
|
||||||
|
@renderList = {}
|
||||||
|
@queue = []
|
||||||
|
@queueRunning = false
|
||||||
|
@lastOrder = []
|
||||||
|
|
||||||
|
super
|
||||||
|
|
||||||
|
@queue.push ['renderAll']
|
||||||
|
@uIRunner()
|
||||||
|
|
||||||
|
# bind to changes
|
||||||
|
if @model
|
||||||
|
@subscribeId = App[@model].subscribe(@collectionSync)
|
||||||
|
|
||||||
|
# render on generic ui call
|
||||||
|
@bind('ui:rerender', =>
|
||||||
|
@queue.push ['renderAll']
|
||||||
|
@uIRunner()
|
||||||
|
)
|
||||||
|
|
||||||
|
# render on login
|
||||||
|
@bind('auth:login', =>
|
||||||
|
@queue.push ['renderAll']
|
||||||
|
@uIRunner()
|
||||||
|
)
|
||||||
|
|
||||||
|
# reset current tasks on logout
|
||||||
|
@bind('auth:logout', =>
|
||||||
|
@queue.push ['renderAll']
|
||||||
|
@uIRunner()
|
||||||
|
)
|
||||||
|
|
||||||
|
@log 'debug', 'Init @uniqKey', @uniqKey
|
||||||
|
@log 'debug', 'Init @observe', @observe
|
||||||
|
@log 'debug', 'Init @model', @model
|
||||||
|
|
||||||
|
release: =>
|
||||||
|
if @subscribeId
|
||||||
|
App[@model].unsubscribe(@subscribeId)
|
||||||
|
|
||||||
|
uIRunner: ->
|
||||||
|
return if !@queue[0]
|
||||||
|
return if @queueRunning
|
||||||
|
@queueRunning = true
|
||||||
|
loop
|
||||||
|
param = @queue.shift()
|
||||||
|
if param[0] is 'domChange'
|
||||||
|
@domChange(param[1])
|
||||||
|
else if param[0] is 'domRemove'
|
||||||
|
@domRemove(param[1])
|
||||||
|
else if param[0] is 'renderAll'
|
||||||
|
@renderAll()
|
||||||
|
if !@queue[0]
|
||||||
|
@onRenderEnd()
|
||||||
|
@queueRunning = false
|
||||||
|
break
|
||||||
|
|
||||||
|
collectionOrderGet: =>
|
||||||
|
newOrder = []
|
||||||
|
all = @itemsAll()
|
||||||
|
for item in all
|
||||||
|
newOrder.push item[@uniqKey]
|
||||||
|
newOrder
|
||||||
|
|
||||||
|
collectionOrderSet: (newOrder = false) =>
|
||||||
|
if !newOrder
|
||||||
|
newOrder = @collectionOrderGet()
|
||||||
|
@lastOrder = newOrder
|
||||||
|
|
||||||
|
collectionSync: (items, type) =>
|
||||||
|
console.log('collectionSync', items, type)
|
||||||
|
|
||||||
|
# remove items
|
||||||
|
if type is 'destroy'
|
||||||
|
ids = []
|
||||||
|
for item in items
|
||||||
|
ids.push item.id
|
||||||
|
@queue.push ['domRemove', ids]
|
||||||
|
@uIRunner()
|
||||||
|
return
|
||||||
|
|
||||||
|
# inital render
|
||||||
|
if _.isEmpty(@renderList)
|
||||||
|
@queue.push ['renderAll']
|
||||||
|
@uIRunner()
|
||||||
|
return
|
||||||
|
|
||||||
|
# check if item order is the same
|
||||||
|
newOrder = @collectionOrderGet()
|
||||||
|
removedIds = _.difference(@lastOrder, newOrder)
|
||||||
|
addedIds = _.difference(newOrder, @lastOrder)
|
||||||
|
|
||||||
|
@log 'debug', 'collectionSync removedIds', removedIds
|
||||||
|
@log 'debug', 'collectionSync addedIds', addedIds
|
||||||
|
@log 'debug', 'collectionSync @lastOrder', @lastOrder
|
||||||
|
@log 'debug', 'collectionSync newOrder', newOrder
|
||||||
|
|
||||||
|
# add items
|
||||||
|
alreadyRemoved = false
|
||||||
|
if !_.isEmpty(addedIds)
|
||||||
|
lastOrderNew = []
|
||||||
|
for id in @lastOrder
|
||||||
|
if !_.contains(removedIds, id)
|
||||||
|
lastOrderNew.push id
|
||||||
|
|
||||||
|
# try to find positions of new items
|
||||||
|
applyOrder = App.Utils.diffPositionAdd(lastOrderNew, newOrder)
|
||||||
|
if !applyOrder
|
||||||
|
@queue.push ['renderAll']
|
||||||
|
@uIRunner()
|
||||||
|
return
|
||||||
|
|
||||||
|
if !_.isEmpty(removedIds)
|
||||||
|
alreadyRemoved = true
|
||||||
|
@queue.push ['domRemove', removedIds]
|
||||||
|
@uIRunner()
|
||||||
|
|
||||||
|
newItems = []
|
||||||
|
for apply in applyOrder
|
||||||
|
item = App[@model].find(apply.id)
|
||||||
|
item.meta_position = apply.position
|
||||||
|
newItems.push item
|
||||||
|
@queue.push ['domChange', newItems]
|
||||||
|
@uIRunner()
|
||||||
|
|
||||||
|
# remove items
|
||||||
|
if !alreadyRemoved && !_.isEmpty(removedIds)
|
||||||
|
@queue.push ['domRemove', removedIds]
|
||||||
|
@uIRunner()
|
||||||
|
|
||||||
|
# update items
|
||||||
|
newItems = []
|
||||||
|
for item in items
|
||||||
|
if !_.contains(removedIds, item.id) && !_.contains(addedIds, item.id)
|
||||||
|
newItems.push item
|
||||||
|
return if _.isEmpty(newItems)
|
||||||
|
@queue.push ['domChange', newItems]
|
||||||
|
@uIRunner()
|
||||||
|
#return
|
||||||
|
|
||||||
|
# rerender all items
|
||||||
|
#@queue.push ['renderAll']
|
||||||
|
#@uIRunner()
|
||||||
|
|
||||||
|
domRemove: (ids) =>
|
||||||
|
@log 'debug', 'domRemove', ids
|
||||||
|
for id in ids
|
||||||
|
@itemAttributesDelete(id)
|
||||||
|
if @renderList[id]
|
||||||
|
@renderList[id].remove()
|
||||||
|
delete @renderList[id]
|
||||||
|
@onRemoved(id)
|
||||||
|
@collectionOrderSet()
|
||||||
|
|
||||||
|
domChange: (items) =>
|
||||||
|
@log 'debug', 'domChange items', items
|
||||||
|
@log 'debug', 'domChange @currentItems', @currentItems
|
||||||
|
changedItems = []
|
||||||
|
for item in items
|
||||||
|
@log 'debug', 'domChange|item', item
|
||||||
|
attributes = @itemAttributes(item)
|
||||||
|
currentItem = @itemAttributesGet(item[@uniqKey])
|
||||||
|
if !currentItem
|
||||||
|
@log 'debug', 'domChange|add', item
|
||||||
|
changedItems.push item
|
||||||
|
@itemAttributesSet(item[@uniqKey], attributes)
|
||||||
|
else
|
||||||
|
@log 'debug', 'domChange|change', item
|
||||||
|
@log 'debug', 'domChange|change|observe attributes', @observe
|
||||||
|
@log 'debug', 'domChange|change|current', currentItem
|
||||||
|
@log 'debug', 'domChange|change|new', attributes
|
||||||
|
for field of @observe
|
||||||
|
@log 'debug', 'domChange|change|compare', field, currentItem[field], attributes[field]
|
||||||
|
diff = !_.isEqual(currentItem[field], attributes[field])
|
||||||
|
@log 'debug', 'domChange|diff', diff, item
|
||||||
|
if diff
|
||||||
|
changedItems.push item
|
||||||
|
@itemAttributesSet(item[@uniqKey], attributes)
|
||||||
|
break
|
||||||
|
return if _.isEmpty(changedItems)
|
||||||
|
@renderParts(changedItems)
|
||||||
|
|
||||||
|
renderAll: =>
|
||||||
|
items = @itemsAll()
|
||||||
|
@log 'debug', 'renderAll', items
|
||||||
|
localeEls = []
|
||||||
|
for item in items
|
||||||
|
attributes = @itemAttributes(item)
|
||||||
|
@itemAttributesSet(item[@uniqKey], attributes)
|
||||||
|
localeEls.push @renderItem(item, false)
|
||||||
|
@html localeEls
|
||||||
|
@collectionOrderSet()
|
||||||
|
@onRenderEnd()
|
||||||
|
|
||||||
|
itemsAll: =>
|
||||||
|
#App[@model].all()
|
||||||
|
App[@model].search(sortBy: @sortBy, order: @order)
|
||||||
|
|
||||||
|
itemAttributesDiff: (item) =>
|
||||||
|
attributes = @itemAttributes(item)
|
||||||
|
currentItem = @itemAttributesGet(item[@uniqKey])
|
||||||
|
for field of @observe
|
||||||
|
@log 'debug', 'itemAttributesDiff|compare', field, currentItem[field], attributes[field]
|
||||||
|
diff = !_.isEqual(currentItem[field], attributes[field])
|
||||||
|
if diff
|
||||||
|
@log 'debug', 'itemAttributesDiff|diff', diff
|
||||||
|
return true
|
||||||
|
false
|
||||||
|
|
||||||
|
itemAttributesDelete: (id) =>
|
||||||
|
delete @currentItems[id]
|
||||||
|
|
||||||
|
itemAttributesGet: (id) =>
|
||||||
|
@currentItems[id]
|
||||||
|
|
||||||
|
itemAttributesSet: (id, attributes) =>
|
||||||
|
@currentItems[id] = attributes
|
||||||
|
|
||||||
|
itemAttributes: (item) =>
|
||||||
|
attributes = {}
|
||||||
|
for field of @observe
|
||||||
|
attributes[field] = item[field]
|
||||||
|
attributes
|
||||||
|
|
||||||
|
renderParts: (items) =>
|
||||||
|
@log 'debug', 'renderParts', items
|
||||||
|
for item in items
|
||||||
|
if !@renderList[item[@uniqKey]]
|
||||||
|
@renderItem(item)
|
||||||
|
else
|
||||||
|
@renderItem(item, @renderList[item[@uniqKey]])
|
||||||
|
@collectionOrderSet()
|
||||||
|
|
||||||
|
renderItem: (item, el) =>
|
||||||
|
if @prepareForObjectListItemSupport
|
||||||
|
item = @prepareForObjectListItem(item)
|
||||||
|
@log 'debug', 'renderItem', item, @template, el, @renderList[item[@uniqKey]]
|
||||||
|
html = $(App.view(@template)(
|
||||||
|
item: item
|
||||||
|
))
|
||||||
|
@renderList[item[@uniqKey]] = html
|
||||||
|
if el is false
|
||||||
|
return html
|
||||||
|
else if !el
|
||||||
|
position = item.meta_position + 1
|
||||||
|
console.log('!el', item, position, item.meta_position)
|
||||||
|
#if item.meta_position
|
||||||
|
@el.find(".js-item:nth-child(#{position})").before(html)
|
||||||
|
else
|
||||||
|
el.replaceWith(html)
|
||||||
|
|
||||||
|
onRenderEnd: ->
|
||||||
|
# nothing
|
||||||
|
|
||||||
|
location: (e) ->
|
||||||
|
@locationVerify(e)
|
||||||
|
|
||||||
|
click: (e) =>
|
||||||
|
row = $(e.target).closest('.js-item')
|
||||||
|
id = row.data('id')
|
||||||
|
console.log('click id', id)
|
||||||
|
@onClick(id, e)
|
||||||
|
|
||||||
|
onClick: (id, e) ->
|
||||||
|
# nothing
|
||||||
|
|
||||||
|
remove: (e) =>
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
row = $(e.target).closest('.js-item')
|
||||||
|
id = row.data('id')
|
||||||
|
@onRemove(id,e)
|
||||||
|
App[@model].destroy(id)
|
||||||
|
|
||||||
|
onRemove: (id, e) ->
|
||||||
|
# nothing
|
||||||
|
|
||||||
|
onRemoved: (id) ->
|
||||||
|
# nothing
|
||||||
|
|
|
@ -1,37 +1,19 @@
|
||||||
class App.TaskbarWidget extends App.Controller
|
class App.TaskbarWidget extends App.CollectionController
|
||||||
events:
|
events:
|
||||||
'click .js-close': 'remove'
|
'click .js-close': 'remove'
|
||||||
'click .js-locationVerify': 'location'
|
'click .js-locationVerify': 'location'
|
||||||
fields:
|
|
||||||
observe:
|
model: false
|
||||||
field1: true
|
|
||||||
field2: false
|
|
||||||
meta: true
|
|
||||||
active: true
|
|
||||||
notify: true
|
|
||||||
observeNot:
|
|
||||||
field1: true
|
|
||||||
field2: false
|
|
||||||
currentItems: {}
|
|
||||||
#1:
|
|
||||||
# a: 123
|
|
||||||
# b: 'some string'
|
|
||||||
#2:
|
|
||||||
# a: 123
|
|
||||||
# b: 'some string'
|
|
||||||
renderList: {}
|
|
||||||
#1: ..dom..ref..
|
|
||||||
#2: ..dom..ref..
|
|
||||||
template: 'widget/task_item'
|
template: 'widget/task_item'
|
||||||
|
uniqKey: 'key'
|
||||||
|
observe:
|
||||||
|
meta: true
|
||||||
|
active: true
|
||||||
|
notify: true
|
||||||
|
|
||||||
constructor: ->
|
constructor: ->
|
||||||
super
|
super
|
||||||
|
|
||||||
@queue = []
|
|
||||||
@queueRunning = false
|
|
||||||
|
|
||||||
@renderAll()
|
|
||||||
|
|
||||||
dndOptions =
|
dndOptions =
|
||||||
tolerance: 'pointer'
|
tolerance: 'pointer'
|
||||||
distance: 15
|
distance: 15
|
||||||
|
@ -51,108 +33,24 @@ class App.TaskbarWidget extends App.Controller
|
||||||
@el.sortable(dndOptions)
|
@el.sortable(dndOptions)
|
||||||
|
|
||||||
# bind to changes
|
# bind to changes
|
||||||
@bind('taskInit', => @renderAll())
|
@bind('taskInit', =>
|
||||||
|
console.log('renderAll aaa')
|
||||||
|
@renderAll()
|
||||||
|
console.log('renderAll bbb')
|
||||||
|
#@queue.push ['renderAll']
|
||||||
|
#@uIRunner()
|
||||||
|
)
|
||||||
@bind('taskUpdate', (tasks) =>
|
@bind('taskUpdate', (tasks) =>
|
||||||
@queue.push ['taskUpdate', tasks]
|
@queue.push ['domChange', tasks]
|
||||||
@uIRunner()
|
@uIRunner()
|
||||||
)
|
)
|
||||||
@bind('taskRemove', (task_ids) =>
|
@bind('taskRemove', (task_ids) =>
|
||||||
@queue.push ['checkRemoves', task_ids]
|
@queue.push ['domRemove', task_ids]
|
||||||
@uIRunner()
|
@uIRunner()
|
||||||
)
|
)
|
||||||
|
|
||||||
# render on generic ui call
|
itemsAll: ->
|
||||||
@bind('ui:rerender', =>
|
App.TaskManager.allWithMeta()
|
||||||
@queue.push ['renderAll']
|
|
||||||
@uIRunner()
|
|
||||||
)
|
|
||||||
|
|
||||||
# render on login
|
|
||||||
@bind('auth:login', =>
|
|
||||||
@queue.push ['renderAll']
|
|
||||||
@uIRunner()
|
|
||||||
)
|
|
||||||
|
|
||||||
# reset current tasks on logout
|
|
||||||
@bind('auth:logout', =>
|
|
||||||
@queue.push ['renderAll']
|
|
||||||
@uIRunner()
|
|
||||||
)
|
|
||||||
|
|
||||||
uIRunner: ->
|
|
||||||
return if !@queue[0]
|
|
||||||
return if @queueRunning
|
|
||||||
@queueRunning = true
|
|
||||||
loop
|
|
||||||
param = @queue.shift()
|
|
||||||
if param[0] is 'taskUpdate'
|
|
||||||
@checkChanges(param[1])
|
|
||||||
else if param[0] is 'checkRemoves'
|
|
||||||
@checkRemoves(param[1])
|
|
||||||
else if param[0] is 'renderAll'
|
|
||||||
@renderAll()
|
|
||||||
if !@queue[0]
|
|
||||||
@queueRunning = false
|
|
||||||
break
|
|
||||||
|
|
||||||
checkRemoves: (keys) ->
|
|
||||||
for key in keys
|
|
||||||
delete @currentItems[key]
|
|
||||||
if @renderList[key]
|
|
||||||
@renderList[key].remove()
|
|
||||||
delete @renderList[key]
|
|
||||||
|
|
||||||
checkChanges: (items) ->
|
|
||||||
changedItems = []
|
|
||||||
for item in items
|
|
||||||
attributes = {}
|
|
||||||
for field of @fields.observe
|
|
||||||
attributes[field] = item[field]
|
|
||||||
#console.log('item', item)
|
|
||||||
#attributes = item.attributes()
|
|
||||||
#console.log('item', @fields.observe, item, attributes)
|
|
||||||
if !@currentItems[item.key]
|
|
||||||
changedItems.push item
|
|
||||||
@currentItems[item.key] = attributes
|
|
||||||
else
|
|
||||||
currentItem = @currentItems[item.key]
|
|
||||||
hit = false
|
|
||||||
for field of @fields.observe
|
|
||||||
diff = _.isEqual(currentItem[field], attributes[field])
|
|
||||||
#console.log('diff', field, diff, currentItem[field], attributes[field])
|
|
||||||
if !hit && diff
|
|
||||||
changedItems.push item
|
|
||||||
@currentItems[item.key] = attributes
|
|
||||||
hit = true
|
|
||||||
return if _.isEmpty(changedItems)
|
|
||||||
@renderParts(changedItems)
|
|
||||||
|
|
||||||
renderAll: ->
|
|
||||||
#@html ''
|
|
||||||
items = App.TaskManager.allWithMeta()
|
|
||||||
localeEls = []
|
|
||||||
for item in items
|
|
||||||
localeEls.push @renderItem(item, false)
|
|
||||||
@html localeEls
|
|
||||||
|
|
||||||
renderParts: (items) ->
|
|
||||||
for item in items
|
|
||||||
if !@renderList[item.key]
|
|
||||||
@renderItem(item)
|
|
||||||
else
|
|
||||||
@renderItem(item, @renderList[item.key])
|
|
||||||
|
|
||||||
renderItem: (item, el) ->
|
|
||||||
html = $(App.view(@template)(
|
|
||||||
item: item
|
|
||||||
))
|
|
||||||
@renderList[item.key] = html
|
|
||||||
if el is false
|
|
||||||
return html
|
|
||||||
else if !el
|
|
||||||
@el.append(html)
|
|
||||||
else
|
|
||||||
el.replaceWith(html)
|
|
||||||
|
|
||||||
location: (e) =>
|
location: (e) =>
|
||||||
return if !$(e.currentTarget).hasClass('is-modified')
|
return if !$(e.currentTarget).hasClass('is-modified')
|
||||||
|
|
|
@ -7,13 +7,11 @@ class App.OnlineNotificationWidget extends App.Controller
|
||||||
|
|
||||||
events:
|
events:
|
||||||
'click .js-mark': 'markAllAsRead'
|
'click .js-mark': 'markAllAsRead'
|
||||||
'click .js-item': 'hide'
|
|
||||||
'click .js-remove': 'removeItem'
|
|
||||||
'click .js-locationVerify': 'onItemClick'
|
|
||||||
'click': 'stopPropagation'
|
'click': 'stopPropagation'
|
||||||
|
|
||||||
elements:
|
elements:
|
||||||
'.js-mark': 'mark'
|
'.js-mark': 'mark'
|
||||||
|
'.js-noNotifications': 'noNotifications'
|
||||||
'.js-item': 'item'
|
'.js-item': 'item'
|
||||||
'.js-content': 'content'
|
'.js-content': 'content'
|
||||||
'.js-header': 'header'
|
'.js-header': 'header'
|
||||||
|
@ -25,7 +23,7 @@ class App.OnlineNotificationWidget extends App.Controller
|
||||||
@bind 'OnlineNotification::changed', =>
|
@bind 'OnlineNotification::changed', =>
|
||||||
@delay(
|
@delay(
|
||||||
=> @fetch()
|
=> @fetch()
|
||||||
2600
|
2200
|
||||||
'online-notification-changed'
|
'online-notification-changed'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -48,20 +46,10 @@ class App.OnlineNotificationWidget extends App.Controller
|
||||||
if !@access()
|
if !@access()
|
||||||
@counterUpdate(0)
|
@counterUpdate(0)
|
||||||
return
|
return
|
||||||
if !@subscribeId
|
|
||||||
@subscribeId = App.OnlineNotification.subscribe(@updateContent)
|
|
||||||
|
|
||||||
if @access()
|
|
||||||
@subscribeId = App.OnlineNotification.subscribe(@updateContent)
|
|
||||||
|
|
||||||
@bind('ui:reshow', =>
|
|
||||||
@show()
|
|
||||||
'popover'
|
|
||||||
)
|
|
||||||
|
|
||||||
$(window).on 'click.notifications', @hide
|
$(window).on 'click.notifications', @hide
|
||||||
|
|
||||||
@updateContent()
|
@createContainer()
|
||||||
|
|
||||||
release: ->
|
release: ->
|
||||||
$(window).off 'click.notifications'
|
$(window).off 'click.notifications'
|
||||||
|
@ -84,14 +72,15 @@ class App.OnlineNotificationWidget extends App.Controller
|
||||||
@nudge(e, 1)
|
@nudge(e, 1)
|
||||||
return
|
return
|
||||||
else if e.keyCode is 13 # enter
|
else if e.keyCode is 13 # enter
|
||||||
@item.filter('.is-hover').find('.js-locationVerify').click()
|
@$('.js-item').filter('.is-hover').find('.js-locationVerify').click()
|
||||||
|
|
||||||
nudge: (e, position) ->
|
nudge: (e, position) ->
|
||||||
|
|
||||||
# get current
|
# get current
|
||||||
current = @item.filter('.is-hover')
|
items = @$('.js-item')
|
||||||
|
current = items.filter('.is-hover')
|
||||||
if !current.size()
|
if !current.size()
|
||||||
@item.first().addClass('is-hover')
|
items.first().addClass('is-hover')
|
||||||
return
|
return
|
||||||
|
|
||||||
if position is 1
|
if position is 1
|
||||||
|
@ -110,27 +99,41 @@ class App.OnlineNotificationWidget extends App.Controller
|
||||||
if prev
|
if prev
|
||||||
@scrollToIfNeeded(prev, true)
|
@scrollToIfNeeded(prev, true)
|
||||||
|
|
||||||
counterUpdate: (count) =>
|
counterUpdate: (count, force = false) =>
|
||||||
count = '' if count is 0
|
count = '' if count is 0
|
||||||
|
|
||||||
|
return if !force && @count is count
|
||||||
|
@count = count
|
||||||
|
|
||||||
$('.js-notificationsCounter').text(count)
|
$('.js-notificationsCounter').text(count)
|
||||||
App.Event.trigger('online_notification_counter', count.toString())
|
App.Event.trigger('online_notification_counter', count.toString())
|
||||||
|
|
||||||
@count = count
|
|
||||||
|
|
||||||
# show mark all as read if needed
|
# show mark all as read if needed
|
||||||
if !count
|
if !count
|
||||||
@mark.addClass('hidden')
|
@mark.addClass('hide')
|
||||||
else
|
else
|
||||||
@mark.removeClass('hidden')
|
@mark.removeClass('hide')
|
||||||
|
|
||||||
markAllAsRead: (event) ->
|
counterGen: (force = false) =>
|
||||||
event.preventDefault()
|
items = App.OnlineNotification.all()
|
||||||
|
count = 0
|
||||||
|
for item in items
|
||||||
|
if !item.seen
|
||||||
|
count++
|
||||||
|
@counterUpdate(count, force)
|
||||||
|
|
||||||
|
if _.isEmpty(items)
|
||||||
|
@noNotifications.removeClass('hide')
|
||||||
|
else
|
||||||
|
@noNotifications.addClass('hide')
|
||||||
|
|
||||||
|
markAllAsRead: (e) ->
|
||||||
|
e.preventDefault()
|
||||||
@counterUpdate(0)
|
@counterUpdate(0)
|
||||||
@ajax(
|
@ajax(
|
||||||
id: 'markAllAsRead'
|
id: 'markAllAsRead'
|
||||||
type: 'POST'
|
type: 'POST'
|
||||||
url: @apiPath + '/online_notifications/mark_all_as_read'
|
url: "#{@apiPath}/online_notifications/mark_all_as_read"
|
||||||
data: JSON.stringify('')
|
data: JSON.stringify('')
|
||||||
processData: true
|
processData: true
|
||||||
)
|
)
|
||||||
|
@ -143,13 +146,14 @@ class App.OnlineNotificationWidget extends App.Controller
|
||||||
heightPopoverHeader = @header.outerHeight(true)
|
heightPopoverHeader = @header.outerHeight(true)
|
||||||
isOverflowing = false
|
isOverflowing = false
|
||||||
heightPopoverContent = 0
|
heightPopoverContent = 0
|
||||||
@item.each (i, el) =>
|
@$('.js-item').each (i, el) =>
|
||||||
|
|
||||||
# accumulate height of items
|
# accumulate height of items
|
||||||
heightPopoverContent += el.clientHeight
|
heightPopoverContent += el.clientHeight
|
||||||
|
|
||||||
if (heightPopoverHeader + heightPopoverContent + heightPopoverSpacer) > heightApp
|
if (heightPopoverHeader + heightPopoverContent + heightPopoverSpacer) > heightApp
|
||||||
@content.css 'height', heightApp - heightPopoverHeader - heightPopoverSpacer
|
containerHeight = heightApp - heightPopoverHeader - heightPopoverSpacer
|
||||||
|
@content.css 'height', containerHeight
|
||||||
isOverflowing = true
|
isOverflowing = true
|
||||||
return false # exit .each loop
|
return false # exit .each loop
|
||||||
|
|
||||||
|
@ -160,7 +164,6 @@ class App.OnlineNotificationWidget extends App.Controller
|
||||||
load = (data) =>
|
load = (data) =>
|
||||||
@fetchedData = true
|
@fetchedData = true
|
||||||
App.OnlineNotification.refresh(data.stream, clear: true)
|
App.OnlineNotification.refresh(data.stream, clear: true)
|
||||||
@updateContent()
|
|
||||||
App.OnlineNotification.fetchFull(load)
|
App.OnlineNotification.fetchFull(load)
|
||||||
|
|
||||||
toggle: =>
|
toggle: =>
|
||||||
|
@ -169,43 +172,23 @@ class App.OnlineNotificationWidget extends App.Controller
|
||||||
else
|
else
|
||||||
@show()
|
@show()
|
||||||
|
|
||||||
updateContent: =>
|
createContainer: =>
|
||||||
if !@Session.get()
|
if !@Session.get()
|
||||||
@content.html('')
|
@content.html('')
|
||||||
return
|
return
|
||||||
|
|
||||||
items = App.OnlineNotification.search(sortBy: 'created_at', order: 'DESC')
|
count = ''
|
||||||
@count = 0
|
localeEl = $( App.view('widget/online_notification')(
|
||||||
for item in items
|
count: count
|
||||||
if !item.seen
|
))
|
||||||
@count++
|
|
||||||
|
|
||||||
@counterUpdate(@count)
|
new App.OnlineNotificationContentWidget(
|
||||||
|
el: localeEl.find('.js-items')
|
||||||
# update content
|
container: @
|
||||||
items = @prepareForObjectList(items)
|
|
||||||
|
|
||||||
# generate desktop notifications
|
|
||||||
for item in items
|
|
||||||
if !@alreadyShown[item.id]
|
|
||||||
@alreadyShown[item.id] = true
|
|
||||||
if @fetchedData
|
|
||||||
if item.objectNative && item.objectNative.activityMessage
|
|
||||||
title = item.objectNative.activityMessage(item)
|
|
||||||
else
|
|
||||||
title = "Need objectNative in item #{item.object}.find(#{item.o_id})"
|
|
||||||
title = App.Utils.html2text(title.replace(/<.+?>/g, '"'))
|
|
||||||
@notifyDesktop(
|
|
||||||
url: item.link
|
|
||||||
title: title
|
|
||||||
)
|
|
||||||
App.OnlineNotification.play()
|
|
||||||
|
|
||||||
@html App.view('widget/online_notification')(
|
|
||||||
items: items
|
|
||||||
count: @count
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@html localeEl
|
||||||
|
@counterGen(true)
|
||||||
return if !@shown
|
return if !@shown
|
||||||
@show()
|
@show()
|
||||||
|
|
||||||
|
@ -221,20 +204,43 @@ class App.OnlineNotificationWidget extends App.Controller
|
||||||
@shown = false
|
@shown = false
|
||||||
@el.hide()
|
@el.hide()
|
||||||
|
|
||||||
onItemClick: (e) ->
|
|
||||||
@locationVerify(e)
|
|
||||||
@hide()
|
|
||||||
|
|
||||||
stopPropagation: (e) ->
|
stopPropagation: (e) ->
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
|
||||||
removeItem: (e) =>
|
|
||||||
e.preventDefault()
|
|
||||||
e.stopPropagation()
|
|
||||||
row = $(e.target).closest('.js-item')
|
|
||||||
id = row.data('id')
|
|
||||||
App.OnlineNotification.destroy(id)
|
|
||||||
@updateHeight()
|
|
||||||
|
|
||||||
remove: =>
|
remove: =>
|
||||||
@el.remove()
|
@el.remove()
|
||||||
|
|
||||||
|
class App.OnlineNotificationContentWidget extends App.CollectionController
|
||||||
|
model: 'OnlineNotification'
|
||||||
|
template: 'widget/online_notification_item'
|
||||||
|
prepareForObjectListItemSupport: true
|
||||||
|
observe:
|
||||||
|
seen: true
|
||||||
|
sortBy: 'created_at'
|
||||||
|
order: 'DESC'
|
||||||
|
alreadyShown: {}
|
||||||
|
|
||||||
|
onRenderEnd: ->
|
||||||
|
@container.counterGen()
|
||||||
|
@container.updateHeight()
|
||||||
|
|
||||||
|
# generate desktop notifications
|
||||||
|
items = App.OnlineNotification.search(sortBy: 'created_at', order: 'DESC')
|
||||||
|
for item in items
|
||||||
|
if !@alreadyShown[item.id]
|
||||||
|
@alreadyShown[item.id] = true
|
||||||
|
if @container.fetchedData
|
||||||
|
item = @prepareForObjectListItem(item)
|
||||||
|
if item.objectNative && item.objectNative.activityMessage
|
||||||
|
title = item.objectNative.activityMessage(item)
|
||||||
|
else
|
||||||
|
title = "Need objectNative in item #{item.object}.find(#{item.o_id})"
|
||||||
|
title = App.Utils.html2text(title.replace(/<.+?>/g, '"'))
|
||||||
|
@notifyDesktop(
|
||||||
|
url: item.link
|
||||||
|
title: title
|
||||||
|
)
|
||||||
|
App.OnlineNotification.play()
|
||||||
|
|
||||||
|
onClick: ->
|
||||||
|
@container.hide()
|
||||||
|
|
|
@ -61,7 +61,7 @@ class _collectionSingleton extends Spine.Module
|
||||||
return
|
return
|
||||||
|
|
||||||
# reset in-memory
|
# reset in-memory
|
||||||
appObject.refresh(params.data, { clear: true })
|
appObject.refresh(params.data, clear: true)
|
||||||
|
|
||||||
loadAssets: (assets) ->
|
loadAssets: (assets) ->
|
||||||
@log 'debug', 'loadAssets', assets
|
@log 'debug', 'loadAssets', assets
|
||||||
|
|
|
@ -626,3 +626,26 @@ class App.Utils
|
||||||
$outer.remove()
|
$outer.remove()
|
||||||
|
|
||||||
return 100 - widthWithScroll
|
return 100 - widthWithScroll
|
||||||
|
|
||||||
|
@diffPositionAdd: (a, b) ->
|
||||||
|
applyOrder = []
|
||||||
|
newOrderMethod = (a, b, applyOrder) ->
|
||||||
|
for position of b
|
||||||
|
if a[position] isnt b[position]
|
||||||
|
|
||||||
|
# changes to complex, whole rerender
|
||||||
|
if _.contains(a, b[position])
|
||||||
|
return false
|
||||||
|
|
||||||
|
# insert new item and try next
|
||||||
|
a.splice(position, 0, b[position])
|
||||||
|
apply =
|
||||||
|
position: parseInt(position)
|
||||||
|
id: b[position]
|
||||||
|
applyOrder.push apply
|
||||||
|
newOrderMethod(a, b, applyOrder)
|
||||||
|
true
|
||||||
|
|
||||||
|
result = newOrderMethod(a, b, applyOrder)
|
||||||
|
return false if !result
|
||||||
|
applyOrder
|
||||||
|
|
|
@ -309,11 +309,33 @@ class App.Model extends Spine.Model
|
||||||
|
|
||||||
# subscribe and render data / fetch new data if triggered
|
# subscribe and render data / fetch new data if triggered
|
||||||
@bind(
|
@bind(
|
||||||
'refresh change remove'
|
'refresh'
|
||||||
(items) =>
|
(items, options) =>
|
||||||
App.Log.debug('Model', "local collection refresh/change #{@className}", items)
|
if !_.isArray(items)
|
||||||
|
items = [items]
|
||||||
|
console.log('refresh', items, options)
|
||||||
|
App.Log.debug('Model', "local collection refresh #{@className}", items)
|
||||||
for key, callback of @SUBSCRIPTION_COLLECTION
|
for key, callback of @SUBSCRIPTION_COLLECTION
|
||||||
callback(items)
|
callback(items, 'refresh')
|
||||||
|
)
|
||||||
|
@bind(
|
||||||
|
'change'
|
||||||
|
(items, subEvent) =>
|
||||||
|
return if subEvent is 'destroy'
|
||||||
|
if !_.isArray(items)
|
||||||
|
items = [items]
|
||||||
|
App.Log.debug('Model', "local collection change #{@className}", items)
|
||||||
|
for key, callback of @SUBSCRIPTION_COLLECTION
|
||||||
|
callback(items, 'change')
|
||||||
|
)
|
||||||
|
@bind(
|
||||||
|
'destroy'
|
||||||
|
(items) =>
|
||||||
|
if !_.isArray(items)
|
||||||
|
items = [items]
|
||||||
|
App.Log.debug('Model', "local collection destroy #{@className}", items)
|
||||||
|
for key, callback of @SUBSCRIPTION_COLLECTION
|
||||||
|
callback(items, 'destroy')
|
||||||
)
|
)
|
||||||
|
|
||||||
# fetch() all on network notify
|
# fetch() all on network notify
|
||||||
|
|
|
@ -1,37 +1,11 @@
|
||||||
<div class="arrow js-arrow"></div>
|
<div class="arrow js-arrow"></div>
|
||||||
<div class="popover-notificationsHeader js-header">
|
<div class="popover-notificationsHeader js-header">
|
||||||
<div class="popover-title"><%- @T('Notifications') %> <span class='popover-notificationsCounter js-notificationsCounter'><%- @count %></span></div>
|
<div class="popover-title"><%- @T('Notifications') %> <span class='popover-notificationsCounter js-notificationsCounter'><%- @count %></span></div>
|
||||||
<a class="btn btn--text btn--subtle js-mark<%- ' hidden' if !@count %>"><%- @T( 'Mark all as read' ) %></a>
|
<a class="btn btn--text btn--subtle js-mark<%- ' hide' if !@count %>"><%- @T( 'Mark all as read' ) %></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="popover-content js-content">
|
<div class="popover-content js-content">
|
||||||
<% if @items.length: %>
|
<div class="activity-placeholder js-noNotifications">
|
||||||
<% for item in @items: %>
|
<%- @T("No unread Notifications for you. :) ") %>
|
||||||
<div class="js-item activity-entry activity-entry--removeable<% if item.seen: %> is-inactive<% end %>" data-id="<%- item.id %>">
|
</div>
|
||||||
<a class="activity-avatar user-popover" data-id="<%= item.created_by_id %>" <% if item.created_by_id isnt 1: %>href="<%- item.created_by.uiUrl() %>"<% end %>>
|
<div class="js-items"></div>
|
||||||
<%- item.created_by.avatar() %>
|
|
||||||
</a>
|
|
||||||
<div class="activity-body">
|
|
||||||
<a class="activity-message js-locationVerify" href="<%- item.link %>">
|
|
||||||
<span class="activity-text">
|
|
||||||
<% if item.objectNative && item.objectNative.activityMessage: %>
|
|
||||||
<%- item.objectNative.activityMessage(item) %>
|
|
||||||
<% else: %>
|
|
||||||
Need objectNative in item <%= item.object %>.find(<%= item.o_id %>)
|
|
||||||
<% end %>
|
|
||||||
</span>
|
|
||||||
<%- @humanTime(item.created_at, false, 'activity-time') %>
|
|
||||||
</a>
|
|
||||||
<div class="activity-remove js-remove">
|
|
||||||
<div class="activity-remove-icon-holder">
|
|
||||||
<%- @Icon('diagonal-cross') %>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
<% else: %>
|
|
||||||
<div class="activity-placeholder">
|
|
||||||
<%- @T("No unread Notifications for you. :) ") %>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
</div>
|
|
@ -1,30 +0,0 @@
|
||||||
<% if @items.length: %>
|
|
||||||
<% for item in @items: %>
|
|
||||||
<div class="activity-entry activity-entry--removeable<% if item.seen: %> is-inactive<% end %>" data-id="<%- item.id %>">
|
|
||||||
<a class="activity-avatar user-popover" data-id="<%= item.created_by_id %>" <% if item.created_by_id isnt 1: %>href="<%- item.created_by.uiUrl() %>"<% end %>>
|
|
||||||
<%- item.created_by.avatar() %>
|
|
||||||
</a>
|
|
||||||
<div class="activity-body">
|
|
||||||
<a class="activity-message js-locationVerify" href="<%- item.link %>">
|
|
||||||
<span class="activity-text">
|
|
||||||
<% if item.objectNative && item.objectNative.activityMessage: %>
|
|
||||||
<%- item.objectNative.activityMessage(item) %>
|
|
||||||
<% else: %>
|
|
||||||
Need objectNative in item <%= item.object %>.find(<%= item.o_id %>)
|
|
||||||
<% end %>
|
|
||||||
</span>
|
|
||||||
<%- @humanTime(item.created_at, false, 'activity-time') %>
|
|
||||||
</a>
|
|
||||||
<div class="activity-remove js-remove">
|
|
||||||
<div class="activity-remove-icon-holder">
|
|
||||||
<%- @Icon('diagonal-cross') %>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
<% else: %>
|
|
||||||
<div class="activity-placeholder">
|
|
||||||
<%- @T("No unread Notifications for you. :) ") %>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
<div class="js-item activity-entry activity-entry--removeable<% if @item.seen: %> is-inactive<% end %>" data-id="<%- @item.id %>">
|
||||||
|
<a class="activity-avatar user-popover" data-id="<%= @item.created_by_id %>" <% if @item.created_by_id isnt 1: %>href="<%- @item.created_by.uiUrl() %>"<% end %>>
|
||||||
|
<%- @item.created_by.avatar() %>
|
||||||
|
</a>
|
||||||
|
<div class="activity-body">
|
||||||
|
<a class="activity-message js-locationVerify" href="<%- @item.link %>">
|
||||||
|
<span class="activity-text">
|
||||||
|
<% if @item.objectNative && @item.objectNative.activityMessage: %>
|
||||||
|
<%- @item.objectNative.activityMessage(@item) %>
|
||||||
|
<% else: %>
|
||||||
|
Need objectNative in item <%= @item.object %>.find(<%= @item.o_id %>)
|
||||||
|
<% end %>
|
||||||
|
</span>
|
||||||
|
<%- @humanTime(@item.created_at, false, 'activity-time') %>
|
||||||
|
</a>
|
||||||
|
<div class="activity-remove js-remove">
|
||||||
|
<div class="activity-remove-icon-holder">
|
||||||
|
<%- @Icon('diagonal-cross') %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -3730,6 +3730,7 @@ footer {
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.is-overflowing .popover-notificationsHeader {
|
&.is-overflowing .popover-notificationsHeader {
|
||||||
|
|
|
@ -1400,4 +1400,74 @@ test("check formatTime format", function() {
|
||||||
equal(verify, result, string)
|
equal(verify, result, string)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// check diffPosition
|
||||||
|
test("check diffPosition format", function() {
|
||||||
|
|
||||||
|
var a = [1,2,3,4]
|
||||||
|
var b = [1,2,3,4,5]
|
||||||
|
var result = [
|
||||||
|
{
|
||||||
|
position: 4,
|
||||||
|
id: 5,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
var verify = App.Utils.diffPositionAdd(a, b)
|
||||||
|
deepEqual(verify, result)
|
||||||
|
|
||||||
|
a = [2,3,4]
|
||||||
|
b = [1,2,3,4]
|
||||||
|
result = [
|
||||||
|
{
|
||||||
|
position: 0,
|
||||||
|
id: 1,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
verify = App.Utils.diffPositionAdd(a, b)
|
||||||
|
deepEqual(verify, result)
|
||||||
|
|
||||||
|
a = [2,3,4]
|
||||||
|
b = [1,2,3,4,5]
|
||||||
|
result = [
|
||||||
|
{
|
||||||
|
position: 0,
|
||||||
|
id: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
position: 4,
|
||||||
|
id: 5,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
verify = App.Utils.diffPositionAdd(a, b)
|
||||||
|
deepEqual(verify, result)
|
||||||
|
|
||||||
|
a = [2,3,4]
|
||||||
|
b = [1,99,12,2,3,4,5]
|
||||||
|
result = [
|
||||||
|
{
|
||||||
|
position: 0,
|
||||||
|
id: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
position: 1,
|
||||||
|
id: 99,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
position: 2,
|
||||||
|
id: 12,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
position: 6,
|
||||||
|
id: 5,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
verify = App.Utils.diffPositionAdd(a, b)
|
||||||
|
deepEqual(verify, result)
|
||||||
|
|
||||||
|
a = [4,3,1]
|
||||||
|
b = [1,2,3,4,5]
|
||||||
|
result = false
|
||||||
|
verify = App.Utils.diffPositionAdd(a, b)
|
||||||
|
deepEqual(verify, result)
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
393
test/browser/agent_ticket_actions_level9_test.rb
Normal file
393
test/browser/agent_ticket_actions_level9_test.rb
Normal file
|
@ -0,0 +1,393 @@
|
||||||
|
# encoding: utf-8
|
||||||
|
require 'browser_test_helper'
|
||||||
|
|
||||||
|
class AgentTicketActionLevel9Test < TestCase
|
||||||
|
|
||||||
|
def test_online_notifications
|
||||||
|
|
||||||
|
@browser = browser_instance
|
||||||
|
login(
|
||||||
|
username: 'master@example.com',
|
||||||
|
password: 'test',
|
||||||
|
url: browser_url,
|
||||||
|
)
|
||||||
|
tasks_close_all()
|
||||||
|
|
||||||
|
# create new ticket
|
||||||
|
ticket1 = ticket_create(
|
||||||
|
data: {
|
||||||
|
customer: 'nico',
|
||||||
|
group: 'Users',
|
||||||
|
title: 'online notification #1',
|
||||||
|
body: 'online notification #1',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
browser2 = browser_instance
|
||||||
|
login(
|
||||||
|
browser: browser2,
|
||||||
|
username: 'agent1@example.com',
|
||||||
|
password: 'test',
|
||||||
|
url: browser_url,
|
||||||
|
)
|
||||||
|
tasks_close_all(browser: browser2)
|
||||||
|
|
||||||
|
click(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-toggleNotifications',
|
||||||
|
)
|
||||||
|
click(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-mark',
|
||||||
|
)
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
# remove all notificatons
|
||||||
|
online_notitifcation_close_all(
|
||||||
|
browser: browser2,
|
||||||
|
)
|
||||||
|
|
||||||
|
exists_not(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-noNotifications.hide',
|
||||||
|
)
|
||||||
|
match(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-noNotifications',
|
||||||
|
value: 'No unread Notifications',
|
||||||
|
)
|
||||||
|
exists(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-mark.hide',
|
||||||
|
)
|
||||||
|
match_not(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-notificationsCounter',
|
||||||
|
value: '\d',
|
||||||
|
no_quote: true,
|
||||||
|
)
|
||||||
|
|
||||||
|
ticket2 = ticket_create(
|
||||||
|
data: {
|
||||||
|
customer: 'nico',
|
||||||
|
group: 'Users',
|
||||||
|
title: 'online notification #2',
|
||||||
|
body: 'online notification #2',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
watch_for(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-notificationsContainer .js-item',
|
||||||
|
value: 'online notification #2',
|
||||||
|
timeout: 10,
|
||||||
|
)
|
||||||
|
match(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-notificationsCounter',
|
||||||
|
value: '1',
|
||||||
|
)
|
||||||
|
|
||||||
|
exists_not(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-mark.hide',
|
||||||
|
)
|
||||||
|
|
||||||
|
ticket3 = ticket_create(
|
||||||
|
data: {
|
||||||
|
customer: 'nico',
|
||||||
|
group: 'Users',
|
||||||
|
title: 'online notification #3',
|
||||||
|
body: 'online notification #3',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
watch_for(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-notificationsContainer .js-item',
|
||||||
|
value: 'online notification #3',
|
||||||
|
timeout: 6,
|
||||||
|
)
|
||||||
|
watch_for(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-notificationsCounter',
|
||||||
|
value: '2',
|
||||||
|
)
|
||||||
|
|
||||||
|
items = browser2.find_elements(css: '.js-notificationsContainer .js-item')
|
||||||
|
count = items.count
|
||||||
|
assert_equal(2, count)
|
||||||
|
|
||||||
|
items[1].click
|
||||||
|
|
||||||
|
click(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-toggleNotifications',
|
||||||
|
)
|
||||||
|
|
||||||
|
watch_for(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-notificationsCounter',
|
||||||
|
value: '1',
|
||||||
|
)
|
||||||
|
|
||||||
|
items = browser2.find_elements(css: '.js-notificationsContainer .js-item')
|
||||||
|
assert_equal(2, items.count)
|
||||||
|
|
||||||
|
items = browser2.find_elements(css: '.js-notificationsContainer .js-item.is-inactive')
|
||||||
|
assert_equal(1, items.count)
|
||||||
|
|
||||||
|
ticket4 = ticket_create(
|
||||||
|
data: {
|
||||||
|
customer: 'nico',
|
||||||
|
group: 'Users',
|
||||||
|
title: 'online notification #4',
|
||||||
|
body: 'online notification #4',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
watch_for(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-notificationsCounter',
|
||||||
|
value: '2',
|
||||||
|
)
|
||||||
|
|
||||||
|
items = browser2.find_elements(css: '.js-notificationsContainer .js-item')
|
||||||
|
assert_equal(3, items.count)
|
||||||
|
|
||||||
|
items = browser2.find_elements(css: '.js-notificationsContainer .js-item.is-inactive')
|
||||||
|
assert_equal(1, items.count)
|
||||||
|
|
||||||
|
click(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-mark',
|
||||||
|
)
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
items = browser2.find_elements(css: '.js-notificationsContainer .js-item')
|
||||||
|
assert_equal(3, items.count)
|
||||||
|
|
||||||
|
items = browser2.find_elements(css: '.js-notificationsContainer .js-item.is-inactive')
|
||||||
|
assert_equal(3, items.count)
|
||||||
|
|
||||||
|
match_not(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-notificationsCounter',
|
||||||
|
value: '\d',
|
||||||
|
no_quote: true,
|
||||||
|
)
|
||||||
|
|
||||||
|
ticket5 = ticket_create(
|
||||||
|
data: {
|
||||||
|
customer: 'nico',
|
||||||
|
group: 'Users',
|
||||||
|
title: 'online notification #5',
|
||||||
|
body: 'online notification #5',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
watch_for(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-notificationsCounter',
|
||||||
|
value: '1',
|
||||||
|
)
|
||||||
|
|
||||||
|
items = browser2.find_elements(css: '.js-notificationsContainer .js-item')
|
||||||
|
assert_equal(4, items.count)
|
||||||
|
|
||||||
|
items = browser2.find_elements(css: '.js-notificationsContainer .js-item.is-inactive')
|
||||||
|
assert_equal(3, items.count)
|
||||||
|
|
||||||
|
# Note: title update will generate extra notification - so we will have 5
|
||||||
|
ticket_update(
|
||||||
|
data: {
|
||||||
|
title: 'online notification #5/5',
|
||||||
|
state: 'closed',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
watch_for(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-notificationsContainer .js-item',
|
||||||
|
value: 'online notification #5/5',
|
||||||
|
timeout: 20,
|
||||||
|
)
|
||||||
|
|
||||||
|
watch_for(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-notificationsContainer .js-item.is-inactive',
|
||||||
|
value: 'online notification #5/5',
|
||||||
|
timeout: 20,
|
||||||
|
)
|
||||||
|
|
||||||
|
match_not(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-notificationsCounter',
|
||||||
|
value: '\d',
|
||||||
|
no_quote: true,
|
||||||
|
)
|
||||||
|
|
||||||
|
items = browser2.find_elements(css: '.js-notificationsContainer .js-item')
|
||||||
|
assert_equal(6, items.count)
|
||||||
|
|
||||||
|
items = browser2.find_elements(css: '.js-notificationsContainer .js-item.is-inactive')
|
||||||
|
assert_equal(6, items.count)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_online_notifications_render
|
||||||
|
@browser = browser_instance
|
||||||
|
login(
|
||||||
|
username: 'master@example.com',
|
||||||
|
password: 'test',
|
||||||
|
url: browser_url,
|
||||||
|
)
|
||||||
|
tasks_close_all()
|
||||||
|
|
||||||
|
browser2 = browser_instance
|
||||||
|
login(
|
||||||
|
browser: browser2,
|
||||||
|
username: 'agent1@example.com',
|
||||||
|
password: 'test',
|
||||||
|
url: browser_url,
|
||||||
|
)
|
||||||
|
tasks_close_all(browser: browser2)
|
||||||
|
click(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-toggleNotifications',
|
||||||
|
)
|
||||||
|
online_notitifcation_close_all(browser: browser2)
|
||||||
|
|
||||||
|
ticket1 = ticket_create(
|
||||||
|
data: {
|
||||||
|
customer: 'nico',
|
||||||
|
group: 'Users',
|
||||||
|
title: 'online notification render #1',
|
||||||
|
body: 'online notification render #1',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
ticket2 = ticket_create(
|
||||||
|
data: {
|
||||||
|
customer: 'nico',
|
||||||
|
group: 'Users',
|
||||||
|
title: 'online notification render #2',
|
||||||
|
body: 'online notification render #2',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
watch_for(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-notificationsCounter',
|
||||||
|
value: '2',
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(
|
||||||
|
browser: browser2,
|
||||||
|
js: '$(".js-notificationsContainer .js-items .js-item:nth-child(1) .activity-text").text("render test 2")',
|
||||||
|
)
|
||||||
|
execute(
|
||||||
|
browser: browser2,
|
||||||
|
js: '$(".js-notificationsContainer .js-items .js-item:nth-child(2) .activity-text").text("render test 1")',
|
||||||
|
)
|
||||||
|
match(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-notificationsContainer .js-items .js-item:nth-child(1) .activity-text',
|
||||||
|
value: 'render test 2',
|
||||||
|
)
|
||||||
|
match(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-notificationsContainer .js-items .js-item:nth-child(2) .activity-text',
|
||||||
|
value: 'render test 1',
|
||||||
|
)
|
||||||
|
ticket3 = ticket_create(
|
||||||
|
data: {
|
||||||
|
customer: 'nico',
|
||||||
|
group: 'Users',
|
||||||
|
title: 'online notification render #3',
|
||||||
|
body: 'online notification render #3',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
watch_for(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-notificationsCounter',
|
||||||
|
value: '3',
|
||||||
|
)
|
||||||
|
match(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-notificationsContainer .js-items .js-item:nth-child(1) .activity-text',
|
||||||
|
value: 'online notification render #3',
|
||||||
|
)
|
||||||
|
match(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-notificationsContainer .js-items .js-item:nth-child(2) .activity-text',
|
||||||
|
value: 'render test 2',
|
||||||
|
)
|
||||||
|
match(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-notificationsContainer .js-items .js-item:nth-child(3) .activity-text',
|
||||||
|
value: 'render test 1',
|
||||||
|
)
|
||||||
|
|
||||||
|
ticket_update(
|
||||||
|
data: {
|
||||||
|
state: 'closed',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
watch_for(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-notificationsCounter',
|
||||||
|
value: '2',
|
||||||
|
)
|
||||||
|
|
||||||
|
match(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-notificationsContainer .js-items .is-inactive.js-item:nth-child(1) .activity-text',
|
||||||
|
value: 'online notification render #3',
|
||||||
|
)
|
||||||
|
match(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-notificationsContainer .js-items .is-inactive.js-item:nth-child(2) .activity-text',
|
||||||
|
value: 'online notification render #3',
|
||||||
|
)
|
||||||
|
match(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-notificationsContainer .js-items .js-item:nth-child(3) .activity-text',
|
||||||
|
value: 'render test 2',
|
||||||
|
)
|
||||||
|
match(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-notificationsContainer .js-items .js-item:nth-child(4) .activity-text',
|
||||||
|
value: 'render test 1',
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(
|
||||||
|
browser: browser2,
|
||||||
|
js: '$(".js-notificationsContainer .js-items .js-item:nth-child(2) .activity-text").text("render test 3")',
|
||||||
|
)
|
||||||
|
|
||||||
|
close_online_notitifcation(
|
||||||
|
browser: browser2,
|
||||||
|
data: {
|
||||||
|
position: 3,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
match(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-notificationsContainer .js-items .is-inactive.js-item:nth-child(1) .activity-text',
|
||||||
|
value: 'online notification render #3',
|
||||||
|
)
|
||||||
|
match(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-notificationsContainer .js-items .js-item:nth-child(2) .activity-text',
|
||||||
|
value: 'render test 3',
|
||||||
|
)
|
||||||
|
match(
|
||||||
|
browser: browser2,
|
||||||
|
css: '.js-notificationsContainer .js-items .js-item:nth-child(3) .activity-text',
|
||||||
|
value: 'render test 1',
|
||||||
|
)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -186,7 +186,7 @@ class TestCase < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
instance.find_elements(css: '#login button')[0].click
|
instance.find_elements(css: '#login button')[0].click
|
||||||
|
|
||||||
sleep 5
|
sleep 4
|
||||||
login = instance.find_elements(css: '.user-menu .user a')[0].attribute('title')
|
login = instance.find_elements(css: '.user-menu .user a')[0].attribute('title')
|
||||||
if login != params[:username]
|
if login != params[:username]
|
||||||
screenshot(browser: instance, comment: 'login_failed')
|
screenshot(browser: instance, comment: 'login_failed')
|
||||||
|
@ -264,7 +264,7 @@ class TestCase < Test::Unit::TestCase
|
||||||
return if !clues
|
return if !clues
|
||||||
instance.execute_script("$('.js-modal--clue .js-close').click()")
|
instance.execute_script("$('.js-modal--clue .js-close').click()")
|
||||||
assert(true, 'clues closed')
|
assert(true, 'clues closed')
|
||||||
sleep 2
|
sleep 1
|
||||||
end
|
end
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
@ -1222,7 +1222,7 @@ wait untill text in selector disabppears
|
||||||
instance = params[:browser] || @browser
|
instance = params[:browser] || @browser
|
||||||
|
|
||||||
(1..100).each do
|
(1..100).each do
|
||||||
sleep 0.1
|
#sleep 0.5
|
||||||
begin
|
begin
|
||||||
if instance.find_elements(css: '.navigation .tasks .task:first-child')[0]
|
if instance.find_elements(css: '.navigation .tasks .task:first-child')[0]
|
||||||
instance.mouse.move_to(instance.find_elements(css: '.navigation .tasks .task:first-child')[0])
|
instance.mouse.move_to(instance.find_elements(css: '.navigation .tasks .task:first-child')[0])
|
||||||
|
@ -1247,6 +1247,85 @@ wait untill text in selector disabppears
|
||||||
assert(true, 'all tasks closed')
|
assert(true, 'all tasks closed')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
=begin
|
||||||
|
|
||||||
|
close_online_notitifcation(
|
||||||
|
browser: browser1,
|
||||||
|
data: {
|
||||||
|
#title: 'some title',
|
||||||
|
position: 3,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
=end
|
||||||
|
|
||||||
|
def close_online_notitifcation(params = {})
|
||||||
|
switch_window_focus(params)
|
||||||
|
log('close_online_notitifcation', params)
|
||||||
|
|
||||||
|
instance = params[:browser] || @browser
|
||||||
|
data = params[:data]
|
||||||
|
|
||||||
|
if data[:title]
|
||||||
|
element = instance.find_elements(partial_link_text: data[:title])[0]
|
||||||
|
if !element
|
||||||
|
screenshot(browser: instance, comment: 'close_online_notitifcation')
|
||||||
|
raise "no online notification with title '#{data[:title]}' found"
|
||||||
|
end
|
||||||
|
instance.mouse.move_to(element)
|
||||||
|
sleep 0.1
|
||||||
|
instance.execute_script("$('.js-notificationsContainer .js-items .js-item .activity-text:contains(\"#{data[:title]}\") .js-remove').first().click()")
|
||||||
|
|
||||||
|
else
|
||||||
|
css = ".js-notificationsContainer .js-items .js-item:nth-child(#{data[:position]})"
|
||||||
|
element = instance.find_elements(css: css)[0]
|
||||||
|
if !element
|
||||||
|
screenshot(browser: instance, comment: 'close_online_notitifcation')
|
||||||
|
raise "no online notification with postion '#{css}' found"
|
||||||
|
end
|
||||||
|
|
||||||
|
instance.mouse.move_to(element)
|
||||||
|
sleep 0.1
|
||||||
|
instance.find_elements(css: "#{css} .js-remove")[0].click
|
||||||
|
end
|
||||||
|
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
=begin
|
||||||
|
|
||||||
|
online_notitifcation_close_all(
|
||||||
|
browser: browser1,
|
||||||
|
)
|
||||||
|
|
||||||
|
=end
|
||||||
|
|
||||||
|
def online_notitifcation_close_all(params = {})
|
||||||
|
switch_window_focus(params)
|
||||||
|
log('online_notitifcation_close_all', params)
|
||||||
|
|
||||||
|
instance = params[:browser] || @browser
|
||||||
|
|
||||||
|
(1..100).each do
|
||||||
|
sleep 0.5
|
||||||
|
begin
|
||||||
|
if instance.find_elements(css: '.js-notificationsContainer .js-item:first-child')[0]
|
||||||
|
instance.mouse.move_to(instance.find_elements(css: '.js-notificationsContainer .js-item:first-child')[0])
|
||||||
|
sleep 0.1
|
||||||
|
click_element = instance.find_elements(css: '.js-notificationsContainer .js-item:first-child .js-remove')[0]
|
||||||
|
if click_element
|
||||||
|
click_element.click
|
||||||
|
end
|
||||||
|
else
|
||||||
|
break
|
||||||
|
end
|
||||||
|
rescue
|
||||||
|
# try again
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert(true, 'all online notification closed')
|
||||||
|
end
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
empty_search(
|
empty_search(
|
||||||
|
@ -1525,6 +1604,7 @@ wait untill text in selector disabppears
|
||||||
customer: 'nico',
|
customer: 'nico',
|
||||||
group: 'Users', # optional / '-NONE-' # if group selection should not be shown
|
group: 'Users', # optional / '-NONE-' # if group selection should not be shown
|
||||||
priority: '2 normal',
|
priority: '2 normal',
|
||||||
|
state: 'open',
|
||||||
title: 'overview #1',
|
title: 'overview #1',
|
||||||
body: 'overview #1',
|
body: 'overview #1',
|
||||||
},
|
},
|
||||||
|
@ -1598,6 +1678,14 @@ wait untill text in selector disabppears
|
||||||
mute_log: true,
|
mute_log: true,
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
if data[:state]
|
||||||
|
select(
|
||||||
|
browser: instance,
|
||||||
|
css: '.active .newTicket select[name="state_id"]',
|
||||||
|
value: data[:state],
|
||||||
|
mute_log: true,
|
||||||
|
)
|
||||||
|
end
|
||||||
if data[:title]
|
if data[:title]
|
||||||
set(
|
set(
|
||||||
browser: instance,
|
browser: instance,
|
||||||
|
|
Loading…
Reference in a new issue