Added ajax long polling.
This commit is contained in:
parent
f496f82669
commit
5e69e1af4e
13 changed files with 314 additions and 118 deletions
|
@ -8,8 +8,6 @@ class App.DashboardActivityStream extends App.Controller
|
|||
super
|
||||
@items = []
|
||||
|
||||
# refresh list ever 140 sec.
|
||||
# @interval( @fetch, 1400000, 'dashboard_activity_stream' )
|
||||
@fetch()
|
||||
|
||||
# bind to rebuild view event
|
||||
|
@ -22,17 +20,20 @@ class App.DashboardActivityStream extends App.Controller
|
|||
if cache
|
||||
@load( cache )
|
||||
|
||||
# # get data
|
||||
# App.Com.ajax(
|
||||
# id: 'dashoard_activity_stream',
|
||||
# type: 'GET',
|
||||
# url: '/api/activity_stream',
|
||||
# data: {
|
||||
# limit: @limit,
|
||||
# }
|
||||
# processData: true,
|
||||
# success: @load
|
||||
# )
|
||||
# init fetch via ajax, all other updates on time via websockets
|
||||
else
|
||||
App.Com.ajax(
|
||||
id: 'dashoard_activity_stream'
|
||||
type: 'GET'
|
||||
url: '/api/activity_stream'
|
||||
data: {
|
||||
limit: 8
|
||||
}
|
||||
processData: true
|
||||
success: (data) =>
|
||||
App.Store.write( 'activity_stream', data )
|
||||
@load(data)
|
||||
)
|
||||
|
||||
load: (data) =>
|
||||
items = data.activity_stream
|
||||
|
|
|
@ -11,19 +11,42 @@ class App.DashboardRss extends App.Controller
|
|||
@fetch()
|
||||
|
||||
fetch: =>
|
||||
|
||||
# get data from cache
|
||||
cache = App.Store.get( 'dashboard_rss' )
|
||||
if cache
|
||||
@load( cache )
|
||||
@render( cache )
|
||||
|
||||
load: (data) =>
|
||||
items = data.items || []
|
||||
@head = data.head || '?'
|
||||
@render(items)
|
||||
|
||||
render: (items) ->
|
||||
html = App.view('dashboard/rss')(
|
||||
head: @head,
|
||||
items: items
|
||||
# init fetch via ajax, all other updates on time via websockets
|
||||
else
|
||||
App.Com.ajax(
|
||||
id: 'dashboard_rss'
|
||||
type: 'GET'
|
||||
url: '/api/rss_fetch'
|
||||
data: {
|
||||
limit: 8
|
||||
url: 'http://www.heise.de/newsticker/heise-atom.xml'
|
||||
}
|
||||
processData: true
|
||||
success: (data) =>
|
||||
if data.message
|
||||
@render(
|
||||
head: 'Heise ATOM'
|
||||
message: data.message
|
||||
)
|
||||
else
|
||||
App.Store.write( 'dashboard_rss', data )
|
||||
@render(data)
|
||||
error: =>
|
||||
@render(
|
||||
head: 'Heise ATOM'
|
||||
message: 'Unable to fetch rss!'
|
||||
)
|
||||
)
|
||||
|
||||
render: (data) ->
|
||||
@html App.view('dashboard/rss')(
|
||||
head: data.head,
|
||||
items: data.item || []
|
||||
message: data.message
|
||||
)
|
||||
html = $(html)
|
||||
@html html
|
||||
|
|
|
@ -25,25 +25,37 @@ class App.DashboardTicket extends App.Controller
|
|||
# use cache of first page
|
||||
cache = App.Store.get( @key )
|
||||
if cache
|
||||
# @render( cache )
|
||||
@load( cache )
|
||||
|
||||
# get data
|
||||
# App.Com.ajax(
|
||||
# id: 'dashboard_ticket_' + @key,
|
||||
# type: 'GET',
|
||||
# url: '/api/ticket_overviews',
|
||||
# data: {
|
||||
# view: @view,
|
||||
# view_mode: 'd',
|
||||
# start_page: @start_page,
|
||||
# }
|
||||
# processData: true,
|
||||
# success: @load
|
||||
# )
|
||||
# init fetch via ajax, all other updates on time via websockets
|
||||
else
|
||||
App.Com.ajax(
|
||||
id: 'dashboard_ticket_' + @key,
|
||||
type: 'GET',
|
||||
url: '/api/ticket_overviews',
|
||||
data: {
|
||||
view: @view,
|
||||
view_mode: 'd',
|
||||
start_page: @start_page,
|
||||
}
|
||||
processData: true,
|
||||
success: (data) =>
|
||||
data.ajax = true
|
||||
@load(data)
|
||||
)
|
||||
|
||||
load: (data) =>
|
||||
|
||||
if data.ajax
|
||||
data.ajax = false
|
||||
App.Store.write( @key, data )
|
||||
|
||||
# load user collection
|
||||
App.Collection.load( type: 'User', data: data.collections.users )
|
||||
|
||||
# load ticket collection
|
||||
App.Collection.load( type: 'Ticket', data: data.collections.tickets )
|
||||
|
||||
# get meta data
|
||||
App.Overview.refresh( data.overview, options: { clear: true } )
|
||||
|
||||
|
@ -57,11 +69,12 @@ class App.DashboardTicket extends App.Controller
|
|||
@log 'refetch...', record
|
||||
@fetch()
|
||||
|
||||
# App.Store.write( @key, data )
|
||||
|
||||
@render( data )
|
||||
|
||||
render: (data) ->
|
||||
return if !data
|
||||
return if !data.ticket_list
|
||||
return if !data.overview
|
||||
|
||||
@overview = data.overview
|
||||
@tickets_count = data.tickets_count
|
||||
|
|
|
@ -37,12 +37,42 @@ class Index extends App.Controller
|
|||
# use cache of first page
|
||||
cache = App.Store.get( @key )
|
||||
if cache
|
||||
@overview = cache.overview
|
||||
@tickets_count = cache.tickets_count
|
||||
@ticket_list = cache.ticket_list
|
||||
@load(cache)
|
||||
|
||||
# init fetch via ajax, all other updates on time via websockets
|
||||
else
|
||||
App.Com.ajax(
|
||||
id: 'ticket_overview_' + @key,
|
||||
type: 'GET',
|
||||
url: '/api/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_list
|
||||
return if !data.overview
|
||||
|
||||
@overview = data.overview
|
||||
@tickets_count = data.tickets_count
|
||||
@ticket_list = data.ticket_list
|
||||
|
||||
if data.ajax
|
||||
data.ajax = false
|
||||
App.Store.write( @key, data )
|
||||
|
||||
# load user collection
|
||||
App.Collection.load( type: 'User', data: data.collections.users )
|
||||
|
||||
# load ticket collection
|
||||
App.Collection.load( type: 'Ticket', data: data.collections.tickets )
|
||||
|
||||
# get meta data
|
||||
@overview = data.overview
|
||||
|
|
|
@ -5,9 +5,7 @@ class App.Com
|
|||
@ajax: (args) -> # Must be a static method
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
|
||||
_instance.ajax(args)
|
||||
_instance
|
||||
|
||||
# The actual Singleton class
|
||||
class _Singleton
|
||||
|
|
|
@ -9,7 +9,7 @@ class App.WebSocket
|
|||
|
||||
@close: (args) -> # Must be a static method
|
||||
if _instance isnt undefined
|
||||
_instance.close()
|
||||
_instance.close(args)
|
||||
|
||||
@send: (args) -> # Must be a static method
|
||||
@connect()
|
||||
|
@ -20,6 +20,7 @@ class App.WebSocket
|
|||
_instance.auth(args)
|
||||
|
||||
@_spool: ->
|
||||
@connect()
|
||||
_instance.spool()
|
||||
|
||||
# The actual Singleton class
|
||||
|
@ -30,6 +31,9 @@ class _Singleton extends App.Controller
|
|||
supported: true
|
||||
lastSpoolMessage: undefined
|
||||
connectionEstablished: false
|
||||
connectionWasEstablished: false
|
||||
backend: 'websocket'
|
||||
client_id: undefined
|
||||
|
||||
constructor: (@args) ->
|
||||
|
||||
|
@ -46,7 +50,10 @@ class _Singleton extends App.Controller
|
|||
@connect()
|
||||
|
||||
send: (data) =>
|
||||
return if !@supported
|
||||
if @backend is 'ajax'
|
||||
@_ajaxSend(data)
|
||||
else
|
||||
|
||||
# console.log 'ws:send trying', data, @ws, @ws.readyState
|
||||
|
||||
# A value of 0 indicates that the connection has not yet been established.
|
||||
|
@ -77,7 +84,7 @@ class _Singleton extends App.Controller
|
|||
if @lastSpoolMessage
|
||||
data['timestamp'] = @lastSpoolMessage
|
||||
|
||||
@log 'Event', 'debug', 'spool', data
|
||||
@log 'Websocket', 'debug', 'spool', data
|
||||
|
||||
# ask for spool messages
|
||||
App.Event.trigger(
|
||||
|
@ -89,37 +96,38 @@ class _Singleton extends App.Controller
|
|||
@lastSpoolMessage = Math.round( +new Date()/1000 )
|
||||
|
||||
close: =>
|
||||
return if !@supported
|
||||
return if @backend is 'ajax'
|
||||
|
||||
@ws.close()
|
||||
|
||||
ping: =>
|
||||
return if !@supported
|
||||
return if @backend is 'ajax'
|
||||
|
||||
@log 'Event', 'debug', 'send websockend ping'
|
||||
@log 'Websocket', 'debug', 'send websockend ping'
|
||||
@send( { action: 'ping' } )
|
||||
|
||||
# check if ping is back within 2 min
|
||||
@clearDelay('websocket-ping-check')
|
||||
check = =>
|
||||
@log 'Event', 'notice', 'no websockend ping response, reconnect...'
|
||||
@log 'Websocket', 'notice', 'no websockend ping response, reconnect...'
|
||||
@close()
|
||||
@delay check, 120000, 'websocket-ping-check'
|
||||
|
||||
pong: ->
|
||||
return if !@supported
|
||||
@log 'Event', 'debug', 'received websockend ping'
|
||||
return if @backend is 'ajax'
|
||||
|
||||
@log 'Websocket', 'debug', 'received websockend ping'
|
||||
|
||||
# test again after 1 min
|
||||
@delay @ping, 60000
|
||||
|
||||
connect: =>
|
||||
return if @backend is 'ajax'
|
||||
|
||||
if !window.WebSocket
|
||||
@error = new App.ErrorModal(
|
||||
message: 'Sorry, no websocket support!'
|
||||
)
|
||||
@supported = false
|
||||
@backend = 'ajax'
|
||||
@log 'WebSocket', 'notice', 'no support of websocket, use ajax long polling'
|
||||
@_ajaxInit()
|
||||
return
|
||||
|
||||
protocol = 'ws://'
|
||||
|
@ -130,9 +138,10 @@ class _Singleton extends App.Controller
|
|||
|
||||
# Set event handlers.
|
||||
@ws.onopen = =>
|
||||
@log 'Event', 'notice', 'new websocked connection open'
|
||||
@log 'Websocket', 'notice', 'new websocket connection open'
|
||||
|
||||
@connectionEstablished = true
|
||||
@connectionWasEstablished = true
|
||||
|
||||
# close error message show up (because try so connect again) if exists
|
||||
@clearDelay('websocket-no-connection-try-reconnect')
|
||||
|
@ -144,7 +153,7 @@ class _Singleton extends App.Controller
|
|||
|
||||
# empty queue
|
||||
for item in @queue
|
||||
@log 'Event', 'debug', 'empty ws queue', item
|
||||
@log 'Websocket', 'debug', 'empty ws queue', item
|
||||
@send(item)
|
||||
@queue = []
|
||||
|
||||
|
@ -153,41 +162,31 @@ class _Singleton extends App.Controller
|
|||
|
||||
@ws.onmessage = (e) =>
|
||||
pipe = JSON.parse( e.data )
|
||||
@log 'Event', 'debug', 'ws:onmessage', pipe
|
||||
|
||||
# go through all blocks
|
||||
for item in pipe
|
||||
|
||||
# reset reconnect loop
|
||||
if item['action'] is 'pong'
|
||||
@pong()
|
||||
|
||||
# fill collection
|
||||
if item['collection']
|
||||
@log 'Event', 'debug', "ws:onmessage collection:" + item['collection']
|
||||
App.Store.write( item['collection'], item['data'] )
|
||||
|
||||
# fire event
|
||||
if item['event']
|
||||
if typeof item['event'] is 'object'
|
||||
for event in item['event']
|
||||
@log 'Event', 'debug', "ws:onmessage event:" + event
|
||||
App.Event.trigger( event, item['data'] )
|
||||
else
|
||||
@log 'Event', 'debug', "ws:onmessage event:" + item['event']
|
||||
App.Event.trigger( item['event'], item['data'] )
|
||||
@log 'Websocket', 'debug', 'ws:onmessage', pipe
|
||||
@_receiveMessage(pipe)
|
||||
|
||||
@ws.onclose = (e) =>
|
||||
@log 'Event', 'debug', "ws:onclose", e
|
||||
@log 'Websocket', 'debug', "ws:onclose", e
|
||||
|
||||
# set timestamp to get spool messages later
|
||||
if @connectionEstablished
|
||||
@lastSpoolMessage = Math.round( +new Date()/1000 )
|
||||
@connectionEstablished = false
|
||||
|
||||
return if @backend is 'ajax'
|
||||
|
||||
# show error message, first try to reconnect
|
||||
if !@error
|
||||
message = =>
|
||||
|
||||
# use fallback if no connection was possible
|
||||
if !@connectionWasEstablished
|
||||
@backend = 'ajax'
|
||||
@log 'WebSocket', 'notice', 'No connection to websocket, use use ajax long polling as fallback'
|
||||
@_ajaxInit()
|
||||
return
|
||||
|
||||
# show reconnect message
|
||||
@error = new App.ErrorModal(
|
||||
message: 'No connection to websocket, trying to reconnect...'
|
||||
)
|
||||
|
@ -197,5 +196,110 @@ class _Singleton extends App.Controller
|
|||
@delay @connect, 4500
|
||||
|
||||
@ws.onerror = (e) =>
|
||||
@log 'Event', 'debug', "ws:onerror", e
|
||||
@log 'Websocket', 'debug', "ws:onerror", e
|
||||
|
||||
_receiveMessage: (data = []) =>
|
||||
|
||||
# go through all blocks
|
||||
for item in data
|
||||
|
||||
# reset reconnect loop
|
||||
if item['action'] is 'pong'
|
||||
@pong()
|
||||
|
||||
# fill collection
|
||||
if item['collection']
|
||||
@log 'Websocket', 'debug', "onmessage collection:" + item['collection']
|
||||
App.Store.write( item['collection'], item['data'] )
|
||||
|
||||
# fire event
|
||||
if item['event']
|
||||
if typeof item['event'] is 'object'
|
||||
for event in item['event']
|
||||
@log 'Websocket', 'debug', "onmessage event:" + event
|
||||
App.Event.trigger( event, item['data'] )
|
||||
else
|
||||
@log 'Websocket', 'debug', "onmessage event:" + item['event']
|
||||
App.Event.trigger( item['event'], item['data'] )
|
||||
|
||||
_ajaxInit: (data = {}) =>
|
||||
|
||||
# return if init is already done and not forced
|
||||
return if @_ajaxInitDone && !data.force
|
||||
|
||||
# stop init request if new one is started
|
||||
if @_ajaxInitWorking
|
||||
console.log '@_ajaxInitWorking', @_ajaxInitWorking
|
||||
@_ajaxInitWorking.abort()
|
||||
|
||||
# call init request
|
||||
@_ajaxInitWorking = App.Com.ajax(
|
||||
type: 'POST'
|
||||
url: '/api/message_send'
|
||||
data: JSON.stringify({ data: { action: 'login' } })
|
||||
processData: false
|
||||
queue: false
|
||||
success: (data) =>
|
||||
if data.client_id
|
||||
@log 'Websocket', 'notice', 'ajax:new client_id', data.client_id
|
||||
@client_id = data.client_id
|
||||
@_ajaxReceive()
|
||||
@_ajaxSendQueue()
|
||||
@_ajaxInitDone = true
|
||||
@_ajaxInitWorking = false
|
||||
error: =>
|
||||
@_ajaxInitDone = true
|
||||
@_ajaxInitWorking = false
|
||||
)
|
||||
|
||||
_ajaxSend: (data) =>
|
||||
@log 'Websocket', 'debug', 'ajax:sendmessage', data
|
||||
if !@client_id || @client_id is undefined || !@_ajaxInitDone
|
||||
@_ajaxInit()
|
||||
@queue.push data
|
||||
else
|
||||
@queue.push data
|
||||
@_ajaxSendQueue()
|
||||
|
||||
_ajaxSendQueue: =>
|
||||
while !_.isEmpty(@queue)
|
||||
data = @queue.shift()
|
||||
App.Com.ajax(
|
||||
type: 'POST'
|
||||
url: '/api/message_send'
|
||||
data: JSON.stringify({ client_id: @client_id, data: data })
|
||||
processData: false
|
||||
queue: true
|
||||
success: (data) =>
|
||||
if data && data.error
|
||||
@client_id = undefined
|
||||
@_ajaxInit( force: true )
|
||||
error: =>
|
||||
@client_id = undefined
|
||||
@_ajaxInit( force: true )
|
||||
)
|
||||
|
||||
_ajaxReceive: =>
|
||||
return if !@client_id
|
||||
return if @_ajaxReceiveWorking is true
|
||||
@_ajaxReceiveWorking = true
|
||||
App.Com.ajax(
|
||||
id: 'message_receive',
|
||||
type: 'POST'
|
||||
url: '/api/message_receive'
|
||||
data: JSON.stringify({ client_id: @client_id })
|
||||
processData: false
|
||||
success: (data) =>
|
||||
@log 'Websocket', 'notice', 'ajax:onmessage', data
|
||||
@_receiveMessage(data)
|
||||
if data && data.error
|
||||
@client_id = undefined
|
||||
@_ajaxInit( force: true )
|
||||
@_ajaxReceiveWorking = false
|
||||
@_ajaxReceive()
|
||||
error: (data) =>
|
||||
@client_id = undefined
|
||||
@_ajaxInit( force: true )
|
||||
@_ajaxReceiveWorking = false
|
||||
@delay @_ajaxReceive, 5000
|
||||
)
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
<div class="row">
|
||||
<div class="span3 can-move">
|
||||
<h2><%- @T( @head ) %></h2>
|
||||
<% if @message: %>
|
||||
<%- @T(@message) %>
|
||||
<% end %>
|
||||
<ul>
|
||||
<% for item in @items: %>
|
||||
<li><a href="<%= item.link %>" title="<%= item.summary %>" target="_blank"><%= item.title %>"</a></li>
|
||||
|
|
|
@ -3,7 +3,7 @@ class ActivityController < ApplicationController
|
|||
|
||||
# GET /api/activity_stream
|
||||
def activity_stream
|
||||
activity_stream = History.activity_stream_fulldata(current_user, params[:limit])
|
||||
activity_stream = History.activity_stream_fulldata( current_user, params[:limit] )
|
||||
|
||||
# return result
|
||||
render :json => activity_stream
|
||||
|
|
|
@ -20,6 +20,7 @@ curl http://localhost/api/rss_fetch.json -v -u #{login}:#{password} -H "Content-
|
|||
items = RSS.fetch(params[:url], params[:limit])
|
||||
if items == nil
|
||||
render :json => { :message => "failed to fetch #{ params[:url] }", :status => :unprocessable_entity }
|
||||
return
|
||||
end
|
||||
render :json => { :items => items }
|
||||
end
|
||||
|
|
|
@ -22,8 +22,8 @@ class TicketOverviewsController < ApplicationController
|
|||
:array => true,
|
||||
)
|
||||
tickets = []
|
||||
overview[:tickets].each {|ticket|
|
||||
data = { :id => ticket.id }
|
||||
overview[:tickets].each {|ticket_id|
|
||||
data = { :id => ticket_id }
|
||||
tickets.push data
|
||||
}
|
||||
|
||||
|
@ -37,17 +37,20 @@ class TicketOverviewsController < ApplicationController
|
|||
end
|
||||
overview = Ticket.overview(
|
||||
:view => params[:view],
|
||||
:view_mode => params[:view_mode],
|
||||
:current_user_id => current_user.id,
|
||||
:start_page => params[:start_page],
|
||||
# :view_mode => params[:view_mode],
|
||||
:current_user => User.find( current_user.id ),
|
||||
:array => true,
|
||||
)
|
||||
if !overview
|
||||
render :json => { :error => "No such view #{ params[:view] }!" }, :status => :unprocessable_entity
|
||||
return
|
||||
end
|
||||
|
||||
# get related users
|
||||
users = {}
|
||||
tickets = []
|
||||
overview[:tickets].each {|ticket|
|
||||
data = Ticket.full_data(ticket.id)
|
||||
overview[:ticket_list].each {|ticket_id|
|
||||
data = Ticket.full_data(ticket_id)
|
||||
tickets.push data
|
||||
if !users[ data['owner_id'] ]
|
||||
users[ data['owner_id'] ] = User.user_data_full( data['owner_id'] )
|
||||
|
@ -84,12 +87,15 @@ class TicketOverviewsController < ApplicationController
|
|||
# return result
|
||||
render :json => {
|
||||
:overview => overview[:overview],
|
||||
:tickets => tickets,
|
||||
:ticket_list => overview[:ticket_list],
|
||||
:tickets_count => overview[:tickets_count],
|
||||
:users => users,
|
||||
:bulk => {
|
||||
:group_id__owner_id => groups_users,
|
||||
},
|
||||
:collections => {
|
||||
:users => users,
|
||||
:tickets => tickets,
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
@ -217,6 +217,10 @@ class Ticket < ApplicationModel
|
|||
}
|
||||
}
|
||||
|
||||
if data[:view] && !overview_selected
|
||||
return
|
||||
end
|
||||
|
||||
# sortby
|
||||
# prio
|
||||
# state
|
||||
|
@ -290,7 +294,7 @@ class Ticket < ApplicationModel
|
|||
count()
|
||||
|
||||
return {
|
||||
:tickets => ticket_ids,
|
||||
:ticket_list => ticket_ids,
|
||||
:tickets_count => tickets_count,
|
||||
:overview => overview_selected_raw,
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ module RSS
|
|||
rescue Exception => e
|
||||
puts "can't fetch #{url}"
|
||||
puts e.inspect
|
||||
return
|
||||
end
|
||||
|
||||
return items
|
||||
|
|
|
@ -40,6 +40,16 @@ module Session
|
|||
return session_list
|
||||
end
|
||||
|
||||
def self.touch( client_id )
|
||||
data = self.get(client_id)
|
||||
path = @path + '/' + client_id.to_s
|
||||
data[:meta][:last_ping] = Time.new.to_i.to_s
|
||||
File.open( path + '/session', 'w' ) { |file|
|
||||
file.puts Marshal.dump(data)
|
||||
}
|
||||
return true
|
||||
end
|
||||
|
||||
def self.get( client_id )
|
||||
session_file = @path + '/' + client_id.to_s + '/session'
|
||||
data = nil
|
||||
|
@ -105,6 +115,7 @@ module Session
|
|||
@@user_threads[user.id] = Thread.new {
|
||||
UserState.new(user.id)
|
||||
@@user_threads[user.id] = nil
|
||||
puts "close user(#{user.id}) thread"
|
||||
# raise "Exception from thread"
|
||||
}
|
||||
end
|
||||
|
@ -119,13 +130,14 @@ module Session
|
|||
@@client_threads[client_id] = Thread.new {
|
||||
ClientState.new(client_id)
|
||||
@@client_threads[client_id] = nil
|
||||
puts "close client(#{client_id}) thread"
|
||||
# raise "Exception from thread"
|
||||
}
|
||||
end
|
||||
}
|
||||
|
||||
# system settings
|
||||
sleep 0.4
|
||||
sleep 0.5
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -464,7 +476,7 @@ class ClientState
|
|||
self.log 'notify', "push overview_data #{overview.meta[:url]} for user #{user.id}"
|
||||
users = {}
|
||||
tickets = []
|
||||
overview_data[:tickets].each {|ticket_id|
|
||||
overview_data[:ticket_list].each {|ticket_id|
|
||||
self.ticket( ticket_id, tickets, users )
|
||||
}
|
||||
|
||||
|
@ -494,7 +506,7 @@ class ClientState
|
|||
self.send({
|
||||
:data => {
|
||||
:overview => overview_data[:overview],
|
||||
:ticket_list => overview_data[:tickets],
|
||||
:ticket_list => overview_data[:ticket_list],
|
||||
:tickets_count => overview_data[:tickets_count],
|
||||
:collections => {
|
||||
:User => users,
|
||||
|
|
Loading…
Reference in a new issue