Browse Source

Init version.

Martin Edenhofer 9 years ago
parent
commit
76637f55a2

+ 488 - 0
app/assets/javascripts/app/controllers/report.js.coffee

@@ -0,0 +1,488 @@
+class Index extends App.ControllerContent
+  constructor: ->
+    super
+
+    # check authentication
+    return if !@authenticate()
+
+    @title 'Reporting'
+    @navupdate '#report'
+    @startLoading()
+    @ajax(
+      type:  'GET',
+      url:   @apiPath + '/reports/config',
+      processData: true,
+      success: (data) =>
+        @stopLoading()
+        @config = data.config
+        App.Collection.load( type: 'ReportProfile', data: data.profiles )
+        @render()
+    )
+
+  getParams: =>
+    return @params if @params
+
+    @params           = {}
+    @params.timeRange = 'year'
+    current           = new Date()
+    currentDay        = current.getDate()
+    currentMonth      = current.getMonth() + 1
+    currentYear       = current.getFullYear()
+    currentWeek       = current.getWeek()
+    @params.day       = currentDay
+    @params.month     = currentMonth
+    @params.week      = currentWeek
+    @params.year      = currentYear
+    if !@params.metric
+      for key, config of @config.metric
+        if config.default
+          @params.metric = config.name
+    if !@params.backendSelected
+      @params.backendSelected = {}
+      for key, config of @config.metric
+        for backend in config.backend
+          if backend.selected
+            @params.backendSelected[backend.name] = true
+    if !@params.profileSelected
+      @params.profileSelected = {}
+      for profile in App.ReportProfile.all()
+        if _.isEmpty( @params.profileSelected )
+          @params.profileSelected[ profile.id ] = true
+    @params
+
+  render: (data = {}) =>
+
+    @params = @getParams()
+
+    @html App.view('report/main')(
+      params: @params
+    )
+
+    new TimeRangePicker(
+      el:     @el.find('.js-timeRangePicker')
+      params: @params
+      ui:     @
+    )
+
+    new TimePicker(
+      el:     @el.find('.js-timePicker')
+      params: @params
+      ui:     @
+    )
+
+    new Sidebar(
+      el:     @el.find('.sidebar')
+      config: @config
+      params: @params
+    )
+
+    new Graph(
+      el:     @el
+      config: @config
+      params: @params
+      ui:     @
+    )
+
+class Graph extends App.ControllerContent
+  constructor: ->
+    super
+
+    # rerender view
+    @bind 'ui:report:rerender', =>
+      @render()
+
+    @render()
+
+  render: =>
+
+    update = (data) =>
+      @draw(data.data)
+      t = new Date
+      @el.find('#download-chart').html(t.toString())
+      new Download(
+        el:     @el.find('.js-dataDownload')
+        config: @config
+        params: @params
+        ui:     @ui
+      )
+
+    url = @apiPath + '/reports/generate'
+    interval = 60000
+    if @params.timeRange is 'year'
+      interval = 30000
+    if @params.timeRange is 'month'
+      interval = 20000
+    if @params.timeRange is 'week'
+      interval = 20000
+    if @params.timeRange is 'day'
+      interval = 20000
+    if @params.timeRange is 'realtime'
+      interval = 10000
+
+    @ajax(
+      type: 'POST'
+      url:  url
+      data: JSON.stringify(
+        metric:    @params.metric
+        year:      @params.year
+        month:     @params.month
+        week:      @params.week
+        day:       @params.day
+        timeRange: @params.timeRange
+        profiles:  @params.profileSelected
+        backends:  @params.backendSelected
+      )
+      processData: true
+      success: (data) =>
+        update(data)
+        @delay( @render, interval, 'report-update', 'page' )
+    )
+
+  draw: (data) =>
+    @log('draw', data)
+    $('#placeholder').empty()
+
+    # create xaxis
+    xaxis = []
+    if @params.timeRange is 'realtime'
+      for minute in [0..59]
+        xaxis.push [minute, '']
+    else if @params.timeRange is 'day'
+      for hour in [0..23]
+        xaxis.push [hour, hour]
+    else if @params.timeRange is 'month'
+      for day in [1..31]
+        xaxis.push [day, day]
+    else if @params.timeRange is 'week'
+      xaxis = [[1, 'Mon'], [2, 'Tue'], [3, 'Wed'], [4, 'Thr'], [5, 'Fri'], [6, 'Sat'], [7, 'Sun'] ]
+    else
+      xaxis = [[1, 'Jan'], [2, 'Feb'], [3, 'Mar'], [4, 'Apr'], [5, 'Mai'], [6, 'Jun'], [7, 'Jul'], [8, 'Aug'], [9, 'Sep'], [10, 'Oct'], [11, 'Nov'], [12, 'Dec']]
+
+    dataPlot = []
+    for key, value of data
+      dataPlot.push {
+        data: value
+        label: key
+      }
+    # plot
+    $.plot( $('#placeholder'), dataPlot, {
+      yaxis: { min: 0 },
+      xaxis: { ticks: xaxis }
+    } )
+
+
+class Download extends App.Controller
+  events:
+    'click .js-dataDownloadBackendSelector': 'tableUpdate'
+
+  constructor: (data) ->
+
+    # unbind existing click binds
+    data.el.unbind('click .js-dataDownloadBackendSelector')
+
+    super
+    @render()
+
+  render: ->
+
+    reports = []
+    $('.js-backendSelector:checked').each( (index, element) ->
+      if $(element).hasClass('download')
+        value = $(element).val()
+        reports.push value
+    )
+
+    profiles = []
+    for key, value of @params.profileSelected
+      profiles.push App.ReportProfile.find(key)
+    console.log('reports', reports, 'profiles', profiles, @config.metric, @params.metric, @config.metric[@params.metric])
+    @html App.view('report/download_header')(
+      reports:  reports
+      profiles: profiles
+      metric:   @config.metric[@params.metric]
+    )
+
+    @profileSelected = ''
+    @backendSelected  = ''
+    active = false
+    @el.find('.js-dataDownloadBackendSelector').each( (index, element) ->
+      if $(element).parent().hasClass('active')
+        active = true
+    )
+    if !active
+      @el.find('.js-dataDownloadBackendSelector').first().parent().addClass('active')
+
+    @el.find('.js-dataDownloadBackendSelector').each( (index, element) =>
+      if $(element).parent().hasClass('active')
+        @profileSelected = $(element).data('profile')
+        @backendSelected  = $(element).data('report')
+    )
+
+    @tableUpdate()
+
+  tableUpdate: (e) =>
+    if e
+      e.preventDefault()
+      @el.find('.js-dataDownloadBackendSelector').parent().removeClass('active')
+      $(e.target).parent().addClass('active')
+      @profileSelected = $(e.target).data('profile')
+      @backendSelected = $(e.target).data('backend')
+
+    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
+        html = App.view('report/download_list')(
+          tickets: tickets
+          count:   count
+          url:     url
+          download: @apiPath + '/reports/csvforset/' + name
+        )
+        @el.find('js-dataDownloadTable').html(html)
+
+    @startLoading()
+    @ajax(
+      type:  'POST'
+      url:   @apiPath + '/reports/sets'
+      data: JSON.stringify(
+        metric:    @params.metric
+        year:      @params.year
+        month:     @params.month
+        week:      @params.week
+        day:       @params.day
+        timeRange: @params.timeRange
+        profiles:  @params.profileSelected
+
+      )
+      processData: true
+      success: (data) =>
+        @stopLoading()
+
+        # load ticket collection / do not save in localStorage
+        App.Collection.load( type: 'TicketReport', data: data.tickets, localStorage: true )
+        ticket_collection = []
+
+        if data.tickets
+          for record in data.tickets
+            ticket = App.TicketReport.fullLocal( record.id )
+            ticket_collection.push ticket
+
+        table( ticket_collection, data.count )
+    )
+
+class TimeRangePicker extends App.Controller
+  events:
+    'click .js-timeRange': 'select'
+
+  constructor: ->
+    super
+
+   # rerender view
+    @bind 'ui:report:rerender', =>
+      @render()
+
+    @render()
+
+  render: =>
+    @html App.view('report/time_range_picker')()
+
+    # select time slot
+    @el.find('.js-timeRange').removeClass('active')
+    @el.find('.js-timeRange[data-type="' + @ui.params.timeRange + '"]').addClass('active')
+
+  select: (e) =>
+    console.log('TS click')
+    e.preventDefault()
+    @ui.params.timeRange = $(e.target).data('type')
+    console.log 'SLOT', @ui.params.timeRange
+    App.Event.trigger( 'ui:report:rerender' )
+
+
+class TimePicker extends App.Controller
+  events:
+    'click .js-timePickerDay':   'selectTimeDay'
+    'click .js-timePickerYear':  'selectTimeYear'
+    'click .js-timePickerMonth': 'selectTimeMonth'
+    'click .js-timePickerWeek':  'selectTimeWeek'
+
+  constructor: ->
+    super
+
+    @_timeSlotPicker()
+
+    # rerender view
+    @bind 'ui:report:rerender', =>
+      @render()
+
+    @render()
+
+  render: =>
+    @html App.view('report/time_picker')(
+      params:         @ui.params
+      timeRangeDay:   @timeRangeDay
+      timeRangeMonth: @timeRangeMonth
+      timeRangeWeek:  @timeRangeWeek
+      timeRangeYear:  @timeRangeYear
+    )
+
+    # select time slot
+    @el.find('.time-slot').removeClass('active')
+    @el.find('.time-slot[data-type="' + @ui.params.timeRange + '"]').addClass('active')
+
+  selectTimeDay: (e) =>
+    e.preventDefault()
+    @ui.params.day = $(e.target).data('type')
+    $(e.target).parent().parent().find('li').removeClass('active')
+    $(e.target).parent().addClass('active')
+    App.Event.trigger( 'ui:report:rerender' )
+
+  selectTimeMonth: (e) =>
+    e.preventDefault()
+    @ui.params.month = $(e.target).data('type')
+    $(e.target).parent().parent().find('li').removeClass('active')
+    $(e.target).parent().addClass('active')
+    App.Event.trigger( 'ui:report:rerender' )
+
+  selectTimeWeek: (e) =>
+    e.preventDefault()
+    @ui.params.week = $(e.target).data('type')
+    $(e.target).parent().parent().find('li').removeClass('active')
+    $(e.target).parent().addClass('active')
+    App.Event.trigger( 'ui:report:rerender' )
+
+  selectTimeYear: (e) =>
+    e.preventDefault()
+    @ui.params.year = $(e.target).data('type')
+    $(e.target).parent().parent().find('li').removeClass('active')
+    $(e.target).parent().addClass('active')
+    App.Event.trigger( 'ui:report:rerender' )
+
+  _timeSlotPicker: ->
+    @timeRangeYear = []
+    year = new Date().getFullYear()
+    for item in [year-2..year]
+      record = {
+        display: item
+        value: item
+      }
+      @timeRangeYear.push record
+
+    @timeRangeMonth = [
+      {
+        display: 'Jan'
+        value: 1
+      },
+      {
+        display: 'Feb'
+        value: 2
+      },
+      {
+        display: 'Mar'
+        value: 3
+      },
+      {
+        display: 'Apr'
+        value: 4,
+      },
+      {
+        display: 'Mai'
+        value: 5,
+      },
+      {
+        display: 'Jun'
+        value: 6,
+      },
+      {
+        display: 'Jul'
+        value: 7,
+      },
+      {
+        display: 'Aug'
+        value: 8,
+      },
+      {
+        display: 'Sep'
+        value: 9,
+      },
+      {
+        display: 'Oct'
+        value: 10,
+      },
+      {
+        display: 'Nov'
+        value: 11,
+      },
+      {
+        display: 'Dec'
+        value: 12,
+      },
+    ]
+
+    @timeRangeWeek = []
+    for item in [1..52]
+      record = {
+        display: item
+        value: item
+      }
+      @timeRangeWeek.push record
+
+    @timeRangeDay = []
+    for item in [1..31]
+      record = {
+        display: item
+        value: item
+      }
+      @timeRangeDay.push record
+
+
+class Sidebar extends App.Controller
+  events:
+    'click .js-profileSelector': 'selectProfile'
+    'click .js-backendSelector': 'selectBackend'
+    'click .panel-title':        'selectMetric'
+
+  constructor: ->
+    super
+    @render()
+
+  render: =>
+
+    metrics = @config.metric
+    profiles = App.ReportProfile.all()
+    console.log('Si', @params)
+    @html App.view('report/sidebar')(
+      metrics:  metrics
+      params:   @params
+      profiles: profiles
+    )
+
+  selectMetric: (e) =>
+    return if $(e.target).closest('.panel').find('.collapse.in').get(0)
+    metric = $(e.target).closest('.panel').data('metric')
+    return if @params.metric is metric
+    @params.metric = metric
+    App.Event.trigger( 'ui:report:rerender' )
+
+  selectProfile: (e) =>
+    profile_id = $(e.target).val()
+    active = $(e.target).prop('checked')
+    if active
+      @params.profileSelected[profile_id] = true
+    else
+      delete @params.profileSelected[profile_id]
+    App.Event.trigger( 'ui:report:rerender' )
+
+  selectBackend: (e) =>
+    backend = $(e.target).val()
+    active = $(e.target).prop('checked')
+    if active
+      @params.backendSelected[backend] = true
+    else
+      delete @params.backendSelected[backend]
+    App.Event.trigger( 'ui:report:rerender' )
+
+App.Config.set( 'report', Index, 'Routes' )
+App.Config.set( 'Reporting', { prio: 8000, parent: '', name: 'Reporing', translate: true, target: '#report', icon: 'report', role: ['Admin'] }, 'NavBarRight' )

