Improved reload and table rendering of report screens.

This commit is contained in:
Martin Edenhofer 2017-12-12 03:54:50 +01:00
parent 0064a5bb6a
commit 95e8aa2dce
14 changed files with 231 additions and 118 deletions

View file

@ -133,6 +133,8 @@ class App.ControllerTable extends App.Controller
customOrderDirection: undefined
customOrderBy: undefined
frontendTimeUpdateExecute: true
bindCol: {}
bindRow: {}
@ -269,6 +271,7 @@ class App.ControllerTable extends App.Controller
@currentRows = newCurrentRows
@log 'debug', 'table.fullRender.contentRemoved', removePositions, addPositions
@renderPager(@el, true)
@frontendTimeUpdateElement(@el) if @frontendTimeUpdateExecute is true
return ['fullRender.contentRemoved', removePositions, addPositions]
if newRows.length isnt @currentRows.length
@ -304,6 +307,7 @@ class App.ControllerTable extends App.Controller
else
@currentRows = clone(rows)
container.find('.js-tableBody').html(rows)
@frontendTimeUpdateElement(container) if @frontendTimeUpdateExecute is true
@renderPager(container)

View file

@ -108,33 +108,40 @@ class Graph extends App.ControllerContent
@render()
render: =>
update: (data) =>
update = (data) =>
# show only selected lines
dataNew = {}
for key, value of data.data
if @params.backendSelected[key] is true
dataNew[key] = value
@ui.storeParams()
# show only selected lines
dataNew = {}
for key, value of data.data
if @params.backendSelected[key] is true
dataNew[key] = value
@ui.storeParams()
if !@lastNewData
@lastNewData = {}
if !@lastNewData
@lastNewData = {}
return if @lastNewData && JSON.stringify(dataNew) is JSON.stringify(@lastNewData)
@lastNewData = dataNew
return if @lastNewData && JSON.stringify(dataNew) is JSON.stringify(@lastNewData)
@lastNewData = dataNew
@draw(dataNew)
t = new Date
@el.find('#download-chart').html(t.toString())
new Download(
@draw(dataNew)
t = new Date
@el.find('#download-chart').html(t.toString())
if @downloadWidget
@downloadWidget.update(
config: @config
params: @params
ui: @ui
)
else
@downloadWidget = new Download(
el: @el.find('.js-dataDownload')
config: @config
params: @params
ui: @ui
)
render: =>
url = "#{@apiPath}/reports/generate"
interval = 5 * 60000
if @params.timeRange is 'year'
@ -142,9 +149,9 @@ class Graph extends App.ControllerContent
if @params.timeRange is 'month'
interval = 60000
if @params.timeRange is 'week'
interval = 40000
interval = 50000
if @params.timeRange is 'day'
interval = 20000
interval = 30000
if @params.timeRange is 'realtime'
interval = 10000
@ -164,7 +171,7 @@ class Graph extends App.ControllerContent
)
processData: true
success: (data) =>
update(data)
@update(data)
@delay(@render, interval, 'report-update', 'page')
)
@ -215,7 +222,7 @@ class Graph extends App.ControllerContent
class Download extends App.Controller
events:
'click .js-dataDownloadBackendSelector': 'tableUpdate'
'click .js-dataDownloadBackendSelector': 'selectBackend'
constructor: (data) ->
@ -225,7 +232,24 @@ class Download extends App.Controller
super
@render()
render: ->
selectBackend: (e) =>
e.preventDefault()
@el.find('.js-dataDownloadBackendSelector').parent().removeClass('active')
$(e.target).parent().addClass('active')
@profileSelectedId = $(e.target).data('profile-id')
@params.downloadBackendSelected = $(e.target).data('backend')
@ui.storeParams()
@table = false
@render()
update: =>
@render()
render: =>
if !@contentRendered
@contentRendered = true
@html(App.view('report/download_content')())
reports = []
@ -244,44 +268,84 @@ class Download extends App.Controller
@profileSelectedId = key
profiles.push App.ReportProfile.find(key)
@html App.view('report/download_header')(
downloadHeaderHtml = App.view('report/download_header')(
reports: reports
profiles: profiles
downloadBackendSelected: @params.downloadBackendSelected
metric: @config.metric[@params.metric]
)
if downloadHeaderHtml isnt @downloadHeaderHtml
@el.find('.js-dataDownloadHeader').html(downloadHeaderHtml)
@downloadHeaderHtml = downloadHeaderHtml
@tableUpdate()
tableUpdate: (e) =>
if e
e.preventDefault()
@el.find('.js-dataDownloadBackendSelector').parent().removeClass('active')
$(e.target).parent().addClass('active')
@profileSelectedId = $(e.target).data('profile-id')
@params.downloadBackendSelected = $(e.target).data('backend')
@ui.storeParams()
tableRender: (tickets, count) =>
if _.isEmpty(tickets)
@$('.js-dataDownloadButton').html('')
@$('.js-dataDownloadTable').html('')
return
table = (tickets, count) =>
url = '#ticket/zoom/'
if App.Config.get('import_mode')
url = App.Config.get('import_otrs_endpoint') + '/index.pl?Action=AgentTicketZoom;TicketID='
if _.isEmpty(tickets)
@el.find('.js-dataDownloadTable').html('')
else
profile_id = 0
for key, value of @params.profileSelected
if value
profile_id = key
downloadUrl = "#{@apiPath}/reports/sets?sheet=true;metric=#{@params.metric};year=#{@params.year};month=#{@params.month};week=#{@params.week};day=#{@params.day};timeRange=#{@params.timeRange};profile_id=#{profile_id};downloadBackendSelected=#{@params.downloadBackendSelected}"
html = App.view('report/download_list')(
tickets: tickets
count: count
url: url
download: downloadUrl
)
@el.find('.js-dataDownloadTable').html(html)
profile_id = 0
for key, value of @params.profileSelected
if value
profile_id = key
downloadUrl = "#{@apiPath}/reports/sets?sheet=true;metric=#{@params.metric};year=#{@params.year};month=#{@params.month};week=#{@params.week};day=#{@params.day};timeRange=#{@params.timeRange};profile_id=#{profile_id};downloadBackendSelected=#{@params.downloadBackendSelected}"
@$('.js-dataDownloadButton').html(App.view('report/download_button')(
count: count
downloadUrl: downloadUrl
))
openTicket = (id,e) =>
ticket = App.Ticket.findNative(id)
@navigate ticket.uiUrl()
callbackTicketTitleAdd = (value, object, attribute, attributes) ->
attribute.title = object.title
value
callbackLinkToTicket = (value, object, attribute, attributes) ->
attribute.link = object.uiUrl()
value
callbackIconHeader = (headers) ->
attribute =
name: 'icon'
display: ''
translation: false
width: '28px'
displayWidth:28
unresizable: true
headers.unshift(0)
headers[0] = attribute
headers
callbackIcon = (value, object, attribute, header) ->
value = ' '
attribute.class = object.iconClass()
attribute.link = ''
attribute.title = object.iconTitle()
value
params =
el: @el.find('.js-dataDownloadTable')
model: App.Ticket
objects: tickets
overviewAttributes: ['number', 'title', 'state', 'group', 'created_at']
bindRow:
events:
'click': openTicket
callbackHeader: [ callbackIconHeader ]
callbackAttributes:
icon:
[ callbackIcon ]
title:
[ callbackLinkToTicket, callbackTicketTitleAdd ]
number:
[ callbackLinkToTicket, callbackTicketTitleAdd ]
if !@table
@table = new App.ControllerTable(params)
else
@table.update(objects: tickets)
tableUpdate: =>
@ajax(
id: 'report_download'
type: 'POST'
@ -298,15 +362,14 @@ class Download extends App.Controller
downloadBackendSelected: @params.downloadBackendSelected
)
processData: true
success: (data) ->
success: (data) =>
App.Collection.loadAssets(data.assets)
ticket_collection = []
if data.ticket_ids
for record_id in data.ticket_ids
ticket = App.Ticket.fullLocal( record_id )
ticket = App.Ticket.fullLocal(record_id)
ticket_collection.push ticket
table(ticket_collection, data.count)
@tableRender(ticket_collection, data.count)
)
class TimeRangePicker extends App.Controller

