Skip to content
Permalink
Browse files

Add graphs and re-org dashboards; address #290.

- Added chartkick gem
- Updated routes for dashboard re-org
- Added stats page (buttons on old dashboard)
- Added jobs page (table on old dashboard)
- Added graphs, and helper method
- Update rubocop config
- Removed pagination from dashboards model
  • Loading branch information...
ruebot committed May 1, 2019
1 parent a768930 commit 00d21d1efb31c675ab2f37f9b6053ac12347a811
@@ -113,6 +113,7 @@ Security/Open:

Style/BlockDelimiters:
Exclude:
- app/controllers/dashboards_controller.rb
- app/helpers/dashboards_helper.rb

Style/ClassAndModuleChildren:
@@ -61,13 +61,15 @@ gem 'bootstrap', '~> 4.3.1' # https://nvd.nist.gov/vuln/detail/CVE-2019-8331
gem 'bootstrap_form',
git: 'https://github.com/bootstrap-ruby/bootstrap_form.git',
branch: 'master'
gem 'chartkick'
gem 'codecov', require: false, group: :test
gem 'daemons'
gem 'delayed-web'
gem 'delayed_job_active_record'
gem 'ffi', '>= 1.9.24' # https://nvd.nist.gov/vuln/detail/CVE-2018-1000201
gem 'figaro'
gem 'font-awesome-rails'
gem 'groupdate'
gem 'http'
gem 'humanize_boolean'
gem 'jquery-rails'
@@ -66,6 +66,7 @@ GEM
sassc-rails (>= 2.0.0)
builder (3.2.3)
byebug (11.0.1)
chartkick (3.0.2)
codecov (0.1.14)
json
simplecov
@@ -102,6 +103,8 @@ GEM
railties (>= 3.2, < 6.1)
globalid (0.4.2)
activesupport (>= 4.2.0)
groupdate (4.1.1)
activesupport (>= 4.2)
hashie (3.5.7)
http (4.1.1)
addressable (~> 2.3)
@@ -317,6 +320,7 @@ DEPENDENCIES
bootstrap (~> 4.3.1)
bootstrap_form!
byebug
chartkick
codecov
coffee-rails (~> 4.2)
daemons
@@ -325,6 +329,7 @@ DEPENDENCIES
ffi (>= 1.9.24)
figaro
font-awesome-rails
groupdate
http
humanize_boolean
jbuilder (~> 2.5)
@@ -14,6 +14,8 @@
//= require jquery3
//= require popper
//= require bootstrap-sprockets
//= require Chart.bundle
//= require chartkick
//= require_tree .
//= require turbolinks

@@ -4,17 +4,77 @@
class DashboardsController < ApplicationController
http_basic_authenticate_with name: ENV['DASHBOARD_USER'],
password: ENV['DASHBOARD_PASS']
include DashboardsHelper

def index
@dashboards = Dashboard.all.order('start_time DESC').page params[:page]
def index; end

def graphs
@dashboards = Dashboard.all
end

def jobs
@dashboards = Dashboard.all.order('start_time DESC')
end

def stats
@dashboards = Dashboard.all
end

def users_chart
render json: User.group_by_day(:created_at).count
end

def jobs_chart
render json: Dashboard.group(:queue)
.group_by_month(:created_at)
.count
.chart_json
end

def show; end
def spark_throughput_chart
queue_name = 'spark'
render json: job_times(queue_name)
end

def download_throughput_chart
queue_name = 'download'
render json: job_times(queue_name).chart_json
end

def graphpass_throughput_chart
queue_name = 'graphpass'
render json: job_times(queue_name).chart_json
end

def textfilter_throughput_chart
queue_name = 'textfilter'
render json: job_times(queue_name).chart_json
end

def seed_throughput_chart
queue_name = 'seed'
render json: job_times(queue_name).chart_json
end

def cleanup_throughput_chart
queue_name = 'cleanup'
render json: job_times(queue_name).chart_json
end

private

def dashboard_params
params.require(:dashboard).permit(:job_id, :user_id, :collection_id,
:queue, :start_time, :end_time)
end

def job_times(queue_name)
jt = Dashboard.where(queue: queue_name)
.where('end_time is not null')
.pluck(:end_time, :start_time, :id)

jt.map { |k, v, i|
Hash[i, TimeDifference.between(k, v).in_minutes]
}.inject(:merge)
end
end
@@ -8,6 +8,10 @@ def job_length(start_time, end_time)
TimeDifference.between(end_time, start_time).humanize
end

def job_length_charts(start_time, end_time)
TimeDifference.between(end_time, start_time)
end