+ 27 - 0
app/assets/javascripts/app/controllers/report_profile.js.coffee

@@ -0,0 +1,27 @@
+class Index extends App.ControllerContent
+  constructor: ->
+    super
+
+    # check authentication
+    return if !@authenticate()
+
+    new App.ControllerGenericIndex(
+      el: @el
+      id: @id
+      genericObject: 'ReportProfile'
+      pageData:
+        title: 'Report Profile'
+        home: 'report_profiles'
+        object: 'Report Profile'
+        objects: 'Report Profiles'
+        navupdate: '#report_profiles'
+        notes: [
+#          'Report Profile are ...'
+        ]
+        buttons: [
+          { name: 'New Profile', 'data-type': 'new', class: 'primary' }
+        ]
+      container: @el.closest('.content')
+    )
+
+App.Config.set( 'ReportProfile', { prio: 8000, name: 'Report Profiles', parent: '#manage', target: '#manage/report_profiles', controller: Index, role: ['Admin'] }, 'NavBarAdmin' )

+ 14 - 0
app/assets/javascripts/app/models/report_profile.js.coffee

@@ -0,0 +1,14 @@
+class App.ReportProfile extends App.Model
+  @configure 'ReportProfile', 'name', 'condition', 'active'
+  @extend Spine.Model.Ajax
+  @url: @apiPath + '/report_profiles'
+  @configure_attributes = [
+    { name: 'name',       display: 'Name',      tag: 'input',     type: 'text', limit: 100, null: false },
+    { name: 'condition',  display: 'Filter',    tag: 'ticket_selector', null: true },
+    { name: 'updated_at', display: 'Updated',   tag: 'datetime',  readonly: 1 },
+    { name: 'active',     display: 'Active',    tag: 'active',    default: true },
+  ]
+  @configure_delete = true
+  @configure_overview = [
+    'name',
+  ]