View file

@ -12,8 +12,8 @@ class App extends Spine.Controller
helper =
# define print name helper
P: (object, attributeName, attributes) ->
App.viewPrint(object, attributeName, attributes)
P: (object, attributeName, attributes, table = false) ->
App.viewPrint(object, attributeName, attributes, table)
# define date format helper
date: (time) ->
@ -136,7 +136,7 @@ class App extends Spine.Controller
return marked(string)
App.i18n.translateContent(string)
@viewPrint: (object, attributeName, attributes) ->
@viewPrint: (object, attributeName, attributes, table) ->
if !attributes
attributes = {}
if object.constructor.attributesGet
@ -172,10 +172,10 @@ class App extends Spine.Controller
if object[attributeNameWithoutRef]
valueRef = object[attributeNameWithoutRef]
@viewPrintItem(value, attributeConfig, valueRef)
@viewPrintItem(value, attributeConfig, valueRef, table)
# define print name helper
@viewPrintItem: (item, attributeConfig = {}, valueRef) ->
@viewPrintItem: (item, attributeConfig = {}, valueRef, table) ->
return '-' if item is undefined
return '-' if item is ''
return item if item is null
@ -238,7 +238,7 @@ class App extends Spine.Controller
# transform date
if attributeConfig.tag is 'date'
isHtmlEscape = true
resultLocal = App.i18n.translateDate(resultLocal)
resultLocal = App.i18n.translateDate(resultLocal)
# transform input tel|url to make it clickable
if attributeConfig.tag is 'input'
@ -258,8 +258,10 @@ class App extends Spine.Controller
cssClass = attributeConfig.class || ''
if cssClass.match 'escalation'
escalation = true
humanTime = App.PrettyDate.humanTime(resultLocal, escalation)
resultLocal = "<time class=\"humanTimeFromNow #{cssClass}\" data-time=\"#{resultLocal}\" title=\"#{timestamp}\">#{humanTime}</time>"
humanTime = ''
if !table
humanTime = App.PrettyDate.humanTime(resultLocal, escalation)
resultLocal = "<time class=\"humanTimeFromNow #{cssClass}\" data-time=\"#{resultLocal}\" title=\"#{timestamp}\">#{humanTime}</time>"
if !isHtmlEscape && typeof resultLocal is 'string'
resultLocal = App.Utils.htmlEscape(resultLocal)

