active_analytics 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +27 -6
  3. data/app/assets/images/active_analytics.png +0 -0
  4. data/app/assets/images/active_analytics_screenshot.png +0 -0
  5. data/app/assets/javascripts/active_analytics/application.js +13 -0
  6. data/app/assets/stylesheets/active_analytics/application.css +1 -19
  7. data/app/assets/stylesheets/active_analytics/charts.css +80 -2262
  8. data/app/assets/stylesheets/active_analytics/style.css +161 -0
  9. data/app/controllers/active_analytics/application_controller.rb +12 -0
  10. data/app/controllers/active_analytics/pages_controller.rb +10 -7
  11. data/app/controllers/active_analytics/referrers_controller.rb +6 -4
  12. data/app/controllers/active_analytics/sites_controller.rb +5 -2
  13. data/app/helpers/active_analytics/application_helper.rb +3 -0
  14. data/app/helpers/active_analytics/sites_helper.rb +3 -0
  15. data/app/models/active_analytics/views_per_day.rb +26 -7
  16. data/app/views/active_analytics/pages/_table.html.erb +31 -19
  17. data/app/views/active_analytics/pages/index.html.erb +4 -7
  18. data/app/views/active_analytics/pages/show.html.erb +18 -15
  19. data/app/views/active_analytics/referrers/_table.html.erb +21 -14
  20. data/app/views/active_analytics/referrers/index.html.erb +4 -3
  21. data/app/views/active_analytics/referrers/show.html.erb +14 -9
  22. data/app/views/active_analytics/sites/_histogram.html.erb +15 -19
  23. data/app/views/active_analytics/sites/index.html.erb +12 -7
  24. data/app/views/active_analytics/sites/show.html.erb +12 -12
  25. data/app/views/layouts/active_analytics/_footer.html.erb +45 -3
  26. data/app/views/layouts/active_analytics/_header.html.erb +47 -21
  27. data/app/views/layouts/active_analytics/application.html.erb +15 -14
  28. data/db/migrate/20210303094108_create_active_analytics_views_per_days.rb +1 -1
  29. data/lib/active_analytics.rb +2 -4
  30. data/lib/active_analytics/version.rb +1 -1
  31. metadata +7 -4
@@ -0,0 +1,161 @@
1
+ body {
2
+ padding: 0;
3
+ margin: 0;
4
+ width: 100%;
5
+ }
6
+
7
+ body > header nav {
8
+ width: 100%;
9
+ max-width: 1280px;
10
+ margin: 0 auto;
11
+ padding: 24px;
12
+ display: flex;
13
+ flex-wrap: wrap;
14
+ align-items: center;
15
+ min-height: 88px;
16
+ }
17
+
18
+ header nav .menubutton {
19
+ margin-left: auto;
20
+ }
21
+
22
+ header .logo {
23
+ margin-right: 8px;
24
+ }
25
+
26
+ header .logo svg {
27
+ width: 24px;
28
+ height: 24px;
29
+ fill: none;
30
+ stroke: rgba(var(--color-blue-500), 1);
31
+ stroke-width: 1;
32
+ }
33
+
34
+ header .is-link {
35
+ text-transform: none;
36
+ text-decoration: none;
37
+ font-size: 1rem;
38
+ letter-spacing: 0;
39
+ font-weight: 400;
40
+ padding: 0 16px;
41
+ margin: 0;
42
+ min-height: 24px;
43
+ color: rgba(var(--color-grey-700), 1);
44
+ }
45
+
46
+ header .is-link:hover {
47
+ background: rgba(var(--color-grey-50), 1);
48
+ }
49
+
50
+ main {
51
+ width: 100%;
52
+ max-width: 1280px;
53
+ margin: 0 auto;
54
+ padding: 0 24px;
55
+ }
56
+
57
+ main h2 {
58
+ word-break: break-word;
59
+ }
60
+
61
+ section {
62
+ margin-bottom: var(--space-4x);
63
+ }
64
+
65
+ .grid-auto {
66
+ --col-min-width: calc(var(--space) * 38);
67
+ }
68
+
69
+ .tooltip-date {
70
+ color: rgba(var(--color-grey-100), 1);
71
+ }
72
+
73
+ .card {
74
+ position: relative;
75
+ overflow: visible;
76
+ }
77
+
78
+ .card h3 {
79
+ display: flex;
80
+ }
81
+
82
+ .card h3 a {
83
+ margin-left: auto;
84
+ font-weight: 400;
85
+ font-size: 1rem;
86
+ }
87
+
88
+ .card table {
89
+ margin: 0 -24px;
90
+ width: calc(100% + 48px);
91
+ }
92
+
93
+ .card table.charts-css {
94
+ margin-bottom: -24px;
95
+ }
96
+
97
+ tr td:first-of-type {
98
+ padding: 12px 0px 12px 24px;
99
+ }
100
+
101
+ tr td:last-of-type {
102
+ padding: 12px 24px 12px 0;
103
+ }
104
+
105
+ td a {
106
+ word-break: break-word;
107
+ }
108
+
109
+ td.number {
110
+ text-align: right;
111
+ font-variant-numeric: tabular-nums;
112
+ }
113
+
114
+ .referer-favicon {
115
+ width: 16px;
116
+ height: 16px;
117
+ display: inline-block;
118
+ position: relative;
119
+ top: 3px;
120
+ margin-right: 4px;
121
+ }
122
+
123
+ div.is-empty {
124
+ display: flex;
125
+ align-items: center;
126
+ justify-content: center;
127
+ height: calc(100% - 72px);
128
+ width: 100%;
129
+ color: rgba(var(--color-grey-300), 1);
130
+ }
131
+
132
+ body > footer {
133
+ max-width: 1280px;
134
+ margin: 48px auto 0;
135
+ padding: 24px;
136
+ }
137
+
138
+ body > footer ul {
139
+ margin: 0;
140
+ list-style-type: none;
141
+ padding: 0;
142
+ }
143
+
144
+ body > footer .card {
145
+ margin: 0;
146
+ background: rgba(var(--color-grey-50), 1);
147
+ }
148
+ body > footer .card p {
149
+ padding: 0 0 2px;
150
+ color: rgba(var(--color-grey-400), 1);
151
+ }
152
+
153
+ @media (max-width: 480px) {
154
+ header nav .menubutton {
155
+ margin-top: 24px;
156
+ }
157
+
158
+ [role="dialog"] {
159
+ min-width: 280px;
160
+ }
161
+ }
@@ -1,4 +1,16 @@
1
1
  module ActiveAnalytics