+ 14 - 0
app/assets/javascripts/app/views/report/download_header.jst.eco

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

+ 26 - 0
app/assets/javascripts/app/views/report/download_list.jst.eco

@@ -0,0 +1,26 @@
+<i><%- @T('%s records', @count) %></i>
+<a href="<%-@download%>" target="_blank" data-type="attachment" id="downloadsetascsv">
+<i class="glyphicon glyphicon-download" title="<%- @Ti('Download') %>"></i>
+</a>
+<table class="table table-striped table-hover">
+  <thead>
+    <tr>
+      <td><%- @T('Number') %></td>
+      <td><%- @T('Title') %></td>
+      <td><%- @T('State') %></td>
+      <td><%- @T('Queue') %></td>
+      <td><%- @T('Created') %></td>
+    </tr>
+  </thead>
+  <tbody>
+<% for ticket in @tickets: %>
+    <tr>
+      <td><a target="_blank" 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>

+ 29 - 0
app/assets/javascripts/app/views/report/main.jst.eco

@@ -0,0 +1,29 @@
+<div class="sidebar"></div>
+
+<div class="main flex">
+
+  <div class="page-header clearfix">
+    <h1 class="pull-left"><%- @T( 'Reporting' ) %> <small></small></h1>
+    <div class="js-timeRangePicker pull-right" style="margin-top: 20px;"></div>
+  </div>
+
+  <div class="page-content"></div>
+
+  <div id="placeholder" class="" style="width:710px;height:450px;"></div>
+
+  <br>
+  <span class=" muted" id="download-chart" style="font-size: 8px;"></span>
+<!--
+<a href="<%-@download%>" target="_blank" data-type="attachment" class="pull-right" id="download-chart">
+<i class="icon-download" title="<%- @Ti('Download') %>"></i>
+</a>
+-->
+<!--
+      <div id="overview" style="margin-left:50px;margin-top:20px;width:400px;height:50px"></div>
+-->
+
+    <div class="js-timePicker"></div>
+    <br>
+    <div class="js-dataDownload"></div>
+  </div>
+</div>