View file

@ -21,7 +21,7 @@
</td>
<% end %>
<% for header in @headers: %>
<% value = @P(@object, header.name, @attributes) %>
<% value = @P(@object, header.name, @attributes, true) %>
<% if @callbacks: %>
<% for attribute, callbacksAll of @callbacks: %>
<% if attribute is header.name: %>

View file

@ -0,0 +1 @@
<a class="btn btn--action" href="<%- @downloadUrl %>" target="_blank" data-type="attachment"><%- @Icon('download') %><span><%- @T('Download %s record(s)', @count) %></span></a>

View file

@ -0,0 +1,6 @@
<div>
<div class="js-dataDownloadHeader"></div>
<div class="js-dataDownloadButton"></div>
<div class="spacer"></div>
<div class="js-dataDownloadTable"></div>
</div>

View file

@ -1,14 +1,9 @@
<div>
<ul class="nav nav-tabs">
<% for profile in @profiles: %>
<% for backend in @metric.backend: %>
<% if backend.dataDownload: %>
<li <% if backend.name is @downloadBackendSelected: %>class="is-active active"<% end %>><a href="#" class="js-dataDownloadBackendSelector" data-toggle="tab" data-profile-id="<%= profile.id %>" data-backend="<%= backend.name %>"><%- @T(backend.display) %></a></li>
<% end %>
<ul class="nav nav-tabs">
<% for profile in @profiles: %>
<% for backend in @metric.backend: %>
<% if backend.dataDownload: %>
<li <% if backend.name is @downloadBackendSelected: %>class="is-active active"<% end %>><a href="#" class="js-dataDownloadBackendSelector" data-toggle="tab" data-profile-id="<%= profile.id %>" data-backend="<%= backend.name %>"><%- @T(backend.display) %></a></li>
<% end %>
<% end %>
</ul>
<div class="js-dataDownloadTable"></div>
</div>
<% end %>
</ul>

View file

@ -1,24 +0,0 @@
<a class="btn btn--action" href="<%- @download %>" target="_blank" data-type="attachment"><%- @Icon('download') %><span><%- @T('Download %s record(s)', @count) %></span></a>
<div class="spacer"></div>
<table class="table table-striped table-hover">
<thead>
<tr>
<td><%- @T('Number') %></td>
<td><%- @T('Title') %></td>
<td><%- @T('State') %></td>
<td><%- @T('Group') %></td>
<td><%- @T('Created') %></td>
</tr>
</thead>
<tbody>
<% for ticket in @tickets: %>
<tr>
<td><a <% if App.Config.get('import_mode'): %>target="_blank"<% end %> href="<%= @url %><%= ticket.id %>"><%- @P(ticket, 'number') %></a></td>
<td><%- @P(ticket, 'title') %></td>
<td><%- @P(ticket, 'state') %></td>
<td><%- @P(ticket, 'group') %></td>
<td><%- @P(ticket, 'created_at') %></td>
</tr>
<% end %>
</tbody>
</table>

View file