2
2
  class ApplicationController < ActionController::Base
3
+
4
+ private
5
+
6
+ def require_date_range
7
+ if params[:from].blank? || params[:to].blank?
8
+ redirect_to(params.to_unsafe_hash.merge(from: 7.days.ago.to_date, to: Date.today))
9
+ end
10
+ end
11
+
12
+ def current_views_per_days
13
+ ViewsPerDay.where(site: params[:site]).between_dates(params[:from], params[:to])
14
+ end
3
15
  end
4
16
  end
@@ -4,19 +4,22 @@ module ActiveAnalytics
4
4
  class PagesController < ApplicationController
5
5
  include PagesHelper
6
6
 
7
+ before_action :require_date_range
8
+
7
9
  def index
8
- scope = ViewsPerDay.where(site: params[:site]).after(30.days.ago)
9
- @histogram = ViewsPerDay::Histogram.new(scope.order_by_date.group_by_date)
10
+ scope = ViewsPerDay.where(site: params[:site]).between_dates(params[:from], params[:to])
11
+ @histogram = ViewsPerDay::Histogram.new(scope.order_by_date.group_by_date, params[:from], params[:to])
10
12
  @pages = scope.top(100).group_by_page
11
13
  end
12
14
 
13
15
  def show
14
- scope = ViewsPerDay.where(site: params[:site], page: page_from_params).after(30.days.ago)
15
- @histogram = ViewsPerDay::Histogram.new(scope.order_by_date.group_by_date)
16
- @referrers = scope.top.group_by_referrer_site
16
+ dates_scopes = ViewsPerDay.between_dates(params[:from], params[:to])
17
+ page_scope = dates_scopes.where(site: params[:site], page: page_from_params)
18
+ @histogram = ViewsPerDay::Histogram.new(page_scope.order_by_date.group_by_date, params[:from], params[:to])
19
+ @referrers = page_scope.top.group_by_referrer_site
17
20
 
18
- @next_pages = ViewsPerDay.where(referrer_host: params[:site], referrer_path: page_from_params).top.group_by_page
19
- @previous_pages = ViewsPerDay.where(site: params[:site], page: page_from_params).top.group_by_referrer_page
21
+ @next_pages = dates_scopes.where(referrer_host: params[:site], referrer_path: page_from_params).top(100).group_by_page
22
+ @previous_pages = dates_scopes.where(site: params[:site], page: page_from_params).where.not(referrer_path: nil).top(100).group_by_referrer_page
20
23
  end
21
24
  end
22
25
  end
@@ -2,15 +2,17 @@ require_dependency "active_analytics/application_controller"
2
2
 
3
3
  module ActiveAnalytics
4
4
  class ReferrersController < ApplicationController
5
+ before_action :require_date_range
6
+
5
7
  def index
6
- scope = ViewsPerDay.where(site: params[:site])
8
+ scope = ViewsPerDay.where(site: params[:site]).between_dates(params[:from], params[:to])
7
9
  @referrers = scope.top(100).group_by_referrer_site