def get_username(user_id)
user = User.find(user_id)
username = user.auk_name
@@ -2,8 +2,6 @@

# Dashboard methods.
class Dashboard < ApplicationRecord
paginates_per 15

validates :job_id, presence: true
validates :user_id, presence: true
validates :queue, presence: true
@@ -0,0 +1,68 @@
<% provide(:title, 'Graphs | AUK Dashboard') %>

<div class="container-fluid">
<div class="row">
<div class="card card-body">
<h2 class="card-header">User registrations</h2>
<p class="card-body">
<%= area_chart dashboards_users_chart_path, curve: false, download: {filename: 'auk_user_user_registration_chart.png', background: '#ffffff'} %>
</p>
</div>
</div>
<div class="row">
<div class="card card-body">
<h2 class="card-header">Jobs</h2>
<p class="card-body">
<%= line_chart dashboards_jobs_chart_path, curve: false, download: {filename: 'auk_jobs_chart.png', background: '#ffffff'} %>
</p>
</div>
</div>
<div class="row">
<div class="card card-body">
<h2 class="card-header">Spark throughput</h2>
<p class="card-body">
<%= area_chart dashboards_spark_throughput_chart_path, curve: false, ytitle: 'Job length (minutes)', download: {filename: 'auk_spark_throughput_chart.png', background: '#ffffff'} %>
</p>
</div>
</div>
<div class="row">
<div class="card card-body">
<h2 class="card-header">Download throughput</h2>
<p class="card-body">
<%= area_chart dashboards_download_throughput_chart_path, curve: false, ytitle: 'Job length (minutes)', download: {filename: 'auk_download_throughput_chart.png', background: '#ffffff'} %>
</p>
</div>
</div>
<div class="row">
<div class="card card-body">
<h2 class="card-header">GraphPass throughput</h2>
<p class="card-body">
<%= area_chart dashboards_graphpass_throughput_chart_path, curve: false, ytitle: 'Job length (minutes)', download: {filename: 'auk_graphpass_throughput_chart.png', background: '#ffffff'} %>
</p>
</div>
</div>
<div class="row">
<div class="card card-body">
<h2 class="card-header">Text filter throughput</h2>
<p class="card-body">
<%= area_chart dashboards_textfilter_throughput_chart_path, curve: false, ytitle: 'Job length (minutes)', download: {filename: 'auk_text_filter_chart.png', background: '#ffffff'} %>
</p>
</div>
</div>
<div class="row">
<div class="card card-body">
<h2 class="card-header">Seed throughput</h2>
<p class="card-body">
<%= area_chart dashboards_seed_throughput_chart_path, curve: false, ytitle: 'Job length (minutes)', download: {filename: 'auk_seed_throughput_chart.png', background: '#ffffff'} %>
</p>
</div>
</div>
<div class="row">
<div class="card card-body">
<h2 class="card-header">Clean-up throughput</h2>
<p class="card-body">
<%= area_chart dashboards_cleanup_throughput_chart_path, curve: false, ytitle: 'Job length (minutes)', download: {filename: 'auk_cleanup_throughput_chart.png', background: '#ffffff'} %>
</p>
</div>
</div>
</div>
@@ -1,98 +1,18 @@
<% provide(:title, 'AUK Dashboard') %>