@ -211,22 +211,26 @@ class ReportsController < ApplicationController
row = 2
result[:ticket_ids].each do |ticket_id|
ticket = Ticket.lookup(id: ticket_id)
row += 1
worksheet.write(row, 0, ticket.number)
worksheet.write(row, 1, ticket.title)
worksheet.write(row, 2, ticket.state.name)
worksheet.write(row, 3, ticket.priority.name)
worksheet.write(row, 4, ticket.group.name)
worksheet.write(row, 5, ticket.owner.fullname)
worksheet.write(row, 6, ticket.customer.fullname)
worksheet.write(row, 7, ticket.try(:organization).try(:name))
worksheet.write(row, 8, ticket.create_article_type.name)
worksheet.write(row, 9, ticket.create_article_sender.name)
worksheet.write(row, 10, ticket.tag_list.join(','))
worksheet.write(row, 11, ticket.created_at)
worksheet.write(row, 12, ticket.updated_at)
worksheet.write(row, 13, ticket.close_at)
begin
ticket = Ticket.lookup(id: ticket_id)
row += 1
worksheet.write(row, 0, ticket.number)
worksheet.write(row, 1, ticket.title)
worksheet.write(row, 2, ticket.state.name)
worksheet.write(row, 3, ticket.priority.name)
worksheet.write(row, 4, ticket.group.name)
worksheet.write(row, 5, ticket.owner.fullname)
worksheet.write(row, 6, ticket.customer.fullname)
worksheet.write(row, 7, ticket.try(:organization).try(:name))
worksheet.write(row, 8, ticket.create_article_type.name)
worksheet.write(row, 9, ticket.create_article_sender.name)
worksheet.write(row, 10, ticket.tag_list.join(','))
worksheet.write(row, 11, ticket.created_at)
worksheet.write(row, 12, ticket.updated_at)
worksheet.write(row, 13, ticket.close_at)
rescue => e
Rails.logger.error "SKIP: #{e.message}"
end
end
workbook.close

View file

@ -10,7 +10,7 @@ class Report::Base
# :selector
def self.history_count(params)
history_object = History::Object.lookup( name: params[:object] )
history_object = History::Object.lookup(name: params[:object])
query, bind_params, tables = Ticket.selector2sql(params[:selector])

View file

@ -135,8 +135,8 @@ returns
field: params[:params][:field],
}
limit = 1000
if !params[:sheet]
limit = 6000
if params[:sheet].blank?
limit = 100
end
@ -146,6 +146,7 @@ returns
end
result = SearchIndexBackend.selectors(['Ticket'], selector, limit, nil, aggs_interval)
return result if params[:sheet].present?
assets = {}
result[:ticket_ids].each do |ticket_id|
ticket_full = Ticket.find(ticket_id)

View file

@ -123,6 +123,7 @@ returns
}
local_params = defaults.merge(local_params)
result = history(local_params)
return result if params[:sheet].present?
assets = {}
result[:ticket_ids].each do |ticket_id|
ticket_full = Ticket.find(ticket_id)

View file

@ -98,6 +98,7 @@ returns
end: params[:range_end],
selector: params[:selector]
)
return result if params[:sheet].present?
assets = {}
result[:ticket_ids].each do |ticket_id|
ticket_full = Ticket.find(ticket_id)

View file

@ -1646,4 +1646,63 @@ test('table new - initial list', function() {
equal(el.find('tbody > tr:nth-child(4) > td').length, 0, 'check row 3')
$('#table').append('<hr><h1>table with data 11</h1><div id="table-new11"></div>')
var el = $('#table-new11')
App.TicketPriority.refresh([
{
id: 1,
name: '1 low',
note: 'some note 1',
active: true,
created_at: '2014-06-10T11:17:34.000Z',
},
{
id: 2,
name: '2 normal',
note: 'some note 2',
active: false,
created_at: '2014-06-10T10:17:34.000Z',
},
], {clear: true})
var table = new App.ControllerTable({
el: el,
overviewAttributes: ['name', 'created_at', 'active'],
model: App.TicketPriority,
objects: App.TicketPriority.search({sortBy:'name', order: 'ASC'}),
checkbox: false,
radio: false,
frontendTimeUpdateExecute: false,
})
//equal(el.find('table').length, 0, 'row count')
//table.render()
equal(el.find('table > thead > tr').length, 1, 'row count')
equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Name', 'check header')
equal(el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Erstellt', 'check header')
equal(el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', 'check header')
equal(el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:first').text().trim(), '1 niedrig', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'true', 'check row 1')
equal(el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:first').text().trim(), '2 normal', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '', 'check row 2')
equal(el.find('tbody > tr:nth-child(3) > td').length, 0, 'check row 3')
result = table.update({sync: true, objects: App.TicketPriority.search({sortBy:'name', order: 'ASC'})})
equal(result[0], 'noChanges')
equal(el.find('table > thead > tr').length, 1, 'row count')
equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Name', 'check header')
equal(el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Erstellt', 'check header')
equal(el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', 'check header')
equal(el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:first').text().trim(), '1 niedrig', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'true', 'check row 1')
equal(el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:first').text().trim(), '2 normal', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '', 'check row 2')
})