8
- @histogram = ViewsPerDay::Histogram.new(scope.order_by_date.group_by_date)
10
+ @histogram = ViewsPerDay::Histogram.new(scope.order_by_date.group_by_date, params[:from], params[:to])
9
11
  end
10
12
 
11
13
  def show
12
- scope = ViewsPerDay.where(site: params[:site], referrer_host: params[:referrer])
13
- @histogram = ViewsPerDay::Histogram.new(scope.order_by_date.group_by_date)
14
+ scope = ViewsPerDay.where(site: params[:site], referrer_host: params[:referrer]).between_dates(params[:from], params[:to])
15
+ @histogram = ViewsPerDay::Histogram.new(scope.order_by_date.group_by_date, params[:from], params[:to])
14
16
  @previous_pages = scope.top(100).group_by_referrer_page
15
17
  @next_pages = scope.top(100).group_by_page
16
18
  end
@@ -2,13 +2,16 @@ require_dependency "active_analytics/application_controller"
2
2
 
3
3
  module ActiveAnalytics
4
4
  class SitesController < ApplicationController
5
+ before_action :require_date_range, only: :show
6
+
5
7
  def index
6
8
  @sites = ViewsPerDay.after(30.days.ago).order_by_totals.group_by_site
9
+ redirect_to(site_path(@sites.first.host)) if @sites.size == 1
7
10
  end
8
11
 
9
12
  def show
10
- scope = ViewsPerDay.where(site: params[:site]).after(30.days.ago)
11
- @histogram = ViewsPerDay::Histogram.new(scope.order_by_date.group_by_date)
13
+ scope = current_views_per_days
14
+ @histogram = ViewsPerDay::Histogram.new(scope.order_by_date.group_by_date, params[:from], params[:to])
12
15
  @referrers = scope.top.group_by_referrer_site
13
16
  @pages = scope.top.group_by_page
14
17
  end
@@ -1,4 +1,7 @@
1
1
  module ActiveAnalytics
2
2
  module ApplicationHelper
3
+ def format_view_count(number)
4
+ number_with_delimiter(number.to_i)
5
+ end
3
6
  end
4
7
  end
@@ -1,4 +1,7 @@
1
1
  module ActiveAnalytics
2
2
  module SitesHelper
3
+ def site_icon(host)
4
+ image_tag("https://icons.duckduckgo.com/ip3/#{host}.ico", referrerpolicy: "no-referrer", class: "referer-favicon")
5
+ end
3
6
  end
4
7
  end
@@ -2,6 +2,7 @@ module ActiveAnalytics
2
2
  class ViewsPerDay < ApplicationRecord
3
3
  validates_presence_of :site, :page, :date
4
4
 
5
+ scope :between_dates, -> (from, to) { where("date BETWEEN ? AND ?", from, to) }
5
6
  scope :after, -> (date) { where("date > ?", date) }
6
7
  scope :order_by_totals, -> { order(Arel.sql("SUM(total) DESC")) }
7
8
  scope :order_by_date, -> { order(:date) }
@@ -33,21 +34,37 @@ module ActiveAnalytics
33
34
  end
34
35
 
35
36
  class Histogram
36
- attr_reader :bars
37
+ attr_reader :bars, :from_date, :to_date
37
38
 
38
- def initialize(scope)
39
+ def initialize(scope, from_date, to_date)
39
40
  @bars = scope.map { |day| Bar.new(day.day, day.total, self) }
41
+ fill_missing_days(@bars, Date.parse(from_date.to_s), Date.parse(to_date.to_s))
42
+ end
43
+
44
+ def fill_missing_days(bars, from, to)
45
+ i = 0
46
+ while (day = from + i) <= to
47
+ if !@bars[i] || @bars[i].label != day
48
+ @bars.insert(i, Bar.new(day, 0, self))
49
+ end
50
+ i += 1
51
+ end
52
+ @bars
40
53
  end
41
54
 
42
55
  def max_value
43
56
  @max_total ||= bars.map(&:value).max
44
57
  end
45
58
 
59
+ def total
60
+ @bars.reduce(0) { |sum, bar| sum += bar.value }
61
+ end
62
+
46
63
  class Bar
47
64
  attr_reader :label, :value, :histogram
48
65
 
49
66
  def initialize(label, value, histogram)
50
- @label, @value,@histogram = label, value, histogram
67
+ @label, @value, @histogram = label, value, histogram
51
68
  end
52
69
 
53
70
  def height
@@ -91,10 +108,12 @@ module ActiveAnalytics
91
108
  end
92
109
 
93
110
  def self.append(params)
