Implemented issue #352 - Show other active agents in ticket detail view (collision prevention).
This commit is contained in:
parent
c6346ea210
commit
f9fdbe5934
20 changed files with 678 additions and 49 deletions
|
@ -94,10 +94,10 @@ class Index extends App.ControllerSubContent
|
|||
# update avatar text if needed
|
||||
if activeAvatar.text()
|
||||
replaceAvatar.text(activeAvatar.text())
|
||||
replaceAvatar.addClass('unique')
|
||||
replaceAvatar.addClass('avatar--unique')
|
||||
else
|
||||
replaceAvatar.text('')
|
||||
replaceAvatar.removeClass('unique')
|
||||
replaceAvatar.removeClass('avatar--unique')
|
||||
)
|
||||
avatar
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ class Content extends App.ControllerContent
|
|||
width = 300
|
||||
height = 226
|
||||
|
||||
holder.addClass 'unique'
|
||||
holder.addClass 'avatar--unique'
|
||||
|
||||
rng = new Math.seedrandom(id)
|
||||
x = rng() * (width - size)
|
||||
|
|
|
@ -47,6 +47,13 @@ class App.TicketZoomAttributeBar extends App.Controller
|
|||
resetButtonShown: resetButtonShown
|
||||
))
|
||||
@setSecondaryAction(@secondaryAction, localeEl)
|
||||
|
||||
if @permissionCheck('ticket.agent')
|
||||
new App.TaskbarWatcher(
|
||||
task_key: @task_key
|
||||
el: localeEl.filter('.js-avatars')
|
||||
)
|
||||
|
||||
@html localeEl
|
||||
|
||||
checkMacroChanges: =>
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
class App.TaskbarWatcher extends App.Controller
|
||||
constructor: ->
|
||||
super
|
||||
@subscribeId = App.TaskManager.preferencesSubscribe(@task_key, @render)
|
||||
|
||||
release: =>
|
||||
return if !@subscribeId
|
||||
App.TaskManager.preferencesUnsubscribe(@subscribeId)
|
||||
|
||||
render: (preferences) =>
|
||||
return if !preferences
|
||||
return if !preferences.tasks
|
||||
return if !@diffrence(@lastTasks, preferences.tasks)
|
||||
@lastTasks = preferences.tasks
|
||||
|
||||
watchers = []
|
||||
currentUserId = App.Session.get('id')
|
||||
@el.empty()
|
||||
for watcher in preferences.tasks
|
||||
if watcher.user_id != currentUserId
|
||||
cssClass = []
|
||||
lastContact = new Date(new Date(watcher.last_contact).getTime() + 5 * 60000)
|
||||
if new Date() > lastContact
|
||||
cssClass.push('avatar--idle')
|
||||
if watcher.changed
|
||||
cssClass.push('avatar--changed')
|
||||
else
|
||||
cssClass.push('avatar--not-changed')
|
||||
|
||||
@el.append('<div class="js-avatar"></div>')
|
||||
@el.append('<div class="half-spacer"></div>')
|
||||
|
||||
avatar = new App.WidgetAvatar(
|
||||
el: @el.find('.js-avatar').last()
|
||||
object_id: watcher.user_id
|
||||
size: 40
|
||||
cssClass: cssClass.join(' ')
|
||||
)
|
||||
|
||||
if watcher.changed
|
||||
status = $('<div class="avatar-status"></div>')
|
||||
status.append App.Utils.icon('pen')
|
||||
avatar.el.find('.avatar').append status
|
||||
|
||||
diffrence: (lastTasks, newTasks) ->
|
||||
return true if !lastTasks
|
||||
return true if lastTasks.length != newTasks.length
|
||||
for taskPosition of lastTasks
|
||||
return true if !lastTasks[taskPosition] || !newTasks[taskPosition]
|
||||
return true if lastTasks[taskPosition].user_id != newTasks[taskPosition].user_id
|
||||
return true if lastTasks[taskPosition].changed != newTasks[taskPosition].changed
|
||||
if lastTasks[taskPosition].last_contact
|
||||
lastContact = new Date(new Date(lastTasks[taskPosition].last_contact).getTime() + 5 * 60000)
|
||||
return true if new Date() > lastContact
|
||||
false
|
|
@ -10,5 +10,5 @@ class App.WidgetAvatar extends App.ObserverController
|
|||
globalRerender: false
|
||||
|
||||
render: (user) =>
|
||||
@html(user.avatar @size, @position, undefined, false, false, @type)
|
||||
@html(user.avatar(@size, @position, @cssClass, false, false, @type))
|
||||
@userPopups(@position)
|
||||
|
|
|
@ -71,6 +71,14 @@ class App.TaskManager
|
|||
return if !_instance
|
||||
_instance.showControllerHideOthers()
|
||||
|
||||
@preferencesSubscribe: (key, callback) ->
|
||||
return if !_instance
|
||||
_instance.preferencesSubscribe(key, callback)
|
||||
|
||||
@preferencesUnsubscribe: (id) ->
|
||||
return if !_instance
|
||||
_instance.preferencesUnsubscribe(id)
|
||||
|
||||
class _taskManagerSingleton extends App.Controller
|
||||
@include App.LogInclude
|
||||
|
||||
|
@ -83,12 +91,19 @@ class _taskManagerSingleton extends App.Controller
|
|||
@offlineModus = params.offlineModus
|
||||
@tasksInitial()
|
||||
|
||||
@bind('taskbar:preferences', (data) =>
|
||||
@tasksPreferences[data.key] = data.preferences
|
||||
@preferencesExecuteCallbacks(data.key)
|
||||
)
|
||||
|
||||
init: ->
|
||||
@domStore = {}
|
||||
@shownStore = {}
|
||||
@workers = {}
|
||||
@allTasksByKey = {}
|
||||
@tasksToUpdate = {}
|
||||
@tasksPreferences = {}
|
||||
@tasksPreferencesCallbacks = {}
|
||||
@activeTaskHistory = []
|
||||
@queue = []
|
||||
@queueRunning = false
|
||||
|
@ -206,13 +221,21 @@ class _taskManagerSingleton extends App.Controller
|
|||
|
||||
# save new task and update task collection
|
||||
ui = @
|
||||
@tasksToUpdate[params.key] = 'inCreate'
|
||||
task.save(
|
||||
done: ->
|
||||
if ui.tasksToUpdate[params.key] is 'inCreate'
|
||||
delete ui.tasksToUpdate[params.key]
|
||||
ui.allTasksByKey[params.key] = @attributes()
|
||||
ui.tasksPreferences[params.key] = clone(@preferences)
|
||||
ui.preferencesExecuteCallbacks(params.key)
|
||||
for taskPosition of ui.allTasks
|
||||
if ui.allTasks[taskPosition] && ui.allTasks[taskPosition]['key'] is @key
|
||||
task = @attributes()
|
||||
ui.allTasks[taskPosition] = task
|
||||
fail: ->
|
||||
if ui.tasksToUpdate[params.key] is 'inCreate'
|
||||
delete ui.tasksToUpdate[params.key]
|
||||
)
|
||||
|
||||
# empty static content if task is shown
|
||||
|
@ -491,7 +514,8 @@ class _taskManagerSingleton extends App.Controller
|
|||
|
||||
taskUpdate: (task, mute = false) ->
|
||||
@log 'debug', 'UPDATE task', task, mute
|
||||
@tasksToUpdate[ task.key ] = 'toUpdate'
|
||||
return if @tasksToUpdate[task.key] is 'inCreate'
|
||||
@tasksToUpdate[task.key] = 'toUpdate'
|
||||
@taskUpdateTrigger()
|
||||
return if mute
|
||||
@touch(task.key)
|
||||
|
@ -520,8 +544,10 @@ class _taskManagerSingleton extends App.Controller
|
|||
continue if !key
|
||||
task = @get(key)
|
||||
continue if !task
|
||||
if @tasksToUpdate[ task.key ] is 'toUpdate'
|
||||
@tasksToUpdate[ task.key ] = 'inProgress'
|
||||
if @tasksToUpdate[task.key] is 'toUpdate'
|
||||
@tasksToUpdate[task.key] = 'inProgress'
|
||||
taskUpdate = App.Taskbar.findByAttribute('key', task.key)
|
||||
if !taskUpdate
|
||||
taskUpdate = new App.Taskbar
|
||||
taskUpdate.load(task)
|
||||
if taskUpdate.isOnline()
|
||||
|
@ -539,7 +565,7 @@ class _taskManagerSingleton extends App.Controller
|
|||
taskDestroy: (task) ->
|
||||
|
||||
# check if update is still in process
|
||||
if @tasksToUpdate[ task.key ] is 'inProgress'
|
||||
if @tasksToUpdate[task.key] is 'inProgress' || @tasksToUpdate[task.key] is 'inCreate'
|
||||
App.Delay.set(
|
||||
=> @taskDestroy(task)
|
||||
800
|
||||
|
@ -550,12 +576,14 @@ class _taskManagerSingleton extends App.Controller
|
|||
return
|
||||
|
||||
# destroy task in backend
|
||||
delete @tasksToUpdate[ task.key ]
|
||||
delete @tasksToUpdate[task.key]
|
||||
|
||||
# if task isnt already stored on backend
|
||||
return if !task.id
|
||||
App.Taskbar.destroy(task.id)
|
||||
|
||||
delete @tasksPreferences[task.key]
|
||||
|
||||
tasksAutoCleanupDelay: =>
|
||||
delay = =>
|
||||
@tasksAutoCleanup()
|
||||
|
@ -637,3 +665,26 @@ class _taskManagerSingleton extends App.Controller
|
|||
)
|
||||
|
||||
App.Event.trigger 'taskbar:ready'
|
||||
|
||||
preferencesSubscribe: (key, callback) =>
|
||||
if !@tasksPreferencesCallbacks[key]
|
||||
@tasksPreferencesCallbacks[key] = {}
|
||||
subscribeId = "#{key}#{Math.floor(Math.random() * 999999)}"
|
||||
@tasksPreferencesCallbacks[key][subscribeId] = callback
|
||||
subscribeId
|
||||
|
||||
preferencesUnsubscribe: (id) =>
|
||||
return if !@tasksPreferencesCallbacks
|
||||
for key, value of @tasksPreferencesCallbacks
|
||||
for subscribeId, callback of value
|
||||
if subscribeId == id
|
||||
delete value[subscribeId]
|
||||
for key, value of @tasksPreferencesCallbacks
|
||||
if _.isEmpty(value)
|
||||
delete @tasksPreferencesCallbacks[key]
|
||||
|
||||
preferencesExecuteCallbacks: (key) =>
|
||||
return if !@tasksPreferencesCallbacks[key]
|
||||
return if !@tasksPreferences[key]
|
||||
for subscribeId, callback of @tasksPreferencesCallbacks[key]
|
||||
callback(@tasksPreferences[key])
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<span class="avatar <%- @cssClass %> unique" style="background-position: -<%- @x %>px -<%- @y %>px;"<%- @placement %><%- @data %>>
|
||||
<span class="avatar <%- @cssClass %> avatar--unique" style="background-position: -<%- @x %>px -<%- @y %>px;"<%- @placement %><%- @data %>>
|
||||
<%- @Icon('crown') if @vip %>
|
||||
<%= @initials %>
|
||||
</span>
|
|
@ -32,7 +32,7 @@
|
|||
</div>
|
||||
<div class="page-header">
|
||||
<div class="flex vertical center">
|
||||
<span class="avatar unique user-popover size-50" data-id="2" style="background-position: -92.79607555375712px -106.24902447601627px;" data-original-title="" title="">NB</span>
|
||||
<span class="avatar avatar--unique user-popover size-50" data-id="2" style="background-position: -92.79607555375712px -106.24902447601627px;" data-original-title="" title="">NB</span>
|
||||
<div class="ticket-title">
|
||||
<h1 contenteditable="true" class="ticket-title-update" data-placeholder="Enter Title...">Welcome to Zammad! We want to entertain you and your whole family!</h1>
|
||||
</div>
|
||||
|
@ -56,7 +56,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="article-content">
|
||||
<span class="avatar unique user-popover " data-id="2" style="background-position: -96.5079185759074px -112.28590086669901px;" data-placement="left" data-original-title="" title="">NB</span>
|
||||
<span class="avatar avatar--unique user-popover " data-id="2" style="background-position: -96.5079185759074px -112.28590086669901px;" data-placement="left" data-original-title="" title="">NB</span>
|
||||
<div class="flex bubble-gap internal-border">
|
||||
<div class="textBubble">
|
||||
<div class="bubble-arrow"></div>
|
||||
|
@ -155,7 +155,7 @@ The <a href="https://zammad.org" title="https://zammad.org" target="_blank">zamm
|
|||
</div>
|
||||
</div>
|
||||
<div class="article-content">
|
||||
<span class="avatar unique user-popover " data-id="2" style="background-position: -96.5079185759074px -112.28590086669901px;" data-placement="left" data-original-title="" title="">NB</span>
|
||||
<span class="avatar avatar--unique user-popover " data-id="2" style="background-position: -96.5079185759074px -112.28590086669901px;" data-placement="left" data-original-title="" title="">NB</span>
|
||||
<div class="flex bubble-gap internal-border">
|
||||
<div class="textBubble"><div class="bubble-arrow"></div>Ich wollte mir die Lyrics von Maria herunterladen, aber ich schaff es einfach nicht, da raufzukommen. Schick mir bitte mein Passwort.
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
<div class="ticketZoom-header">
|
||||
<div class="flex vertical center">
|
||||
<div class="js-avatar">
|
||||
<span class="avatar unique size-50 user-popover" data-id="2" data-original-title="" style="background-position: -92.79607555375712px -106.24902447601627px;" title="">NB</span>
|
||||
<span class="avatar avatar--unique size-50 user-popover" data-id="2" data-original-title="" style="background-position: -92.79607555375712px -106.24902447601627px;" title="">NB</span>
|
||||
</div>
|
||||
|
||||
<div class="ticket-title">
|
||||
|
@ -71,7 +71,7 @@
|
|||
|
||||
<div class="article-content">
|
||||
<div class="js-avatar">
|
||||
<span class="avatar unique size-40 user-popover" data-id="2" data-original-title="" style="background-position: -96.5079185759074px -112.28590086669901px;" title="">NB</span>
|
||||
<span class="avatar avatar--unique size-40 user-popover" data-id="2" data-original-title="" style="background-position: -96.5079185759074px -112.28590086669901px;" title="">NB</span>
|
||||
</div>
|
||||
|
||||
<div class="bubble-gap">
|
||||
|
@ -796,7 +796,7 @@
|
|||
|
||||
<div class="sidebar-content">
|
||||
<div class="sidebar-block">
|
||||
<span class="avatar unique userInfo-avatar size-50 user-popover" data-id="2" style="background-position: -92.79607555375712px -106.24902447601627px;">NB</span>
|
||||
<span class="avatar avatar--unique userInfo-avatar size-50 user-popover" data-id="2" style="background-position: -92.79607555375712px -106.24902447601627px;">NB</span>
|
||||
|
||||
<h3 title="Name">Nicole Braun</h3>
|
||||
</div>
|
||||
|
@ -862,7 +862,7 @@
|
|||
|
||||
<div class="userList">
|
||||
<div class="userList-entry">
|
||||
<span class="avatar unique size-40 user-popover" data-id="2" data-original-title="" style="background-position: -96.5079185759074px -112.28590086669901px;" title="">NB</span> <a class="userList-entry user-popover" data-id="2" data-original-title="" href="#user/profile/2" title="">Nicole Braun</a>
|
||||
<span class="avatar avatar--unique size-40 user-popover" data-id="2" data-original-title="" style="background-position: -96.5079185759074px -112.28590086669901px;" title="">NB</span> <a class="userList-entry user-popover" data-id="2" data-original-title="" href="#user/profile/2" title="">Nicole Braun</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
<label><%- @T('Members') %></label>
|
||||
<div class="profile-details horizontal wrap">
|
||||
<div class="profile-organizationMember">
|
||||
<span class="avatar unique user-popover size-40" data-id="4" style="background-position: -97.5718417033075px -178.430732445616px;">AG</span>
|
||||
<span class="avatar avatar--unique user-popover size-40" data-id="4" style="background-position: -97.5718417033075px -178.430732445616px;">AG</span>
|
||||
<a href="#">Doreen Kubiak</a>
|
||||
</div>
|
||||
<div class="profile-organizationMember">
|
||||
|
@ -60,11 +60,11 @@
|
|||
<a href="#">Franz Xaver</a>
|
||||
</div>
|
||||
<div class="profile-organizationMember">
|
||||
<span class="avatar unique user-popover size-40" data-id="4" style="background-position: -27.5718417033075px -17.430732445616px;">JM</span>
|
||||
<span class="avatar avatar--unique user-popover size-40" data-id="4" style="background-position: -27.5718417033075px -17.430732445616px;">JM</span>
|
||||
<a href="#">Julius Müller</a>
|
||||
</div>
|
||||
<div class="profile-organizationMember">
|
||||
<span class="avatar unique user-popover size-40" data-id="4" style="background-position: -97.5718417033075px -178.430732445616px;">HH</span>
|
||||
<span class="avatar avatar--unique user-popover size-40" data-id="4" style="background-position: -97.5718417033075px -178.430732445616px;">HH</span>
|
||||
<a href="#">Hans Hubert</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
</div>
|
||||
<div class="page-header">
|
||||
<div class="flex vertical center">
|
||||
<span class="avatar unique user-popover size-50" data-id="2" style="background-position: -92.79607555375712px -106.24902447601627px;" data-original-title="" title="">NB</span>
|
||||
<span class="avatar avatar--unique user-popover size-50" data-id="2" style="background-position: -92.79607555375712px -106.24902447601627px;" data-original-title="" title="">NB</span>
|
||||
<div class="ticket-title">
|
||||
<h1 contenteditable="true" class="ticket-title-update" data-placeholder="Enter Title...">Welcome to Zammad! We want to entertain you and your whole family!</h1>
|
||||
</div>
|
||||
|
@ -76,7 +76,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="article-content">
|
||||
<span class="avatar unique user-popover " data-id="2" style="background-position: -96.5079185759074px -112.28590086669901px;" data-placement="left" data-original-title="" title="">NB</span>
|
||||
<span class="avatar avatar--unique user-popover " data-id="2" style="background-position: -96.5079185759074px -112.28590086669901px;" data-placement="left" data-original-title="" title="">NB</span>
|
||||
<div class="flex bubble-gap internal-border">
|
||||
<div class="textBubble">
|
||||
<div class="bubble-arrow"></div>
|
||||
|
@ -182,7 +182,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="article-content">
|
||||
<span class="avatar unique user-popover " data-id="2" style="background-position: -96.5079185759074px -112.28590086669901px;" data-placement="left" data-original-title="" title="">NB</span>
|
||||
<span class="avatar avatar--unique user-popover " data-id="2" style="background-position: -96.5079185759074px -112.28590086669901px;" data-placement="left" data-original-title="" title="">NB</span>
|
||||
<div class="flex bubble-gap internal-border">
|
||||
<div class="textBubble"><div class="bubble-arrow"></div><div class="article-text" id="article-35098758344">Ich wollte mir die Lyrics von Maria herunterladen, aber ich schaff es einfach nicht, da raufzukommen. Schick mir bitte mein Passwort.
|
||||
|
||||
|
@ -547,7 +547,7 @@
|
|||
<hr>
|
||||
<div class="sidebar-content">
|
||||
<div class="sidebar-block">
|
||||
<span class="avatar unique userInfo-avatar size-50 user-popover" data-id="2" style="background-position: -92.79607555375712px -106.24902447601627px;">NB</span>
|
||||
<span class="avatar avatar--unique userInfo-avatar size-50 user-popover" data-id="2" style="background-position: -92.79607555375712px -106.24902447601627px;">NB</span>
|
||||
<h3 title="Name">
|
||||
Nicole Braun
|
||||
</h3>
|
||||
|
@ -604,7 +604,7 @@
|
|||
<label>Members</label>
|
||||
<div class="userList">
|
||||
<div class="userList-entry">
|
||||
<span class="avatar unique size-40 user-popover" data-id="2" data-original-title="" style="background-position: -96.5079185759074px -112.28590086669901px;" title="">NB</span> <a class="userList-entry user-popover" data-id="2" data-original-title="" href="#user/profile/2" title="">Nicole Braun</a>
|
||||
<span class="avatar avatar--unique size-40 user-popover" data-id="2" data-original-title="" style="background-position: -96.5079185759074px -112.28590086669901px;" title="">NB</span> <a class="userList-entry user-popover" data-id="2" data-original-title="" href="#user/profile/2" title="">Nicole Braun</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
<div class="flex horizontal js-avatars"></div>
|
||||
<div class="buttonDropdown btn js-reset <% if !@resetButtonShown: %>hide<% end %>"><%- @T('Discard your unsaved changes.') %></div>
|
||||
<div class="buttonDropdown dropdown dropdown--actions dropup">
|
||||
<div class="btn btn--text btn--icon--last" data-toggle="dropdown">
|
||||
|
|
|
@ -3508,6 +3508,20 @@ footer {
|
|||
fill: hsl(47,100%,59%);
|
||||
}
|
||||
|
||||
&-status {
|
||||
position: absolute;
|
||||
right: -4px;
|
||||
bottom: -4px;
|
||||
border-radius: 999px;
|
||||
background: hsl(234,10%,19%);
|
||||
fill: white;
|
||||
width: 21px;
|
||||
height: 21px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&.size-50 {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
|
@ -3530,7 +3544,12 @@ footer {
|
|||
}
|
||||
}
|
||||
|
||||
&.unique {
|
||||
&--idle {
|
||||
filter: grayscale(100%);
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
&--unique {
|
||||
background-image: image_url("/assets/images/avatar-bg.png");
|
||||
background-size: 300px 226px;
|
||||
color: white;
|
||||
|
@ -5236,6 +5255,10 @@ footer {
|
|||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.tags {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.userNotifications label + .btn {
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
@ -8502,6 +8525,11 @@ body.fit {
|
|||
margin-right: auto;
|
||||
}
|
||||
|
||||
.half-spacer {
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
|
|
|
@ -4,16 +4,13 @@ class TaskbarController < ApplicationController
|
|||
before_action :authentication_check
|
||||
|
||||
def index
|
||||
|
||||
current_user_tasks = Taskbar.where(user_id: current_user.id)
|
||||
model_index_render_result(current_user_tasks)
|
||||
|
||||
end
|
||||
|
||||
def show
|
||||
taskbar = Taskbar.find(params[:id])
|
||||
access(taskbar)
|
||||
|
||||
model_show_render_item(taskbar)
|
||||
end
|
||||
|
||||
|
@ -24,7 +21,6 @@ class TaskbarController < ApplicationController
|
|||
def update
|
||||
taskbar = Taskbar.find(params[:id])
|
||||
access(taskbar)
|
||||
|
||||
taskbar.update_attributes!(Taskbar.param_cleanup(params))
|
||||
model_update_render_item(taskbar)
|
||||
end
|
||||
|
@ -32,7 +28,6 @@ class TaskbarController < ApplicationController
|
|||
def destroy
|
||||
taskbar = Taskbar.find(params[:id])
|
||||
access(taskbar)
|
||||
|
||||
taskbar.destroy
|
||||
model_destroy_render_item()
|
||||
end
|
||||
|
|
|
@ -3,16 +3,103 @@
|
|||
class Taskbar < ApplicationModel
|
||||
store :state
|
||||
store :params
|
||||
before_create :update_last_contact, :set_user
|
||||
before_update :update_last_contact, :set_user
|
||||
store :preferences
|
||||
before_create :update_last_contact, :set_user, :update_preferences_infos
|
||||
before_update :update_last_contact, :set_user, :update_preferences_infos
|
||||
|
||||
after_update :notify_clients
|
||||
after_destroy :update_preferences_infos, :notify_clients
|
||||
|
||||
attr_accessor :local_update
|
||||
|
||||
def state_changed?
|
||||
return false if !state
|
||||
return false if state.empty?
|
||||
state.each { |_key, value|
|
||||
if value.class == Hash || value.class == ActiveSupport::HashWithIndifferentAccess
|
||||
value.each { |_key1, value1|
|
||||
next if value1 && value1.empty?
|
||||
return true
|
||||
}
|
||||
else
|
||||
next if value && value.empty?
|
||||
return true
|
||||
end
|
||||
}
|
||||
false
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def update_last_contact
|
||||
return true if local_update
|
||||
self.last_contact = Time.zone.now
|
||||
end
|
||||
|
||||
def set_user
|
||||
return true if local_update
|
||||
self.user_id = UserInfo.current_user_id
|
||||
end
|
||||
|
||||
def update_preferences_infos
|
||||
return true if local_update
|
||||
|
||||
# find other same open tasks
|
||||
preferences[:tasks] = []
|
||||
Taskbar.where(key: key).order(:created_at).each { |taskbar|
|
||||
changed = if taskbar.id == id
|
||||
state_changed?
|
||||
else
|
||||
taskbar.state_changed?
|
||||
end
|
||||
task = {
|
||||
id: taskbar.id,
|
||||
user_id: taskbar.user_id,
|
||||
last_contact: taskbar.last_contact,
|
||||
changed: changed,
|
||||
}
|
||||
preferences[:tasks].push task
|
||||
}
|
||||
if !id
|
||||
changed = state_changed?
|
||||
task = {
|
||||
user_id: user_id,
|
||||
last_contact: last_contact,
|
||||
changed: changed,
|
||||
}
|
||||
preferences[:tasks].push task
|
||||
end
|
||||
|
||||
# update other taskbars
|
||||
Taskbar.where(key: key).order(:created_at).each { |taskbar|
|
||||
next if taskbar.id == id
|
||||
taskbar.preferences = preferences
|
||||
taskbar.local_update = true
|
||||
taskbar.save!
|
||||
}
|
||||
|
||||
return true if destroyed?
|
||||
|
||||
# remember preferences for current taskbar
|
||||
self.preferences = preferences
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def notify_clients
|
||||
return true if !changes['preferences']
|
||||
data = {
|
||||
event: 'taskbar:preferences',
|
||||
data: {
|
||||
id: id,
|
||||
key: key,
|
||||
preferences: preferences,
|
||||
},
|
||||
}
|
||||
PushMessages.send_to(
|
||||
user_id,
|
||||
data,
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -243,6 +243,7 @@ class CreateBase < ActiveRecord::Migration
|
|||
t.string :key, limit: 100, null: false
|
||||
t.string :callback, limit: 100, null: false
|
||||
t.text :state, limit: 20.megabytes + 1, null: true
|
||||
t.text :preferences, limit: 5.megabytes + 1, null: true
|
||||
t.string :params, limit: 2000, null: true
|
||||
t.integer :prio, null: false
|
||||
t.boolean :notify, null: false, default: false
|
||||
|
@ -251,6 +252,7 @@ class CreateBase < ActiveRecord::Migration
|
|||
end
|
||||
add_index :taskbars, [:user_id]
|
||||
add_index :taskbars, [:client_id]
|
||||
add_index :taskbars, [:key]
|
||||
|
||||
create_table :tags do |t|
|
||||
t.references :tag_item, null: false
|
||||
|
|
11
db/migrate/20161228000001_add_taskbar_meta.rb
Normal file
11
db/migrate/20161228000001_add_taskbar_meta.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
class AddTaskbarMeta < ActiveRecord::Migration
|
||||
def up
|
||||
# return if it's a new setup
|
||||
return if !Setting.find_by(name: 'system_init_done')
|
||||
|
||||
add_column :taskbars, :preferences, :text, limit: 5.megabytes + 1, null: true
|
||||
add_index :taskbars, [:key]
|
||||
|
||||
Cache.clear
|
||||
end
|
||||
end
|
|
@ -19,17 +19,31 @@ module PushMessages
|
|||
)
|
||||
return true
|
||||
end
|
||||
Thread.current[:push_messages].push data
|
||||
message = { type: 'broadcast', data: data }
|
||||
Thread.current[:push_messages].push message
|
||||
end
|
||||
|
||||
def self.send_to(user_id, data)
|
||||
if !PushMessages.enabled?
|
||||
Sessions.send_to(user_id, data)
|
||||
return true
|
||||
end
|
||||
message = { type: 'send_to', user_id: user_id, data: data }
|
||||
Thread.current[:push_messages].push message
|
||||
end
|
||||
|
||||
def self.finish
|
||||
return false if !enabled?
|
||||
Thread.current[:push_messages].each { |data|
|
||||
Thread.current[:push_messages].each { |message|
|
||||
if message[:type] == 'send_to'
|
||||
Sessions.send_to(message[:user_id], message[:data])
|
||||
else
|
||||
Sessions.broadcast(
|
||||
data[:message],
|
||||
data[:type],
|
||||
data[:current_user_id],
|
||||
message[:data][:message],
|
||||
message[:data][:type],
|
||||
message[:data][:current_user_id],
|
||||
)
|
||||
end
|
||||
}
|
||||
Thread.current[:push_messages] = nil
|
||||
true
|
||||
|
|
269
spec/models/taskbar_spec.rb
Normal file
269
spec/models/taskbar_spec.rb
Normal file
|
@ -0,0 +1,269 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Taskbar do
|
||||
|
||||
context 'single creation' do
|
||||
Taskbar.destroy_all
|
||||
UserInfo.current_user_id = 1
|
||||
|
||||
taskbar = Taskbar.create(
|
||||
client_id: 123,
|
||||
key: 'Ticket-1234',
|
||||
callback: 'TicketZoom',
|
||||
params: {
|
||||
id: 1234,
|
||||
},
|
||||
state: {},
|
||||
prio: 1,
|
||||
notify: false,
|
||||
)
|
||||
|
||||
it 'existing key' do
|
||||
expect(taskbar.key).to eq('Ticket-1234')
|
||||
end
|
||||
|
||||
it 'params' do
|
||||
expect(taskbar.params[:id]).to eq(1234)
|
||||
end
|
||||
|
||||
it 'state' do
|
||||
expect(taskbar.state.empty?).to eq(true)
|
||||
end
|
||||
|
||||
UserInfo.current_user_id = nil
|
||||
end
|
||||
|
||||
context 'multible creation' do
|
||||
|
||||
it 'create tasks' do
|
||||
|
||||
Taskbar.destroy_all
|
||||
UserInfo.current_user_id = 1
|
||||
taskbar1 = Taskbar.create(
|
||||
client_id: 123,
|
||||
key: 'Ticket-1234',
|
||||
callback: 'TicketZoom',
|
||||
params: {
|
||||
id: 1234,
|
||||
},
|
||||
state: {},
|
||||
prio: 1,
|
||||
notify: false,
|
||||
)
|
||||
|
||||
UserInfo.current_user_id = 2
|
||||
taskbar2 = Taskbar.create(
|
||||
client_id: 123,
|
||||
key: 'Ticket-1234',
|
||||
callback: 'TicketZoom',
|
||||
params: {
|
||||
id: 1234,
|
||||
},
|
||||
state: {},
|
||||
prio: 2,
|
||||
notify: false,
|
||||
)
|
||||
|
||||
taskbar1.reload
|
||||
expect(taskbar1.preferences[:tasks].count).to eq(2)
|
||||
expect(taskbar1.preferences[:tasks][0][:user_id]).to eq(1)
|
||||
expect(taskbar1.preferences[:tasks][0][:changed]).to eq(false)
|
||||
expect(taskbar1.preferences[:tasks][1][:user_id]).to eq(2)
|
||||
expect(taskbar1.preferences[:tasks][1][:changed]).to eq(false)
|
||||
|
||||
taskbar2.reload
|
||||
expect(taskbar2.preferences[:tasks].count).to eq(2)
|
||||
expect(taskbar2.preferences[:tasks][0][:user_id]).to eq(1)
|
||||
expect(taskbar2.preferences[:tasks][0][:changed]).to eq(false)
|
||||
expect(taskbar2.preferences[:tasks][1][:user_id]).to eq(2)
|
||||
expect(taskbar2.preferences[:tasks][1][:changed]).to eq(false)
|
||||
|
||||
taskbar3 = Taskbar.create(
|
||||
client_id: 123,
|
||||
key: 'Ticket-4444',
|
||||
callback: 'TicketZoom',
|
||||
params: {
|
||||
id: 4444,
|
||||
},
|
||||
state: {},
|
||||
prio: 2,
|
||||
notify: false,
|
||||
)
|
||||
|
||||
taskbar1.reload
|
||||
expect(taskbar1.preferences[:tasks].count).to eq(2)
|
||||
expect(taskbar1.preferences[:tasks][0][:user_id]).to eq(1)
|
||||
expect(taskbar1.preferences[:tasks][0][:changed]).to eq(false)
|
||||
expect(taskbar1.preferences[:tasks][1][:user_id]).to eq(2)
|
||||
expect(taskbar1.preferences[:tasks][1][:changed]).to eq(false)
|
||||
|
||||
taskbar2.reload
|
||||
expect(taskbar2.preferences[:tasks].count).to eq(2)
|
||||
expect(taskbar2.preferences[:tasks][0][:user_id]).to eq(1)
|
||||
expect(taskbar2.preferences[:tasks][0][:changed]).to eq(false)
|
||||
expect(taskbar2.preferences[:tasks][1][:user_id]).to eq(2)
|
||||
expect(taskbar2.preferences[:tasks][1][:changed]).to eq(false)
|
||||
|
||||
taskbar3.reload
|
||||
expect(taskbar3.preferences[:tasks].count).to eq(1)
|
||||
expect(taskbar3.preferences[:tasks][0][:user_id]).to eq(2)
|
||||
expect(taskbar3.preferences[:tasks][0][:changed]).to eq(false)
|
||||
|
||||
UserInfo.current_user_id = 3
|
||||
taskbar4 = Taskbar.create(
|
||||
client_id: 123,
|
||||
key: 'Ticket-1234',
|
||||
callback: 'TicketZoom',
|
||||
params: {
|
||||
id: 1234,
|
||||
},
|
||||
state: {},
|
||||
prio: 4,
|
||||
notify: false,
|
||||
)
|
||||
|
||||
taskbar1.reload
|
||||
expect(taskbar1.preferences[:tasks].count).to eq(3)
|
||||
expect(taskbar1.preferences[:tasks][0][:user_id]).to eq(1)
|
||||
expect(taskbar1.preferences[:tasks][0][:changed]).to eq(false)
|
||||
expect(taskbar1.preferences[:tasks][1][:user_id]).to eq(2)
|
||||
expect(taskbar1.preferences[:tasks][1][:changed]).to eq(false)
|
||||
expect(taskbar1.preferences[:tasks][2][:user_id]).to eq(3)
|
||||
expect(taskbar1.preferences[:tasks][2][:changed]).to eq(false)
|
||||
|
||||
taskbar2.reload
|
||||
expect(taskbar2.preferences[:tasks].count).to eq(3)
|
||||
expect(taskbar2.preferences[:tasks][0][:user_id]).to eq(1)
|
||||
expect(taskbar2.preferences[:tasks][0][:changed]).to eq(false)
|
||||
expect(taskbar2.preferences[:tasks][1][:user_id]).to eq(2)
|
||||
expect(taskbar2.preferences[:tasks][1][:changed]).to eq(false)
|
||||
expect(taskbar2.preferences[:tasks][2][:user_id]).to eq(3)
|
||||
expect(taskbar2.preferences[:tasks][2][:changed]).to eq(false)
|
||||
|
||||
taskbar3.reload
|
||||
expect(taskbar3.preferences[:tasks].count).to eq(1)
|
||||
expect(taskbar3.preferences[:tasks][0][:user_id]).to eq(2)
|
||||
expect(taskbar3.preferences[:tasks][0][:changed]).to eq(false)
|
||||
|
||||
taskbar4.reload
|
||||
expect(taskbar4.preferences[:tasks].count).to eq(3)
|
||||
expect(taskbar4.preferences[:tasks][0][:user_id]).to eq(1)
|
||||
expect(taskbar4.preferences[:tasks][0][:changed]).to eq(false)
|
||||
expect(taskbar4.preferences[:tasks][1][:user_id]).to eq(2)
|
||||
expect(taskbar4.preferences[:tasks][1][:changed]).to eq(false)
|
||||
expect(taskbar4.preferences[:tasks][2][:user_id]).to eq(3)
|
||||
expect(taskbar4.preferences[:tasks][2][:changed]).to eq(false)
|
||||
|
||||
UserInfo.current_user_id = 2
|
||||
taskbar2.state = { article: {}, ticket: {} }
|
||||
taskbar2.save!
|
||||
|
||||
taskbar1.reload
|
||||
expect(taskbar1.preferences[:tasks].count).to eq(3)
|
||||
expect(taskbar1.preferences[:tasks][0][:user_id]).to eq(1)
|
||||
expect(taskbar1.preferences[:tasks][0][:changed]).to eq(false)
|
||||
expect(taskbar1.preferences[:tasks][1][:user_id]).to eq(2)
|
||||
expect(taskbar1.preferences[:tasks][1][:changed]).to eq(false)
|
||||
expect(taskbar1.preferences[:tasks][2][:user_id]).to eq(3)
|
||||
expect(taskbar1.preferences[:tasks][2][:changed]).to eq(false)
|
||||
|
||||
taskbar2.reload
|
||||
expect(taskbar2.preferences[:tasks].count).to eq(3)
|
||||
expect(taskbar2.preferences[:tasks][0][:user_id]).to eq(1)
|
||||
expect(taskbar2.preferences[:tasks][0][:changed]).to eq(false)
|
||||
expect(taskbar2.preferences[:tasks][1][:user_id]).to eq(2)
|
||||
expect(taskbar2.preferences[:tasks][1][:changed]).to eq(false)
|
||||
expect(taskbar2.preferences[:tasks][2][:user_id]).to eq(3)
|
||||
expect(taskbar2.preferences[:tasks][2][:changed]).to eq(false)
|
||||
|
||||
taskbar3.reload
|
||||
expect(taskbar3.preferences[:tasks].count).to eq(1)
|
||||
expect(taskbar3.preferences[:tasks][0][:user_id]).to eq(2)
|
||||
expect(taskbar3.preferences[:tasks][0][:changed]).to eq(false)
|
||||
|
||||
taskbar4.reload
|
||||
expect(taskbar4.preferences[:tasks].count).to eq(3)
|
||||
expect(taskbar4.preferences[:tasks][0][:user_id]).to eq(1)
|
||||
expect(taskbar4.preferences[:tasks][0][:changed]).to eq(false)
|
||||
expect(taskbar4.preferences[:tasks][1][:user_id]).to eq(2)
|
||||
expect(taskbar4.preferences[:tasks][1][:changed]).to eq(false)
|
||||
expect(taskbar4.preferences[:tasks][2][:user_id]).to eq(3)
|
||||
expect(taskbar4.preferences[:tasks][2][:changed]).to eq(false)
|
||||
|
||||
UserInfo.current_user_id = 2
|
||||
taskbar2.state = { article: { body: 'some body' }, ticket: {} }
|
||||
taskbar2.save!
|
||||
|
||||
taskbar1.reload
|
||||
expect(taskbar1.preferences[:tasks].count).to eq(3)
|
||||
expect(taskbar1.preferences[:tasks][0][:user_id]).to eq(1)
|
||||
expect(taskbar1.preferences[:tasks][0][:changed]).to eq(false)
|
||||
expect(taskbar1.preferences[:tasks][1][:user_id]).to eq(2)
|
||||
expect(taskbar1.preferences[:tasks][1][:changed]).to eq(true)
|
||||
expect(taskbar1.preferences[:tasks][2][:user_id]).to eq(3)
|
||||
expect(taskbar1.preferences[:tasks][2][:changed]).to eq(false)
|
||||
|
||||
taskbar2.reload
|
||||
expect(taskbar2.preferences[:tasks].count).to eq(3)
|
||||
expect(taskbar2.preferences[:tasks][0][:user_id]).to eq(1)
|
||||
expect(taskbar2.preferences[:tasks][0][:changed]).to eq(false)
|
||||
expect(taskbar2.preferences[:tasks][1][:user_id]).to eq(2)
|
||||
expect(taskbar2.preferences[:tasks][1][:changed]).to eq(true)
|
||||
expect(taskbar2.preferences[:tasks][2][:user_id]).to eq(3)
|
||||
expect(taskbar2.preferences[:tasks][2][:changed]).to eq(false)
|
||||
|
||||
taskbar3.reload
|
||||
expect(taskbar3.preferences[:tasks].count).to eq(1)
|
||||
expect(taskbar3.preferences[:tasks][0][:user_id]).to eq(2)
|
||||
expect(taskbar3.preferences[:tasks][0][:changed]).to eq(false)
|
||||
|
||||
taskbar4.reload
|
||||
expect(taskbar4.preferences[:tasks].count).to eq(3)
|
||||
expect(taskbar4.preferences[:tasks][0][:user_id]).to eq(1)
|
||||
expect(taskbar4.preferences[:tasks][0][:changed]).to eq(false)
|
||||
expect(taskbar4.preferences[:tasks][1][:user_id]).to eq(2)
|
||||
expect(taskbar4.preferences[:tasks][1][:changed]).to eq(true)
|
||||
expect(taskbar4.preferences[:tasks][2][:user_id]).to eq(3)
|
||||
expect(taskbar4.preferences[:tasks][2][:changed]).to eq(false)
|
||||
|
||||
UserInfo.current_user_id = 1
|
||||
taskbar1.state = { article: { body: '' }, ticket: { state_id: 123 } }
|
||||
taskbar1.save!
|
||||
|
||||
taskbar1.reload
|
||||
expect(taskbar1.preferences[:tasks].count).to eq(3)
|
||||
expect(taskbar1.preferences[:tasks][0][:user_id]).to eq(1)
|
||||
expect(taskbar1.preferences[:tasks][0][:changed]).to eq(true)
|
||||
expect(taskbar1.preferences[:tasks][1][:user_id]).to eq(2)
|
||||
expect(taskbar1.preferences[:tasks][1][:changed]).to eq(true)
|
||||
expect(taskbar1.preferences[:tasks][2][:user_id]).to eq(3)
|
||||
expect(taskbar1.preferences[:tasks][2][:changed]).to eq(false)
|
||||
|
||||
taskbar2.reload
|
||||
expect(taskbar2.preferences[:tasks].count).to eq(3)
|
||||
expect(taskbar2.preferences[:tasks][0][:user_id]).to eq(1)
|
||||
expect(taskbar2.preferences[:tasks][0][:changed]).to eq(true)
|
||||
expect(taskbar2.preferences[:tasks][1][:user_id]).to eq(2)
|
||||
expect(taskbar2.preferences[:tasks][1][:changed]).to eq(true)
|
||||
expect(taskbar2.preferences[:tasks][2][:user_id]).to eq(3)
|
||||
expect(taskbar2.preferences[:tasks][2][:changed]).to eq(false)
|
||||
|
||||
taskbar3.reload
|
||||
expect(taskbar3.preferences[:tasks].count).to eq(1)
|
||||
expect(taskbar3.preferences[:tasks][0][:user_id]).to eq(2)
|
||||
expect(taskbar3.preferences[:tasks][0][:changed]).to eq(false)
|
||||
|
||||
taskbar4.reload
|
||||
expect(taskbar4.preferences[:tasks].count).to eq(3)
|
||||
expect(taskbar4.preferences[:tasks][0][:user_id]).to eq(1)
|
||||
expect(taskbar4.preferences[:tasks][0][:changed]).to eq(true)
|
||||
expect(taskbar4.preferences[:tasks][1][:user_id]).to eq(2)
|
||||
expect(taskbar4.preferences[:tasks][1][:changed]).to eq(true)
|
||||
expect(taskbar4.preferences[:tasks][2][:user_id]).to eq(3)
|
||||
expect(taskbar4.preferences[:tasks][2][:changed]).to eq(false)
|
||||
|
||||
UserInfo.current_user_id = nil
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -43,6 +43,17 @@ class AgentTicketUpdate2Test < TestCase
|
|||
value: 'some level 3 <b>body</b> 123äöü',
|
||||
)
|
||||
|
||||
watch_for(
|
||||
browser: browser1,
|
||||
css: '.content.active .js-attributeBar .js-avatar .avatar--not-changed',
|
||||
value: 'AT', # agent1
|
||||
)
|
||||
watch_for(
|
||||
browser: browser2,
|
||||
css: '.content.active .js-attributeBar .js-avatar .avatar--not-changed',
|
||||
value: 'TA', # master
|
||||
)
|
||||
|
||||
# change edit screen in instance 1
|
||||
ticket_update(
|
||||
browser: browser1,
|
||||
|
@ -58,6 +69,17 @@ class AgentTicketUpdate2Test < TestCase
|
|||
no_quote: true,
|
||||
)
|
||||
|
||||
watch_for(
|
||||
browser: browser1,
|
||||
css: '.content.active .js-attributeBar .js-avatar .avatar--not-changed',
|
||||
value: 'AT', # agent1
|
||||
)
|
||||
watch_for(
|
||||
browser: browser2,
|
||||
css: '.content.active .js-attributeBar .js-avatar .avatar--changed',
|
||||
value: 'TA', # master
|
||||
)
|
||||
|
||||
# update ticket in instance 2
|
||||
ticket_update(
|
||||
browser: browser2,
|
||||
|
@ -72,6 +94,16 @@ class AgentTicketUpdate2Test < TestCase
|
|||
value: '(Discard your unsaved changes.|Verwerfen der)',
|
||||
no_quote: true,
|
||||
)
|
||||
watch_for(
|
||||
browser: browser1,
|
||||
css: '.content.active .js-attributeBar .js-avatar .avatar--changed',
|
||||
value: 'AT', # agent1
|
||||
)
|
||||
watch_for(
|
||||
browser: browser2,
|
||||
css: '.content.active .js-attributeBar .js-avatar .avatar--changed',
|
||||
value: 'TA', # master
|
||||
)
|
||||
|
||||
click(
|
||||
browser: browser2,
|
||||
|
@ -92,6 +124,17 @@ class AgentTicketUpdate2Test < TestCase
|
|||
},
|
||||
)
|
||||
|
||||
watch_for(
|
||||
browser: browser1,
|
||||
css: '.content.active .js-attributeBar .js-avatar .avatar--not-changed',
|
||||
value: 'AT', # agent1
|
||||
)
|
||||
watch_for(
|
||||
browser: browser2,
|
||||
css: '.content.active .js-attributeBar .js-avatar .avatar--changed',
|
||||
value: 'TA', # master
|
||||
)
|
||||
|
||||
# check content and edit screen in instance 1
|
||||
watch_for(
|
||||
browser: browser2,
|
||||
|
@ -126,6 +169,17 @@ class AgentTicketUpdate2Test < TestCase
|
|||
no_quote: true,
|
||||
)
|
||||
|
||||
watch_for(
|
||||
browser: browser1,
|
||||
css: '.content.active .js-attributeBar .js-avatar .avatar--not-changed',
|
||||
value: 'AT', # agent1
|
||||
)
|
||||
watch_for(
|
||||
browser: browser2,
|
||||
css: '.content.active .js-attributeBar .js-avatar .avatar--not-changed',
|
||||
value: 'TA', # master
|
||||
)
|
||||
|
||||
# check content in instance 2
|
||||
watch_for(
|
||||
browser: browser2,
|
||||
|
@ -160,6 +214,17 @@ class AgentTicketUpdate2Test < TestCase
|
|||
no_quote: true,
|
||||
)
|
||||
|
||||
watch_for(
|
||||
browser: browser1,
|
||||
css: '.content.active .js-attributeBar .js-avatar .avatar--not-changed',
|
||||
value: 'AT', # agent1
|
||||
)
|
||||
watch_for(
|
||||
browser: browser2,
|
||||
css: '.content.active .js-attributeBar .js-avatar .avatar--not-changed',
|
||||
value: 'TA', # master
|
||||
)
|
||||
|
||||
# reload instances, verify again
|
||||
reload(
|
||||
browser: browser1,
|
||||
|
@ -195,6 +260,17 @@ class AgentTicketUpdate2Test < TestCase
|
|||
no_quote: true,
|
||||
)
|
||||
|
||||
watch_for(
|
||||
browser: browser1,
|
||||
css: '.content.active .js-attributeBar .js-avatar .avatar--not-changed',
|
||||
value: 'AT', # agent1
|
||||
)
|
||||
watch_for(
|
||||
browser: browser2,
|
||||
css: '.content.active .js-attributeBar .js-avatar .avatar--not-changed',
|
||||
value: 'TA', # master
|
||||
)
|
||||
|
||||
# change form of ticket, reset, reload and verify in instance 2
|
||||
ticket_update(
|
||||
browser: browser2,
|
||||
|
@ -244,6 +320,17 @@ class AgentTicketUpdate2Test < TestCase
|
|||
)
|
||||
sleep 2
|
||||
|
||||
watch_for(
|
||||
browser: browser1,
|
||||
css: '.content.active .js-attributeBar .js-avatar .avatar--changed',
|
||||
value: 'AT', # agent1
|
||||
)
|
||||
watch_for(
|
||||
browser: browser2,
|
||||
css: '.content.active .js-attributeBar .js-avatar .avatar--not-changed',
|
||||
value: 'TA', # master
|
||||
)
|
||||
|
||||
reload(
|
||||
browser: browser2,
|
||||
)
|
||||
|
@ -260,6 +347,17 @@ class AgentTicketUpdate2Test < TestCase
|
|||
no_quote: true,
|
||||
)
|
||||
|
||||
watch_for(
|
||||
browser: browser1,
|
||||
css: '.content.active .js-attributeBar .js-avatar .avatar--changed',
|
||||
value: 'AT', # agent1
|
||||
)
|
||||
watch_for(
|
||||
browser: browser2,
|
||||
css: '.content.active .js-attributeBar .js-avatar .avatar--not-changed',
|
||||
value: 'TA', # master
|
||||
)
|
||||
|
||||
task_type(
|
||||
browser: browser2,
|
||||
type: 'stayOnTab',
|
||||
|
@ -278,6 +376,17 @@ class AgentTicketUpdate2Test < TestCase
|
|||
no_quote: true,
|
||||
)
|
||||
|
||||
watch_for(
|
||||
browser: browser1,
|
||||
css: '.content.active .js-attributeBar .js-avatar .avatar--not-changed',
|
||||
value: 'AT', # agent1
|
||||
)
|
||||
watch_for(
|
||||
browser: browser2,
|
||||
css: '.content.active .js-attributeBar .js-avatar .avatar--not-changed',
|
||||
value: 'TA', # master
|
||||
)
|
||||
|
||||
# check if new article is empty
|
||||
ticket_verify(
|
||||
browser: browser2,
|
||||
|
|
Loading…
Reference in a new issue