+ 33 - 0
app/assets/javascripts/app/views/report/sidebar.jst.eco

@@ -0,0 +1,33 @@
+<div class="panel-group" id="accordion">
+  <% for key, metric of @metrics: %>
+    <div class="panel panel-default" data-metric="<%= metric.name %>">
+      <div class="panel-heading">
+        <div class="panel-title">
+          <a data-toggle="collapse" data-parent="#accordion" href="#collapse-<%= metric.name %>">
+            <%- @T(metric.display) %>
+          </a>
+        </div>
+      </div>
+      <div id="collapse-<%= metric.name %>" class="panel-collapse collapse <% if metric.name is @params.metric: %>in<% end %>">
+        <div class="panel-body">
+          <ul class="type area_select">
+            <% for backend in metric.backend: %>
+              <li style="display: block; margin-left: -12px;"><input class="js-backendSelector" type="checkbox" value="<%= backend.name %>" <% if @params.backendSelected[backend.name]: %>checked<% end %>/>
+                <%- @T(backend.display) %>
+              </li>
+            <% end %>
+          </ul>
+        </div>
+      </div>
+    </div>
+  <% end %>
+</div>
+
+<h3><%- @T('Profiles') %></h3>
+<ul>
+  <% for profile in @profiles: %>
+    <li style="display: block; margin-left: -12px;"><input class="js-profileSelector" type="radio" name="profile" value="<%= profile.id %>"  <% if @params.profileSelected[profile.id]: %>checked<% end %>/>
+      <%= profile.name %>
+    </li>
+  <% end %>
+</ul>