94
- vpd = find_or_initialize_by(params)
95
- vpd.referrer_path = nil if vpd.referrer_path?
96
- vpd.total += 1 if vpd.persisted?
97
- vpd.save!
111
+ params[:site] = params[:site].downcase if params[:site]
112
+ params[:page] = params[:page].downcase if params[:page]
113
+ params[:referrer_path] = nil if params[:referrer_path].blank?
114
+ params[:referrer_path] = params[:referrer_path].downcase if params[:referrer_path]
115
+ params[:referrer_host] = params[:referrer_host].downcase if params[:referrer_host]
116
+ find_or_create_by!(params) if where(params).update_all("total = total + 1") == 0
98
117
  end
99
118
  end
100
119
  end
@@ -1,21 +1,33 @@
1
- <table>
2
- <% for page in pages %>
3
- <tr>
4
- <td>
5
- <% if page.host == params[:site] %>
6
- <% if page.path.present? %>
7
- <%= link_to page.path, page_path(site: page.host, page: page_to_params(page.path)) %>
1
+
2
+ <% if pages.empty? %>
3
+ <div class="is-empty">
4
+ <span>no data</span>
5
+ </div>
6
+ <% else %>
7
+ <table>
8
+ <% for page in pages %>
9
+ <tr>
10
+ <td>
11
+ <% if page.host == params[:site] %>
12
+ <% if page.path.present? %>
13
+ <%= link_to page.path, page_path(site: page.host, page: page_to_params(page.path), from: params[:from], to: params[:to]) %>
14
+ <% else %>
15
+ <%= site_icon page.host %>
16
+ <%= link_to page.host, site_path(site: page.host, from: params[:from], to: params[:to]) %>
17
+ <small>(page not provided <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy#strict-origin-when-cross-origin">?</a>)</small>
18
+ <% end %>
19
+ <% elsif page.host.present? && page.path.present? %>
20
+ <%= link_to(referrer_path(site: params[:site], referrer: page.host, from: params[:from], to: params[:to])) { site_icon page.host } %>
21
+ <%= link_to page.url, referrer_path(site: params[:site], referrer: page.host, from: params[:from], to: params[:to]) %>
22
+ <% elsif page.host.present? %>
23
+ <%= site_icon page.host %>
24
+ <%= page.host %>
8
25
  <% else %>
9
- <%= link_to page.host, site_path(site: page.host) %>
10
- <small>(page not provided <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy#strict-origin-when-cross-origin">?</a>)</small>
26
+ (None or direct)
11
27
  <% end %>
12
- <% elsif page.host.present? && page.path.present? %>
13
- <%= page.url %>
14
- <% else %>
15
- (None or direct)
16
- <% end %>
17
- </td>
18
- <td><%= page.total %></td>
19
- </tr>
20
- <% end %>
21
- </table>
28
+ </td>
29
+ <td class="number"><%= format_view_count page.total %></td>
30
+ </tr>
31
+ <% end %>
32
+ </table>
33
+ <% end %>
@@ -1,12 +1,9 @@
1
- <section>
2
- <h2>Pages</h2>
3
- </section>
4
-
5
- <section>
1
+ <section class="card">
2
+ <h3><%= format_view_count @histogram.total %> views</h3>
6
3
  <%= render "/active_analytics/sites/histogram", histogram: @histogram %>
7
4
  </section>
8
5
 
9
- <section>
10
- <h3>Pages</h3>
6
+ <section class="card">
7
+ <h3>Top pages</h3>
11
8
  <%= render "/active_analytics/pages/table", pages: @pages %>
12
9
  </section>
@@ -2,22 +2,25 @@
2
2
  <h2><%= page_from_params %></h2>
3
3
  </section>
4
4
 
5
- <section>
6
- <h3>Views per day</h3>
5
+ <section class="card">
6
+ <h3><%= format_view_count @histogram.total %> views</h3>
7
7
  <%= render "/active_analytics/sites/histogram", histogram: @histogram %>
8
8
  </section>
9
9
 
10
- <section>
11
- <h3>Top referrers</h3>
12
- <%= render "/active_analytics/referrers/table", referrers: @referrers %>
13
- </section>
14
-
15
- <section>
16
- <h3>Previous Pages</h3>
17
- <%= render "table", pages: @previous_pages %>
18
- </section>
10
+ <ul class="grid-auto">
11
+ <li class="card">
12
+ <!-- <section>
13
+ <h3>Top sources</h3>
14
+ <%= render "/active_analytics/referrers/table", referrers: @referrers %>
15
+ </section> -->
16
+ <section>
17
+ <h3>Previous page</h3>
18
+ <%= render "table", pages: @previous_pages %>
19
+ </section>
20
+ </li>
19
21
 
20
- <section>
21
- <h3>Next Pages</h3>
22
- <%= render "table", pages: @next_pages %>
23
- </section>
22
+ <li class="card">
23
+ <h3>Next page</h3>
24
+ <%= render "table", pages: @next_pages %>
25
+ </li>
26
+ </ul>