Add admin stat pages for users, characters, locations, items, and universes

This commit is contained in:
Andrew Brown 2016-09-28 23:39:32 +02:00
parent 65d00abf74
commit 061f0aef37
17 changed files with 314 additions and 8 deletions

View File

@ -19,6 +19,7 @@ gem 'material_icons'
# Quality of Life
gem 'cocoon'
gem 'dateslices'
# Javascript
gem 'coffee-rails'
@ -36,6 +37,9 @@ gem 'serendipitous', git: 'git://github.com/indentlabs/serendipitous-gem.git'
# Editor
gem 'medium-editor-rails'
# Graphs & Charts
gem 'chartkick'
group :production do
# gem 'less-rails'
# gem 'less-rails-fontawesome'

View File

@ -65,6 +65,7 @@ GEM
rack (>= 1.0.0)
rack-test (>= 0.5.4)
xpath (~> 2.0)
chartkick (2.1.1)
childprocess (0.5.9)
ffi (~> 1.0, >= 1.0.11)
climate_control (0.0.3)
@ -104,6 +105,8 @@ GEM
railties (>= 3, < 5)
cucumber-wire (0.0.1)
database_cleaner (1.5.3)
dateslices (0.0.4)
rails (> 4)
debug_inspector (0.0.2)
devise (3.5.6)
bcrypt (~> 3.0)
@ -305,11 +308,13 @@ DEPENDENCIES
better_errors
binding_of_caller
capybara
chartkick
cocoon
coffee-rails
coveralls
cucumber-rails
database_cleaner
dateslices
devise
factory_girl_rails
guard
@ -340,4 +345,4 @@ DEPENDENCIES
uglifier (>= 1.3.0)
BUNDLED WITH
1.12.5
1.13.1

View File

@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/

View File

@ -17,4 +17,6 @@
//= require autocomplete-rails
//= require cocoon
//= require medium-editor
//= require Chart.bundle
//= require chartkick
//= require_tree .

View File

@ -0,0 +1 @@
h1, h2, h3 { text-align: center; }

View File

@ -0,0 +1,18 @@
class AdminController < ApplicationController
layout 'admin'
def dashboard
end
def universes
end
def characters
end
def locations
end
def items
end
end

View File

@ -1,7 +1,7 @@
# Controller for top-level pages of the site that do not have
# an associated model
class MainController < ApplicationController
layout "landing", only: [:index, :about_notebook]
layout 'landing', only: [:index, :about_notebook]
def index
redirect_to :dashboard if user_signed_in?

View File

@ -0,0 +1,2 @@
module AdminHelper
end

View File

@ -13,9 +13,7 @@ class User < ActiveRecord::Base
has_many :characters
has_many :items
has_many :languages
has_many :locations
has_many :magics
has_many :universes
# as_json creates a hash structure, which you then pass to ActiveSupport::json.encode to actually encode the object as a JSON string.
@ -45,9 +43,7 @@ class User < ActiveRecord::Base
{
characters: characters,
items: items,
languages: languages,
locations: locations,
magics: magics,
universes: universes
}
end
@ -56,9 +52,7 @@ class User < ActiveRecord::Base
[
characters.length,
items.length,
languages.length,
locations.length,
magics.length,
universes.length
].sum
end

View File

@ -0,0 +1,54 @@
<div class="row">
<div class="col s12">
<h1>Character creations</h1>
<%= line_chart Character.group_by_day(:created_at) %>
</div>
</div>
<div class="row">
<div class="col s4">
<h2>Characters per user</h1>
<%# bar_chart User.joins(:characters).group("characters.user_id").count() %>
TODO
</div>
<div class="col s4">
<h2>Characters per universe</h1>
<%# bar_chart Universe.joins(:characters).group("characters.universe_id").count() %>
TODO
</div>
<div class="col s4">
<h2>Character privacy</h1>
<%= pie_chart Character.group(:privacy).count() %>
</div>
</div>
<h1>Character usage data</h1>
<div class="row">
<div class="col s4">
<h2>Most common names</h2>
<%= bar_chart Character.where.not(name: "").group(:name).order('count_all desc').limit(5).count() %>
</div>
<div class="col s4">
<h2>Most common age</h2>
<%= bar_chart Character.where.not(age: "").group(:age).order('count_all desc').limit(5).count() %>
</div>
<div class="col s4">
<h2>Most common gender</h2>
<%= pie_chart Character.where.not(gender: "").group(:gender).order('count_all desc').limit(5).count() %>
</div>
</div>
<div class="row">
<div class="col s4">
<h2>Most common occupation</h2>
<%= bar_chart Character.where.not(occupation: "").group(:occupation).order('count_all desc').limit(5).count() %>
</div>
<div class="col s4">
<h2>Most-favorite weapons</h2>
<%= bar_chart Character.where.not(fave_weapon: "").group(:fave_weapon).order('count_all desc').limit(5).count() %>
</div>
<div class="col s4">
<h2>Most common eye color</h2>
<%= pie_chart Character.where.not(eyecolor: "").group(:eyecolor).order('count_all desc').limit(5).count() %>
</div>
</div>

View File

@ -0,0 +1,26 @@
<h1>User signups</h1>
<%= area_chart User.group_by_day(:created_at) %>
<div class="row">
<div class="col s6">
<h1>Universes per user</h1>
<%= bar_chart User.joins(:universes).group("universes.user_id").count() %>
</div>
<div class="col s6">
<h1>Characters per user</h1>
<%= bar_chart User.joins(:characters).group("characters.user_id").count() %>
</div>
</div>
<div class="row">
<div class="col s6">
<h1>Locations per user</h1>
<%= bar_chart User.joins(:locations).group("locations.user_id").count() %>
</div>
<div class="col s6">
<h1>Items per user</h1>
<%= bar_chart User.joins(:items).group("items.user_id").count() %>
</div>
</div>