+ 36 - 0
app/assets/javascripts/app/views/report/time_picker.jst.eco

@@ -0,0 +1,36 @@
+<div class="">
+  <% if @params.timeRange is 'day': %>
+    <div class="btn-group" role="group" aria-label="">
+      <% for item in @timeRangeDay: %>
+        <button type="button" class="btn btn-default js-timePickerDay <% if @params.day is item.value: %>active<% end %>" data-id="<%= @params.timeRange %>" data-type="<%= item.value %>"><%= item.display %></button>
+      <% end %>
+    </div>
+    <br>
+  <% end %>
+
+  <% if @params.timeRange is 'day' || @params.timeRange is 'month': %>
+    <div class="btn-group" role="group" aria-label="">
+      <% for item in @timeRangeMonth: %>
+        <button type="button" class="btn btn-default js-timePickerMonth <% if @params.month is item.value: %>active<% end %>" data-id="<%= @params.timeRange %>" data-type="<%= item.value %>"><%= item.display %></button>
+      <% end %>
+    </div>
+    <br>
+  <% end %>
+
+  <% if @params.timeRange is 'week': %>
+    <div class="btn-group" role="group" aria-label="">
+      <% for item in @timeRangeWeek: %>
+        <button type="button" class="btn btn-default js-timePickerWeek <% if @params.week is item.value: %>active<% end %>" data-id="<%= @params.timeRange %>" data-type="<%= item.value %>"><%= item.display %></button>
+      <% end %>
+    </div>
+    <br>
+  <% end %>
+
+  <% if @params.timeRange isnt 'realtime': %>
+    <div class="btn-group" role="group" aria-label="">
+      <% for item in @timeRangeYear: %>
+        <button type="button" class="btn btn-default js-timePickerYear <% if @params.year is item.value: %>active<% end %>" data-id="<%= @params.timeRange %>" data-type="<%= item.value %>"><%= item.display %></button>
+      <% end %>
+    </div>
+  <% end %>
+</div>

+ 7 - 0
app/assets/javascripts/app/views/report/time_range_picker.jst.eco

@@ -0,0 +1,7 @@
+<div class="btn-group">
+  <button type="button" class="btn js-timeRange" data-type="year"><%- @T('Year') %></button>
+  <button type="button" class="btn js-timeRange" data-type="month"><%- @T('Month') %></button>
+  <button type="button" class="btn js-timeRange" data-type="week"><%- @T('Week') %></button>
+  <button type="button" class="btn js-timeRange" data-type="day"><%- @T('Day') %></button>
+  <button type="button" class="btn js-timeRange" data-type="realtime"><%- @T('Realtime') %></button>
+</div>

+ 1 - 1
app/controllers/application_controller.rb

@@ -151,7 +151,7 @@ class ApplicationController < ActionController::Base
 
   def authentication_check_only(auth_param)
 
-    logger.debug 'authentication_check'
+    #logger.debug 'authentication_check'
     #logger.debug params.inspect
     #logger.debug session.inspect
     #logger.debug cookies.inspect

Some files were not shown because too many files changed in this diff