From def1aacb201b486cca6a03208ecb2ef95121a0fe Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Thu, 19 Feb 2015 20:32:37 +0100 Subject: [PATCH] Moved to new task manager api (now also with browser tests). --- .../controllers/agent_ticket_create.js.coffee | 7 +- .../app/controllers/login.js.coffee | 3 - .../organization_profile.js.coffee | 7 +- .../app/controllers/taskbar_widget.js.coffee | 27 +- .../app/controllers/ticket_overview.js.coffee | 350 ++++++++++-------- .../app/controllers/ticket_zoom.js.coffee | 7 +- .../app/controllers/user_profile.js.coffee | 8 +- .../app/lib/app_post/task_manager.js.coffee | 301 +++++++++------ app/views/tests/taskbar.html.erb | 16 + config/routes/test.rb | 1 + lib/sessions/backend/ticket_overview_index.rb | 4 +- lib/sessions/backend/ticket_overview_list.rb | 6 +- public/assets/tests/taskbar.js | 235 ++++++++++++ 13 files changed, 684 insertions(+), 288 deletions(-) create mode 100644 app/views/tests/taskbar.html.erb create mode 100644 public/assets/tests/taskbar.js diff --git a/app/assets/javascripts/app/controllers/agent_ticket_create.js.coffee b/app/assets/javascripts/app/controllers/agent_ticket_create.js.coffee index 4f88bc5f1..b993aa514 100644 --- a/app/assets/javascripts/app/controllers/agent_ticket_create.js.coffee +++ b/app/assets/javascripts/app/controllers/agent_ticket_create.js.coffee @@ -576,7 +576,12 @@ class Router extends App.ControllerPermanent type: params.type id: params.id - App.TaskManager.add( 'TicketCreateScreen-' + params['id'], 'TicketCreate', clean_params ) + App.TaskManager.execute( + key: 'TicketCreateScreen-' + params['id'] + controller: 'TicketCreate' + params: clean_params + show: true + ) # create new ticket routes/controller App.Config.set( 'ticket/create', Router, 'Routes' ) diff --git a/app/assets/javascripts/app/controllers/login.js.coffee b/app/assets/javascripts/app/controllers/login.js.coffee index 39572415c..e28d766f3 100644 --- a/app/assets/javascripts/app/controllers/login.js.coffee +++ b/app/assets/javascripts/app/controllers/login.js.coffee @@ -90,9 +90,6 @@ class Index extends App.ControllerContent success: (data, status, xhr) => - # rebuild navbar with ticket overview counter - App.WebSocket.send( event: 'navupdate_ticket_overview' ) - # redirect to # requested_url = @Config.get( 'requested_url' ) if requested_url && requested_url isnt '#login' diff --git a/app/assets/javascripts/app/controllers/organization_profile.js.coffee b/app/assets/javascripts/app/controllers/organization_profile.js.coffee index f455e21ba..9e0449e6b 100644 --- a/app/assets/javascripts/app/controllers/organization_profile.js.coffee +++ b/app/assets/javascripts/app/controllers/organization_profile.js.coffee @@ -155,6 +155,11 @@ class Router extends App.ControllerPermanent clean_params = organization_id: params.organization_id - App.TaskManager.add( 'Organization-' + @organization_id, 'OrganizationProfile', clean_params ) + App.TaskManager.execute( + key: 'Organization-' + @organization_id + controller: 'OrganizationProfile' + params: clean_params + show: true + ) App.Config.set( 'organization/profile/:organization_id', Router, 'Routes' ) diff --git a/app/assets/javascripts/app/controllers/taskbar_widget.js.coffee b/app/assets/javascripts/app/controllers/taskbar_widget.js.coffee index 2cbd715e2..17f8f800e 100644 --- a/app/assets/javascripts/app/controllers/taskbar_widget.js.coffee +++ b/app/assets/javascripts/app/controllers/taskbar_widget.js.coffee @@ -91,8 +91,8 @@ class App.TaskbarWidget extends App.Controller return # check if active task is closed - currentTask = App.TaskManager.get( key ) - tasks = App.TaskManager.all() + currentTask = App.TaskManager.get( key ) + tasks = App.TaskManager.all() active_is_closed = false for task in tasks if currentTask.active && task.key is key @@ -101,19 +101,16 @@ class App.TaskbarWidget extends App.Controller # remove task App.TaskManager.remove( key ) - # navigate to next task if needed - tasks = App.TaskManager.all() - if active_is_closed && !_.isEmpty( tasks ) - task_last = undefined - for task in tasks - task_last = task - if task_last - worker = App.TaskManager.worker( task_last.key ) - if worker - @navigate worker.url() - return - if _.isEmpty( tasks ) - @navigate '#' + # if we do not need to move to an other task + return if !active_is_closed + + # get new task url + nextTaskUrl = App.TaskManager.nextTaskUrl() + if nextTaskUrl + @navigate nextTaskUrl + return + + @navigate '#' class Remove extends App.ControllerModal constructor: -> diff --git a/app/assets/javascripts/app/controllers/ticket_overview.js.coffee b/app/assets/javascripts/app/controllers/ticket_overview.js.coffee index 32c7a256d..659721058 100644 --- a/app/assets/javascripts/app/controllers/ticket_overview.js.coffee +++ b/app/assets/javascripts/app/controllers/ticket_overview.js.coffee @@ -1,140 +1,157 @@ -class Index extends App.Controller - constructor: -> - super - @render() - - render: -> - - @html App.view('agent_ticket_view')() - - # redirect to first view - if !@view - cache = App.Store.get( 'navupdate_ticket_overview' ) - if cache && !_.isEmpty( cache ) - view = cache[0].link - @navigate "ticket/view/#{view}" - return - - new Navbar( - el: @el.find('.sidebar') - view: @view - ) - - if @view - new Table( - el: @el.find('.main') - view: @view - ) - -class Table extends App.ControllerContent - events: - 'click [data-type=edit]': 'zoom' - 'click [data-type=settings]': 'settings' - 'click [data-type=viewmode]': 'viewmode' - 'click [data-type=page]': 'page' - +class App.TicketOverview extends App.Controller constructor: -> super # check authentication return if !@authenticate() - @view_mode = localStorage.getItem( "mode:#{@view}" ) || 's' - @log 'notice', 'view:', @view, @view_mode - - # set title - @title '' - @navupdate '#ticket/view' - - @meta = {} - @bulk = {} - - # set new key - @key = 'ticket_overview_' + @view - - # bind to rebuild view event - @bind( 'ticket_overview_rebuild', @fetch ) - - # render - @fetch() - - fetch: (force) => - - # use cache of first page - cache = App.Store.get( @key ) - if !force && cache - @load(cache) - - # init fetch via ajax, all other updates on time via websockets - else - @ajax( - id: 'ticket_overview_' + @key - type: 'GET' - url: @apiPath + '/ticket_overviews' - data: - view: @view - view_mode: @view_mode - processData: true - success: (data) => - data.ajax = true - @load(data) - ) - - load: (data) => - return if !data - return if !data.ticket_ids - return if !data.overview - - @overview = data.overview - @tickets_count = data.tickets_count - @ticket_ids = data.ticket_ids - - if data.ajax - data.ajax = false - App.Store.write( @key, data ) - - # load assets - App.Collection.loadAssets( data.assets ) - - # get meta data - @overview = data.overview - App.Overview.refresh( @overview, { clear: true } ) - - App.Overview.unbind('local:rerender') - App.Overview.bind 'local:rerender', (record) => - @log 'notice', 'rerender...', record - @render() - - App.Overview.unbind('local:refetch') - App.Overview.bind 'local:refetch', (record) => - @log 'notice', 'refetch...', record - @fetch(true) - - @ticket_list_show = [] - for ticket_id in @ticket_ids - @ticket_list_show.push App.Ticket.fullLocal( ticket_id ) - - # remeber bulk attributes - @bulk = data.bulk - - # set cache -# App.Store.write( @key, data ) - - # render page @render() render: -> + @html App.view('ticket_overview')() + + @navBarController = new Navbar( + el: @el.find('.sidebar') + view: @view + ) + + @contentController = new Table( + el: @el.find('.main') + view: @view + ) + + active: (state) => + @activeState = state + + isActive: => + @activeState + + url: => + '#ticket/view/' + @view + + show: (params) => + + # highlight navbar + @navupdate '#ticket/view' + + # redirect to last overview if we got called in first level + @view = params['view'] + if !@view && @viewLast + @navigate "ticket/view/#{@viewLast}" + return + + # build nav bar + if @navBarController + @navBarController.update( + view: @view + activeState: true + ) + + # do not rerender overview if current overview is requested again + return if @viewLast is @view + + # remember last view + @viewLast = @view + + # build content + if @contentController + @contentController.update( + view: @view + ) + + hide: => + if @navBarController + @navBarController.active(false) + + changed: => + false + + release: => + # no + +class Table extends App.Controller + events: + 'click [data-type=edit]': 'zoom' + 'click [data-type=settings]': 'settings' + 'click [data-type=viewmode]': 'viewmode' + 'click [data-type=page]': 'page' + + constructor: -> + super + + @cache = {} + + # rebuild ticket overview data + @bind 'ticket_overview_rebuild', (data) => + console.log('EVENT ticket_overview_rebuild', @view, data.view) + + # remeber bulk attributes + @bulk = data.bulk + + @cache[data.view] = data + + # check if current view is updated + if @view is data.view + @render() + + + update: (params) => + for key, value of params + @[key] = value + + @view_mode = localStorage.getItem( "mode:#{@view}" ) || 's' + @log 'notice', 'view:', @view, @view_mode + + @render() + + fetch: (force) => + + # init fetch via ajax, all other updates on time via websockets + @ajax( + id: 'ticket_overview_' + @key + type: 'GET' + url: @apiPath + '/ticket_overviews' + data: + view: @view + view_mode: @view_mode + processData: true + success: (data) => + if data.assets + App.Collection.loadAssets( data.assets ) + + # remeber bulk attributes + @bulk = data.bulk + + @cache[data.view] = data + @render() + ) + + render: -> + return if !@cache + return if !@cache[@view] + + overview = @cache[@view].overview + tickets_count = @cache[@view].tickets_count + ticket_ids = @cache[@view].ticket_ids + + # get meta data + overview = @cache[@view].overview + App.Overview.refresh( overview, { clear: true } ) + + # get ticket list + ticket_list_show = [] + for ticket_id in ticket_ids + ticket_list_show.push App.Ticket.fullLocal( ticket_id ) # if customer and no ticket exists, show the following message only - if !@ticket_list_show[0] && @isRole('Customer') + if !ticket_list_show[0] && @isRole('Customer') @html App.view('customer_not_ticket_exists')() return @selected = @bulkGetSelected() # set page title - @overview = App.Overview.find( @overview.id ) - @title @overview.name + overview = App.Overview.find( overview.id ) # render init page checkbox = true @@ -157,7 +174,7 @@ class Table extends App.ControllerContent if @isRole('Customer') view_modes = [] html = App.view('agent_ticket_view/content')( - overview: @overview + overview: overview view_modes: view_modes checkbox: checkbox edit: edit @@ -172,16 +189,17 @@ class Table extends App.ControllerContent table = '' if @view_mode is 'm' table = App.view('agent_ticket_view/detail')( - overview: @overview - objects: @ticket_list_show + overview: overview + objects: ticket_list_show checkbox: checkbox ) table = $(table) table.delegate('[name="bulk_all"]', 'click', (e) -> + console.log('OOOO', $(e.target).attr('checked') ) if $(e.target).attr('checked') - $(e.target).parents().find('[name="bulk"]').attr('checked', true) + $(e.target).closest('table').find('[name="bulk"]').attr('checked', true) else - $(e.target).parents().find('[name="bulk"]').attr('checked', false) + $(e.target).closest('table').find('[name="bulk"]').attr('checked', false) ) @el.find('.table-overview').append(table) else @@ -226,12 +244,12 @@ class Table extends App.ControllerContent value new App.ControllerTable( - overview: @overview.view.s - el: @el.find('.table-overview') + overview: overview.view.s + el: @$('.table-overview') model: App.Ticket - objects: @ticket_list_show + objects: ticket_list_show checkbox: checkbox - groupBy: @overview.group_by + groupBy: overview.group_by bindRow: events: 'click': openTicket @@ -452,9 +470,6 @@ class Table extends App.ControllerContent # refresh view after all tickets are proceeded if @bulk_count_index == @bulk_count - # rebuild navbar with updated ticket count of overviews - App.WebSocket.send( event: 'navupdate_ticket_overview' ) - # fetch overview data again @fetch() ) @@ -687,17 +702,17 @@ class Navbar extends App.Controller super # rebuild ticket overview data - @bind 'navupdate_ticket_overview', (data) => - if !_.isEmpty(data) - App.Store.write( 'navupdate_ticket_overview', data ) - @render(data) + @bind 'ticket_overview_index', (data) => + #console.log('EVENT ticket_overview_index') + @cache = data + @update() - cache = App.Store.get( 'navupdate_ticket_overview' ) - if cache - @render( cache ) - else - @render( [] ) + # init fetch via ajax + ajaxInit = => + # ignore if already pushed via websockets + return if @cache + #console.log('AJAX CALLL') # init fetch via ajax, all other updates on time via websockets @ajax( id: 'ticket_overviews', @@ -705,17 +720,37 @@ class Navbar extends App.Controller url: @apiPath + '/ticket_overviews', processData: true, success: (data) => - App.Store.write( 'navupdate_ticket_overview', data ) - @render(data) + @cache = data + @update() ) + @delay( ajaxInit, 5000 ) - render: (dataOrig) -> + active: (state) => + @activeState = state - data = _.clone(dataOrig) + update: (params = {}) -> + for key, value of params + @[key] = value + @render() + + if @activeState + meta = + title: '' + if @cache + for item in @cache + if item.link is @view + meta.title = item.name + @title meta.title + + render: => + #console.log('RENDER NAV') + return if !@cache + data = _.clone(@cache) # redirect to first view - if !@view && !_.isEmpty(data) + if @activeState && !@view && !_.isEmpty(data) view = data[0].link + #console.log('REDIRECT', "ticket/view/#{view}") @navigate "ticket/view/#{view}" return @@ -724,6 +759,7 @@ class Navbar extends App.Controller item.target = '#ticket/view/' + item.link if item.link is @view item.active = true + activeOverview = item else item.active = false @@ -784,8 +820,26 @@ class Router extends App.Controller else @navigate 'ticket/zoom/' + @ticket_ids[ @position - 1 ] + '/nav/true' -App.Config.set( 'ticket/view', Index, 'Routes' ) -App.Config.set( 'ticket/view/:view', Index, 'Routes' ) +class TicketOverviewRouter extends App.ControllerPermanent + constructor: (params) -> + super + + # cleanup params + clean_params = + view: params.view + + App.TaskManager.execute( + key: 'TicketOverview' + controller: 'TicketOverview' + params: clean_params + show: true + persistent: true + ) + +App.Config.set( 'ticket/view', TicketOverviewRouter, 'Routes' ) +App.Config.set( 'ticket/view/:view', TicketOverviewRouter, 'Routes' ) #App.Config.set( 'ticket/view/:view/:position/:direction', Router, 'Routes' ) +App.Config.set( 'TicketOverview', 'TicketOverview', 'permanentTask' ) + App.Config.set( 'TicketOverview', { prio: 1000, parent: '', name: 'Overviews', target: '#ticket/view', role: ['Agent', 'Customer'], class: 'overviews' }, 'NavBar' ) diff --git a/app/assets/javascripts/app/controllers/ticket_zoom.js.coffee b/app/assets/javascripts/app/controllers/ticket_zoom.js.coffee index 7e65572d6..e58f439b0 100644 --- a/app/assets/javascripts/app/controllers/ticket_zoom.js.coffee +++ b/app/assets/javascripts/app/controllers/ticket_zoom.js.coffee @@ -1730,7 +1730,12 @@ class TicketZoomRouter extends App.ControllerPermanent article_id: params.article_id nav: params.nav - App.TaskManager.add( 'Ticket-' + @ticket_id, 'TicketZoom', clean_params ) + App.TaskManager.execute( + key: 'Ticket-' + @ticket_id + controller: 'TicketZoom' + params: clean_params + show: true + ) App.Config.set( 'ticket/zoom/:ticket_id', TicketZoomRouter, 'Routes' ) App.Config.set( 'ticket/zoom/:ticket_id/nav/:nav', TicketZoomRouter, 'Routes' ) diff --git a/app/assets/javascripts/app/controllers/user_profile.js.coffee b/app/assets/javascripts/app/controllers/user_profile.js.coffee index 3db91782a..d8896a41a 100644 --- a/app/assets/javascripts/app/controllers/user_profile.js.coffee +++ b/app/assets/javascripts/app/controllers/user_profile.js.coffee @@ -158,6 +158,12 @@ class Router extends App.ControllerPermanent clean_params = user_id: params.user_id - App.TaskManager.add( 'User-' + @user_id, 'UserProfile', clean_params ) + App.TaskManager.execute( + key: 'User-' + @user_id + controller: 'UserProfile' + params: clean_params + show: true + ) + App.Config.set( 'user/profile/:user_id', Router, 'Routes' ) diff --git a/app/assets/javascripts/app/lib/app_post/task_manager.js.coffee b/app/assets/javascripts/app/lib/app_post/task_manager.js.coffee index 8e0238b71..710e69ffa 100644 --- a/app/assets/javascripts/app/lib/app_post/task_manager.js.coffee +++ b/app/assets/javascripts/app/lib/app_post/task_manager.js.coffee @@ -1,18 +1,18 @@ class App.TaskManager _instance = undefined - @init: -> - _instance ?= new _taskManagerSingleton + @init: ( params ) -> + _instance ?= new _taskManagerSingleton( params ) @all: -> if _instance == undefined _instance ?= new _taskManagerSingleton _instance.all() - @add: ( key, callback, params, to_not_show ) -> + @execute: ( params ) -> if _instance == undefined _instance ?= new _taskManagerSingleton - _instance.add( key, callback, params, to_not_show ) + _instance.execute( params ) @get: ( key ) -> if _instance == undefined @@ -49,26 +49,31 @@ class App.TaskManager _instance ?= new _taskManagerSingleton _instance.worker( key ) - @workerAll: -> + @nextTaskUrl: -> if _instance == undefined _instance ?= new _taskManagerSingleton - _instance.workerAll() + _instance.nextTaskUrl() @TaskbarId: -> if _instance == undefined _instance ?= new _taskManagerSingleton _instance.TaskbarId() -class _taskManagerSingleton extends App.Controller +class _taskManagerSingleton extends Spine.Module @include App.LogInclude - constructor: -> + constructor: (params = {}) -> super + if params.el + @el = params.el + else + @el = $('#app') + @offlineModus = params.offlineModus @workers = {} @workersStarted = {} @allTasks = [] @tasksToUpdate = {} - @activeTask = undefined + @activeTaskHistory = [] @tasksInitial() # render on login @@ -106,36 +111,44 @@ class _taskManagerSingleton extends App.Controller prio++ prio + # generate dom id for task + domID: (key) -> + "content_permanent_#{key}" + worker: ( key ) -> return @workers[ key ] if @workers[ key ] return - workerAll: -> - @workers - - add: ( key, callback, params, to_not_show = false ) -> + execute: ( params ) -> # input validation - key = App.Utils.htmlAttributeCleanup(key) + params.key = App.Utils.htmlAttributeCleanup(params.key) - active = true - if to_not_show - active = false + # in case later araives an init execute, ignore it + if params.init && @workers[ params.key ] + console.log('IGNORE LATER INIT', params) + return + + # remember latest active controller + if params.show + @activeTaskHistory.push _.clone(params) # create new task if not exists - task = @get( key ) - @log 'debug', 'add', key, callback, params, to_not_show, task, active - if !task + task = @get( params.key ) + #console.log 'debug', 'execute', params, 'task', task + + # create new online task if not exists and if not persistent + if !task && !params.persistent @log 'debug', 'add, create new taskbar in backend' task = new App.Taskbar task.load( - key: key - params: params - callback: callback + key: params.key + params: params.params + callback: params.controller client_id: 123 prio: @newPrio() notify: false - active: active + active: params.show ) @allTasks.push task.attributes() @@ -150,27 +163,20 @@ class _taskManagerSingleton extends App.Controller ) # empty static content if task is shown - if active - @activeTask = key - $('#content').empty() + if params.show + @el.find('#content').empty() # hide all tasks - $('.content').addClass('hide').removeClass('active') + @el.find('.content').addClass('hide').removeClass('active') # create div for task if not exists - if !$("#content_permanent_#{key}")[0] - $('#app').append('
') - - # set task to shown and active - if @activeTask is key - $('#content_permanent_' + key).removeClass('hide').addClass('active') - else - $('#content_permanent_' + key).addClass('hide').removeClass('active') + if !@el.find("##{@domID(params.key)}")[0] + @el.append("
") # set all tasks to active false, only new/selected one to active - if active + if params.show for task in @allTasks - if task.key isnt key + if task.key isnt params.key if task.active task.active = false @taskUpdate( task ) @@ -184,72 +190,87 @@ class _taskManagerSingleton extends App.Controller task.notify = false if changed @taskUpdate( task ) - else - for task in @allTasks - if @activeTask isnt task.key - if task.active - task.active = false - @taskUpdate( task ) # start worker for task if not exists - @startController(key, callback, params, to_not_show) + @startController(params) App.Event.trigger 'task:render' - return key - startController: (key, callback, params, to_not_show) => + startController: (params) => - @log 'debug', 'controller start try...', callback, key + @log 'debug', 'controller start try...', params - # create params - params_app = _.clone(params) - params_app['el'] = $('#content_permanent_' + key ) - params_app['task_key'] = key - if to_not_show + # create clean params + params_app = _.clone(params.params) + params_app['el'] = $("##{@domID(params.key)}") + params_app['task_key'] = params.key + if !params.show params_app['doNotLog'] = 1 - # return if controller is already started - if @workersStarted[key] - if !to_not_show - @showController( key, params_app ) - return + # start controller if not already started + if !@workersStarted[params.key] + @workersStarted[params.key] = true - @workersStarted[key] = true + # create new controller instanz + @workers[params.key] = new App[params.controller]( params_app ) - # create new controller instanz - a = new App[callback]( params_app ) - @workers[ key ] = a + # if controller is started hidden, call hide of controller + if !params.show + @hide(params.key) - # activate controller - if !to_not_show - @showController( key, params_app ) + # hide all other controller / show current controller + else + @showControllerHideOthers( params.key, params_app ) - return a - - showController: ( thisKey, params_app ) => + showControllerHideOthers: ( thisKey, params_app ) => for key of @workersStarted - controller = @workers[ key ] - if controller - if key is thisKey + if key is thisKey + @show(key, params_app) + else + @hide(key) - # execute controllers show - if controller.show - controller.show(params_app) - App.Event.trigger('ui:rerender:task') - else + # show task content + show: (key, params_app) -> + @el.find("##{@domID(key)}").removeClass('hide').addClass('active') - # execute controllers hide - if controller.hide - controller.hide() + controller = @workers[ key ] + return false if !controller + # set controller state to active + if controller.active + controller.active(true) + + # execute controllers show + if controller.show + controller.show(params_app) + App.Event.trigger('ui:rerender:task') + + true + + # hide task content + hide: (key) -> + @el.find("##{@domID(key)}").addClass('hide').removeClass('active') + + controller = @workers[ key ] + return false if !controller + + # set controller state to active + if controller.active + controller.active(false) + + # execute controllers hide + if controller.hide + controller.hide() + + true + + # get task get: ( key ) => for task in @allTasks if task.key is key return task -# return task if task.key is key - return -# throw "No such task with '#{key}'" + # update task update: ( key, params ) => task = @get( key ) if !task @@ -258,11 +279,12 @@ class _taskManagerSingleton extends App.Controller task[item] = value @taskUpdate( task ) - remove: ( key, to_not_show = false ) => + # remove task certain task from tasks + remove: ( key ) => task = @get( key ) - if !task - throw "No such task with '#{key}' to remove" + return if !task + # update @allTasks allTasks = _.filter( @allTasks (taskLocal) -> @@ -271,21 +293,16 @@ class _taskManagerSingleton extends App.Controller ) @allTasks = allTasks || [] - try - $('#content_permanent_' + key ).html('') - $('#content_permanent_' + key ).remove() - catch - @log 'notice', "invalid key '#{key}'" - - - delete @workersStarted[ key ] - delete @workers[ key ] + # release task from dom and destroy controller + @release(key) + # rerender taskbar App.Event.trigger 'task:render' - # destroy in backend + # destroy in backend storage @taskDestroy(task) + # set notify of task notify: ( key ) => task = @get( key ) if !task @@ -293,6 +310,7 @@ class _taskManagerSingleton extends App.Controller task.notify = true @taskUpdate( task ) + # set new order of tasks (needed for dnd) reorder: ( order ) => prio = 0 for key in order @@ -304,23 +322,32 @@ class _taskManagerSingleton extends App.Controller task.prio = prio @taskUpdate( task ) + # release one task + release: (key) => + try + @el.find( "##{@domID(key)}" ).html('') + @el.find( "##{@domID(key)}" ).remove() + catch + @log 'notice', "invalid key '#{key}'" + + delete @workersStarted[ key ] + delete @workers[ key ] + + # reset while tasks reset: => - # release tasks + # release touch tasks for task in @allTasks - try - $('#content_permanent_' + task.key ).html('') - $('#content_permanent_' + task.key ).remove() - catch - @log 'notice', "invalid key '#{key}'" + @release(key) - delete @workersStarted[ task.key ] - delete @workers[ task.key ] + # release persistent tasks + for key, controller of @workers + @release(key) # clear instance vars - @tasksToUpdate = {} - @allTasks = [] - @activeTask = undefined + @tasksToUpdate = {} + @allTasks = [] + @activeTaskHistory = [] # clear in mem tasks App.Taskbar.deleteAll() @@ -328,6 +355,27 @@ class _taskManagerSingleton extends App.Controller # rerender task bar App.Event.trigger 'task:render' + nextTaskUrl: => + + # activate latest controller based on history + loop + controllerParams = @activeTaskHistory.pop() + break if !controllerParams + break if !controllerParams.key + controller = @workers[ controllerParams.key ] + if controller && controller.url + return controller.url() + + # activate latest controller with highest prio + tasks = @all() + taskNext = tasks[tasks.length-1] + if taskNext + controller = @workers[ taskNext.key ] + if controller && controller.url + return controller.url() + + false + TaskbarId: => if !@TaskbarIdInt @TaskbarIdInt = Math.floor( Math.random() * 99999999 ) @@ -339,6 +387,7 @@ class _taskManagerSingleton extends App.Controller App.Event.trigger 'task:render' taskUpdateLoop: => + return if @offlineModus for key of @tasksToUpdate continue if !key task = @get( key ) @@ -381,26 +430,52 @@ class _taskManagerSingleton extends App.Controller tasksInitial: => + # reopen tasks + App.Event.trigger 'taskbar:init' + + # initial load of permanent tasks + task_count = 0 + permanentTask = App.Config.get( 'permanentTask' ) + if permanentTask + for key, callback of permanentTask + task_count += 1 + do (task) => + App.Delay.set( + => + @execute( + key: key + controller: callback + params: {} + show: false + persistent: true + init: true + ) + task_count * 50 + undefined + 'task' + ) + # initial load of taskbar collection tasks = App.Taskbar.all() @allTasks = [] for task in tasks @allTasks.push task.attributes() - - # reopen tasks - App.Event.trigger 'taskbar:init' - - task_count = 0 for task in @allTasks task_count += 1 do (task) => App.Delay.set( => - @add(task.key, task.callback, task.params, true) + @execute( + key: task.key + controller: task.callback + params: task.params + show: false + persistent: false + init: true + ) task_count * 600 undefined 'task' ) App.Event.trigger 'taskbar:ready' - diff --git a/app/views/tests/taskbar.html.erb b/app/views/tests/taskbar.html.erb new file mode 100644 index 000000000..3005fce88 --- /dev/null +++ b/app/views/tests/taskbar.html.erb @@ -0,0 +1,16 @@ + + + + + + + + +
+ +
diff --git a/config/routes/test.rb b/config/routes/test.rb index 60f9051ed..541bb2e65 100644 --- a/config/routes/test.rb +++ b/config/routes/test.rb @@ -9,6 +9,7 @@ Zammad::Application.routes.draw do match '/tests-form-validation', :to => 'tests#form_validation', :via => :get match '/tests-table', :to => 'tests#table', :via => :get match '/tests-html-utils', :to => 'tests#html_utils', :via => :get + match '/tests-taskbar', :to => 'tests#taskbar', :via => :get match '/tests/wait/:sec', :to => 'tests#wait', :via => :get end \ No newline at end of file diff --git a/lib/sessions/backend/ticket_overview_index.rb b/lib/sessions/backend/ticket_overview_index.rb index 67e89c8ad..5f7b0eb01 100644 --- a/lib/sessions/backend/ticket_overview_index.rb +++ b/lib/sessions/backend/ticket_overview_index.rb @@ -44,14 +44,14 @@ class Sessions::Backend::TicketOverviewIndex if !@client return { - :event => 'navupdate_ticket_overview', + :event => 'ticket_overview_index', :data => data, } end @client.log 'notify', "push overview_index for user #{ @user.id }" @client.send({ - :event => 'navupdate_ticket_overview', + :event => ['ticket_overview_index'], :data => data, }) end diff --git a/lib/sessions/backend/ticket_overview_list.rb b/lib/sessions/backend/ticket_overview_list.rb index 2119b428a..b2671c11a 100644 --- a/lib/sessions/backend/ticket_overview_list.rb +++ b/lib/sessions/backend/ticket_overview_list.rb @@ -105,16 +105,16 @@ class Sessions::Backend::TicketOverviewList }) @client.send({ :data => { + :view => item[:index].link.to_s, :overview => overview_data[:overview], :ticket_ids => overview_data[:ticket_ids], :tickets_count => overview_data[:tickets_count], - :bulk => { + :bulk => { :group_id__owner_id => groups_users, :owner_id => [], }, }, - :event => [ 'ticket_overview_rebuild' ], - :collection => 'ticket_overview_' + item[:index].link.to_s, + :event => [ 'ticket_overview_rebuild' ], }) end } diff --git a/public/assets/tests/taskbar.js b/public/assets/tests/taskbar.js new file mode 100644 index 000000000..b13deabeb --- /dev/null +++ b/public/assets/tests/taskbar.js @@ -0,0 +1,235 @@ +window.onload = function() { + +test( "taskbar basic tests", function() { + // create task bar div + $('#taskbars').append('

taskbar basic tests

') + App.TaskManager.init({ + el: $('#taskbar1'), + offlineModus: true, + }) + + // add tasks + App.TaskManager.execute({ + key: 'TestKey1', + controller: 'TestController1', + params: { + message: '#1', + }, + show: true, + persistent: false, + }) + equal( $('#taskbars .content').length, 1, "check available active contents" ); + equal( $('#taskbars .content.active').length, 1, "check available active contents" ); + equal( $('#taskbars .content.active').text(), "some test controller message:'#1',show:'true',hide:'false',active:'true'", "check active content!" ); + + App.TaskManager.execute({ + key: 'TestKey2', + controller: 'TestController1', + params: { + message: '#2', + }, + show: true, + persistent: false, + }) + equal( $('#taskbars .content').length, 2, "check available active contents" ); + equal( $('#taskbars .content.active').length, 1, "check available active contents" ); + equal( $('#taskbars .content.active').text(), "some test controller message:'#2',show:'true',hide:'false',active:'true'", "check active content!" ); + + equal( $('#taskbars #content_permanent_TestKey1').text(), "some test controller message:'#1',show:'true',hide:'true',active:'false'", "check active content!" ); + + // check task history + equal( App.TaskManager.nextTaskUrl(), '#/some/url/#2') + equal( App.TaskManager.nextTaskUrl(), '#/some/url/#1') + + App.TaskManager.execute({ + key: 'TestKey3', + controller: 'TestController1', + params: { + message: '#3', + }, + show: false, + persistent: false, + }) + equal( $('#taskbars .content').length, 3, "check available active contents" ); + equal( $('#taskbars .content.active').length, 1, "check available active contents" ); + equal( $('#taskbars .content.active').text(), "some test controller message:'#2',show:'true',hide:'false',active:'true'" ); + + equal( $('#taskbars #content_permanent_TestKey1').text(), "some test controller message:'#1',show:'true',hide:'true',active:'false'", "check active content!" ); + equal( $('#taskbars #content_permanent_TestKey3').text(), "some test controller message:'#3',show:'false',hide:'true',active:'false'", "check active content!" ); + + + App.TaskManager.execute({ + key: 'TestKey4', + controller: 'TestController1', + params: { + message: '#4', + }, + show: false, + persistent: true, + }) + equal( $('#taskbars .content').length, 4, "check available active contents" ); + equal( $('#taskbars .content.active').length, 1, "check available active contents" ); + equal( $('#taskbars .content.active').text(), "some test controller message:'#2',show:'true',hide:'false',active:'true'" ); + + equal( $('#taskbars #content_permanent_TestKey1').text(), "some test controller message:'#1',show:'true',hide:'true',active:'false'", "check active content!" ); + equal( $('#taskbars #content_permanent_TestKey3').text(), "some test controller message:'#3',show:'false',hide:'true',active:'false'", "check active content!" ); + equal( $('#taskbars #content_permanent_TestKey4').text(), "some test controller message:'#4',show:'false',hide:'true',active:'false'", "check active content!" ); + + + App.TaskManager.execute({ + key: 'TestKey5', + controller: 'TestController1', + params: { + message: '#5', + }, + show: true, + persistent: true, + }) + equal( $('#taskbars .content').length, 5, "check available active contents" ); + equal( $('#taskbars .content.active').length, 1, "check available active contents" ); + equal( $('#taskbars .content.active').text(), "some test controller message:'#5',show:'true',hide:'false',active:'true'" ); + + equal( $('#taskbars #content_permanent_TestKey1').text(), "some test controller message:'#1',show:'true',hide:'true',active:'false'", "check active content!" ); + equal( $('#taskbars #content_permanent_TestKey2').text(), "some test controller message:'#2',show:'true',hide:'true',active:'false'", "check active content!" ); + equal( $('#taskbars #content_permanent_TestKey3').text(), "some test controller message:'#3',show:'false',hide:'true',active:'false'", "check active content!" ); + equal( $('#taskbars #content_permanent_TestKey4').text(), "some test controller message:'#4',show:'false',hide:'true',active:'false'", "check active content!" ); + + + App.TaskManager.execute({ + key: 'TestKey6', + controller: 'TestController1', + params: { + message: '#6', + }, + show: true, + persistent: false, + }) + equal( $('#taskbars .content').length, 6, "check available active contents" ); + equal( $('#taskbars .content.active').length, 1, "check available active contents" ); + equal( $('#taskbars .content.active').text(), "some test controller message:'#6',show:'true',hide:'false',active:'true'" ); + + equal( $('#taskbars #content_permanent_TestKey1').text(), "some test controller message:'#1',show:'true',hide:'true',active:'false'", "check active content!" ); + equal( $('#taskbars #content_permanent_TestKey2').text(), "some test controller message:'#2',show:'true',hide:'true',active:'false'", "check active content!" ); + equal( $('#taskbars #content_permanent_TestKey3').text(), "some test controller message:'#3',show:'false',hide:'true',active:'false'", "check active content!" ); + equal( $('#taskbars #content_permanent_TestKey4').text(), "some test controller message:'#4',show:'false',hide:'true',active:'false'", "check active content!" ); + equal( $('#taskbars #content_permanent_TestKey5').text(), "some test controller message:'#5',show:'true',hide:'true',active:'false'", "check active content!" ); + + + // remove task#2 + App.TaskManager.remove('TestKey2') + + equal( $('#taskbars .content').length, 5, "check available active contents" ); + equal( $('#taskbars .content.active').length, 1, "check available active contents" ); + equal( $('#taskbars .content.active').text(), "some test controller message:'#6',show:'true',hide:'false',active:'true'" ); + + equal( $('#taskbars #content_permanent_TestKey1').text(), "some test controller message:'#1',show:'true',hide:'true',active:'false'", "check active content!" ); + equal( $('#taskbars #content_permanent_TestKey3').text(), "some test controller message:'#3',show:'false',hide:'true',active:'false'", "check active content!" ); + equal( $('#taskbars #content_permanent_TestKey4').text(), "some test controller message:'#4',show:'false',hide:'true',active:'false'", "check active content!" ); + equal( $('#taskbars #content_permanent_TestKey5').text(), "some test controller message:'#5',show:'true',hide:'true',active:'false'", "check active content!" ); + + // activate task#3 + App.TaskManager.execute({ + key: 'TestKey3', + controller: 'TestController1', + params: { + message: '#3', + }, + show: true, + persistent: false, + }) + equal( $('#taskbars .content').length, 5, "check available active contents" ); + equal( $('#taskbars .content.active').length, 1, "check available active contents" ); + equal( $('#taskbars .content.active').text(), "some test controller message:'#3',show:'true',hide:'true',active:'true'" ); + + equal( $('#taskbars #content_permanent_TestKey1').text(), "some test controller message:'#1',show:'true',hide:'true',active:'false'", "check active content!" ); + equal( $('#taskbars #content_permanent_TestKey4').text(), "some test controller message:'#4',show:'false',hide:'true',active:'false'", "check active content!" ); + equal( $('#taskbars #content_permanent_TestKey5').text(), "some test controller message:'#5',show:'true',hide:'true',active:'false'", "check active content!" ); + + + // activate task#1 + App.TaskManager.execute({ + key: 'TestKey1', + controller: 'TestController1', + params: { + message: '#1', + }, + show: true, + persistent: false, + }) + equal( $('#taskbars .content').length, 5, "check available active contents" ); + equal( $('#taskbars .content.active').length, 1, "check available active contents" ); + equal( $('#taskbars .content.active').text(), "some test controller message:'#1',show:'true',hide:'true',active:'true'" ); + + equal( $('#taskbars #content_permanent_TestKey3').text(), "some test controller message:'#3',show:'true',hide:'true',active:'false'", "check active content!" ); + equal( $('#taskbars #content_permanent_TestKey4').text(), "some test controller message:'#4',show:'false',hide:'true',active:'false'", "check active content!" ); + equal( $('#taskbars #content_permanent_TestKey5').text(), "some test controller message:'#5',show:'true',hide:'true',active:'false'", "check active content!" ); + + + // remove task#1 + App.TaskManager.remove('TestKey1') + + // verify if task#3 is active + equal( $('#taskbars .content').length, 4, "check available active contents" ); + equal( $('#taskbars .content.active').length, 0, "check available active contents" ); + equal( $('#taskbars .content.active').text(), "" ); + + // remove task#3 + App.TaskManager.remove('TestKey3') + + // verify if task#5 is active + equal( $('#taskbars .content').length, 3, "check available active contents" ); + equal( $('#taskbars .content.active').length, 0, "check available active contents" ); + equal( $('#taskbars .content.active').text(), "" ); + + // remove task#5 // can not get removed because of permanent task + App.TaskManager.remove('TestKey5') + + // verify if task#5 is active + equal( $('#taskbars .content').length, 3, "check available active contents" ); + equal( $('#taskbars .content.active').length, 0, "check available active contents" ); + equal( $('#taskbars .content.active').text(), "" ); + + // create task#7 + App.TaskManager.execute({ + key: 'TestKey7', + controller: 'TestController1', + params: { + message: '#7', + }, + show: true, + persistent: false, + }) + equal( $('#taskbars .content').length, 4, "check available active contents" ); + equal( $('#taskbars .content.active').length, 1, "check available active contents" ); + equal( $('#taskbars .content.active').text(), "some test controller message:'#7',show:'true',hide:'false',active:'true'", "check active content!" ); + + // remove task#7 + App.TaskManager.remove('TestKey7') + + // verify if task#5 is active + equal( $('#taskbars .content').length, 3, "check available active contents" ); + equal( $('#taskbars .content.active').length, 0, "check available active contents" ); + equal( $('#taskbars .content.active').text(), "" ); + + // check task history + equal( App.TaskManager.nextTaskUrl(), '#/some/url/#6') + equal( App.TaskManager.nextTaskUrl(), '#/some/url/#5') + equal( App.TaskManager.nextTaskUrl(), '#/some/url/#6') + equal( App.TaskManager.nextTaskUrl(), '#/some/url/#6') + + // remove task#6 + App.TaskManager.remove('TestKey6') + + // check task history + equal( App.TaskManager.nextTaskUrl(), false) + equal( App.TaskManager.nextTaskUrl(), false) + + // destroy task bar + App.TaskManager.reset() + + // check if any taskar exists + equal( $('#taskbars .content').length, 0, "check available active contents" ); + +}) + +}