View File

@ -0,0 +1,50 @@
<div class="row">
<div class="col s12">
<h1>Item creations</h1>
<%= line_chart Item.group_by_day(:created_at) %>
</div>
</div>
<div class="row">
<div class="col s4">
<h2>Items per user</h1>
<%# bar_chart User.joins(:items).group("items.user_id").count() %>
TODO
</div>
<div class="col s4">
<h2>Items per universe</h1>
<%# bar_chart Universe.joins(:items).group("items.universe_id").count() %>
TODO
</div>
<div class="col s4">
<h2>Item privacy</h1>
<%= pie_chart Item.group(:privacy).count() %>
</div>
</div>
<h1>Item usage data</h1>
<div class="row">
<div class="col s6">
<h2>Most common names</h2>
<%= bar_chart Item.where.not(name: "").group(:name).order('count_all desc').limit(5).count() %>
</div>
<div class="col s6">
<h2>Most common types</h2>
<%= bar_chart Item.where.not(item_type: "").group(:item_type).order('count_all desc').limit(5).count() %>
</div>
</div>
<div class="row">
<div class="col s4">
<h2>Common made years</h2>
<%= bar_chart Item.where.not(year_made: "").group(:year_made).order('count_all desc').limit(5).count() %>
</div>
<div class="col s4">
<h2>Common makers</h2>
<%= bar_chart Item.where.not(made_by: "").group(:made_by).order('count_all desc').limit(5).count() %>
</div>
<div class="col s4">
<h2>Most common weights</h2>
<%= bar_chart Item.where.not(weight: "").group(:weight).order('count_all desc').limit(5).count() %>
</div>
</div>

View File

@ -0,0 +1,50 @@
<div class="row">
<div class="col s12">
<h1>Location creations</h1>
<%= line_chart Location.group_by_day(:created_at) %>
</div>
</div>
<div class="row">
<div class="col s4">
<h2>Locations per user</h1>
<%# bar_chart User.joins(:locations).group("locations.user_id").count() %>
TODO
</div>
<div class="col s4">
<h2>Locations per universe</h1>
<%# bar_chart Universe.joins(:locations).group("locations.universe_id").count() %>
TODO
</div>
<div class="col s4">
<h2>Location privacy</h1>
<%= pie_chart Location.group(:privacy).count() %>
</div>
</div>
<h1>Location usage data</h1>
<div class="row">
<div class="col s6">
<h2>Most common names</h2>
<%= bar_chart Location.where.not(name: "").group(:name).order('count_all desc').limit(5).count() %>
</div>
<div class="col s6">
<h2>Most common types</h2>
<%= bar_chart Location.where.not(type_of: "").group(:type_of).order('count_all desc').limit(5).count() %>
</div>
</div>
<div class="row">
<div class="col s4">
<h2>Common estab. years</h2>
<%= bar_chart Location.where.not(established_year: "").group(:established_year).order('count_all desc').limit(5).count() %>
</div>
<div class="col s4">
<h2>Most common currencies</h2>
<%= pie_chart Location.where.not(currency: "").group(:currency).order('count_all desc').limit(5).count() %>
</div>
<div class="col s4">
<h2>Most common languages</h2>
<%= pie_chart Location.where.not(language: "").where.not(language: nil).group(:language).order('count_all desc').limit(5).count() %>
</div>
</div>

View File

@ -0,0 +1,36 @@
<div class="row">
<div class="col s12">
<h1>Universe creations</h1>
<%= line_chart Universe.group_by_day(:created_at) %>
</div>
</div>
<div class="row">
<div class="col s6">
<h2>Universes per user</h1>
<%# bar_chart User.joins(:items).group("items.user_id").count() %>
TODO
</div>
<div class="col s6">
<h2>Privacy per universe</h2>
<%= pie_chart Universe.group(:privacy) %>
</div>
</div>
<div class="row">
<div class="col s4">
<h2>Characters per universe</h1>
<%# bar_chart Universe.joins(:items).group("items.universe_id").count() %>
TODO
</div>
<div class="col s4">
<h2>Locations per universe</h1>
<%# bar_chart Universe.joins(:items).group("items.universe_id").count() %>
TODO
</div>
<div class="col s4">
<h2>Items per universe</h1>
<%# bar_chart Universe.joins(:items).group("items.universe_id").count() %>
TODO
</div>
</div>

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title><%= content_for?(:title) ? yield(:title) : 'Notebook' %></title>
<%= stylesheet_link_tag 'application' %>
<%= javascript_include_tag 'application' %>
<%= csrf_meta_tags %>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.6/css/materialize.min.css">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.6/js/materialize.min.js"></script>
</head>
<body>
<%= render 'layouts/navbar' %>
<main>
<%= yield %>
<a href="https://plus.google.com/118076966717703203223" rel="publisher"></a>
</main>
</body>
</html>

View File

@ -43,6 +43,14 @@ Rails.application.routes.draw do
get 'editor', to: 'write#editor'
end
scope 'admin' do
get '/', to: 'admin#dashboard'
get '/universes', to: 'admin#universes'
get '/characters', to: 'admin#characters'
get '/locations', to: 'admin#locations'
get '/items', to: 'admin#items'
end
# API Endpoints
scope '/generate' do
# General information

View File

@ -0,0 +1,29 @@
require 'test_helper'
class AdminControllerTest < ActionController::TestCase
test "should get dashboard" do
get :dashboard
assert_response :success
end
test "should get universes" do
get :universes
assert_response :success
end
test "should get characters" do
get :characters
assert_response :success
end
test "should get locations" do
get :locations
assert_response :success
end
test "should get items" do
get :items
assert_response :success
end
end