<div class="container-fluid">
<div class="row-fluid">
<div class="panel panel-default">
<div class="btn-group-justified">
<button type="button" class="btn-primary btn dashboard-btn btn-md active">
<h3>Users</h3>
<h1><%= get_number_of_users %></h1>
</button>
<button type="button" class="btn-primary btn dashboard-btn btn-md active">
<h3>Collections</h3>
<h1><%= get_total_number_of_collections %></h1>
</button>
<button type="button" class="btn-primary btn dashboard-btn btn-md active">
<h3>Files</h3>
<h1><%= get_total_number_of_warcs %></h1>
</button>
<button type="button" class="btn-primary btn dashboard-btn btn-md active">
<h3>Active Jobs</h3>
<h1><%= get_number_of_queued_jobs %></h1>
</button>
<button type="button" class="btn-primary btn dashboard-btn btn-md active">
<h3>Jobs Completed</h3>
<h1><%= get_total_number_of_jobs_run %></h1>
</button>
<button type="button" class="btn-primary btn dashboard-btn btn-md active">
<h3>Job Time</h3>
<h1><%= get_total_job_time %></h1>
</button>
<button type="button" class="btn-primary btn dashboard-btn btn-md active">
<h3>Longest Job</h3>
<h1><%= get_longest_job_time %></h1>
</button>
<button type="button" class="btn-primary btn dashboard-btn btn-md active" data-toggle="tooltip" data-html="true" title="<%= get_most_jobs_user_institution %>">
<h3>Most Jobs</h3>
<h1><%= get_most_jobs_user %></h3>
</button>
<button type="button" class="btn-primary btn dashboard-btn btn-md active" data-toggle="tooltip" data-html="true" title="<%= get_largest_collection_title %>">
<h3>Largest Collection</h3>
<h1><%= get_largest_collection %></h1>
</button>
<button type="button" class="btn-primary btn dashboard-btn btn-md active">
<h3>Space Used</h3>
<h1><%= get_space_used %></h1>
</button>
<button type="button" class="btn-primary btn dashboard-btn btn-md active">
<h3>Space Available</h3>
<h1><%= get_space_available %></h1>
</button>
<button type="button" class="btn-primary btn dashboard-btn btn-md active">
<h3>Data Analyzed</h3>
<h1><%= data_analyzed %></h1>
</button>
</div>
<div class="row">
<div class="col-sm">
<h1 class="card-header"><%= link_to('Jobs', '/dashboards/jobs') %></h1>
</div>
<div class="col-sm">
<h1 class="card-header"><%= link_to('Stats', '/dashboards/stats') %></h1>
</div>
<div class="col-sm">
<h1 class="card-header"><%= link_to('Graphs', '/dashboards/graphs') %></h1>
</div>
</div>
<div class="row">
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>User</th>
<th>Institution</th>
<th>Collection</th>
<th>Queue</th>
<th>Start Time</th>
<th>End Time</th>
<th>Total Run Time</th>
<th>Download</th>
</tr>
</thead>
<tbody>
<% @dashboards.each do |dashboard| %>
<tr>
<td><%= get_username(dashboard.user_id) %></td>
<td><%= get_institution(dashboard.user_id) %></td>
<% if dashboard.queue == 'seed' %>
<td></td>
<% end %>
<% if dashboard.queue != 'seed' %>
<td><%= link_to(get_collection_name(dashboard.collection_id), archiveit_collection_url(dashboard.collection_id), target: '_blank') %></td>
<% end %>
<td><%= dashboard.queue %></td>
<td><%= dashboard.start_time %></td>
<td><%= dashboard.end_time %></td>
<td><%= job_length(dashboard.start_time, dashboard.end_time) %></td>
<% if dashboard.queue == 'download' %>
<td><%= collection_size_human(dashboard.collection_id, dashboard.user_id) %></td>
<% end %>
</tr>
<% end %>
</tbody>
</table>
</div>
<%= image_tag("https://camo.githubusercontent.com/148a43ac461f352346f8cd894af8bb5845a831fb/68747470733a2f2f7777772e6f6c64626f6f6b696c6c757374726174696f6e732e636f6d2f77702d636f6e74656e742f686967682d7265732f313836372f6772616e6476696c6c652d61756b2d313630302e6a7067", class: "mx-auto d-block img-fluid") %>
</div>
</div>
<%= paginate @dashboards %>
@@ -0,0 +1,43 @@
<% provide(:title, 'Jobs | AUK Dashboard') %>

<div class="container-fluid">
<div class="row">
<div class="table-responsive">
<table class="table table-striped sortable">
<thead>
<tr>
<th>User</th>
<th>Institution</th>
<th>Collection</th>
<th>Queue</th>
<th>Start Time</th>
<th>End Time</th>
<th>Total Run Time</th>
<th>Download</th>
</tr>
</thead>
<tbody>
<% @dashboards.each do |dashboard| %>
<tr>
<td><%= get_username(dashboard.user_id) %></td>
<td><%= get_institution(dashboard.user_id) %></td>
<% if dashboard.queue == 'seed' %>
<td></td>
<% end %>
<% if dashboard.queue != 'seed' %>
<td><%= link_to(get_collection_name(dashboard.collection_id), archiveit_collection_url(dashboard.collection_id), target: '_blank') %></td>
<% end %>
<td><%= dashboard.queue %></td>
<td><%= dashboard.start_time %></td>
<td><%= dashboard.end_time %></td>
<td><%= job_length(dashboard.start_time, dashboard.end_time) %></td>
<% if dashboard.queue == 'download' %>
<td><%= collection_size_human(dashboard.collection_id, dashboard.user_id) %></td>
<% end %>
</tr>
<% end %>
</tbody>
</table>
</div>
</div>
</div>
Oops, something went wrong.

0 comments on commit 00d21d1

Please sign in to comment.
You can’t perform that action at this time.