ahoy_captain 0.11.1 → 0.76
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +13 -25
- data/Rakefile +2 -23
- data/app/assets/javascript/ahoy_captain/application.js +4 -4
- data/app/assets/javascript/ahoy_captain/controllers/application.js +5 -5
- data/app/assets/javascript/ahoy_captain/controllers/application_controller.js +8 -27
- data/app/assets/javascript/ahoy_captain/controllers/details_modal_controller.js +5 -5
- data/app/assets/javascript/ahoy_captain/controllers/dropdown_label_controller.js +2 -2
- data/app/assets/javascript/ahoy_captain/controllers/filter_controller.js +145 -0
- data/app/assets/javascript/ahoy_captain/controllers/filter_tag_controller.js +17 -0
- data/app/assets/javascript/ahoy_captain/controllers/funnel_chart_controller.js +127 -113
- data/app/assets/javascript/ahoy_captain/controllers/index.js +3 -4
- data/app/assets/javascript/ahoy_captain/controllers/link_controller.js +43 -0
- data/app/assets/javascript/ahoy_captain/controllers/navigation_controller.js +25 -0
- data/app/assets/javascript/ahoy_captain/controllers/realtime_controller.js +9 -12
- data/app/components/ahoy_captain/dropdown_button_component.html.erb +5 -5
- data/app/components/ahoy_captain/dropdown_link_component.html.erb +7 -5
- data/app/components/ahoy_captain/dropdown_link_component.rb +0 -4
- data/app/components/ahoy_captain/filter/modal_component.html.erb +9 -12
- data/app/components/ahoy_captain/filter/select_component.html.erb +19 -23
- data/app/components/ahoy_captain/filter/select_component.rb +9 -41
- data/app/components/ahoy_captain/filter/tag_component.html.erb +4 -8
- data/app/components/ahoy_captain/filter/tag_component.rb +30 -6
- data/app/components/ahoy_captain/filter/tag_container_component.html.erb +3 -2
- data/app/components/ahoy_captain/filter/tag_container_component.rb +8 -1
- data/app/components/ahoy_captain/sticky_nav_component.html.erb +33 -28
- data/app/components/ahoy_captain/sticky_nav_component.rb +0 -19
- data/app/components/ahoy_captain/table_component.html.erb +37 -4
- data/app/components/ahoy_captain/table_component.rb +5 -25
- data/app/components/ahoy_captain/tile_component.html.erb +10 -21
- data/app/components/ahoy_captain/tile_component.rb +2 -10
- data/app/components/ahoy_captain/tooltip_component.html.erb +2 -2
- data/app/controllers/ahoy_captain/application_controller.rb +30 -23
- data/app/controllers/ahoy_captain/campaigns_controller.rb +10 -2
- data/app/controllers/ahoy_captain/cities_controller.rb +24 -0
- data/app/controllers/ahoy_captain/countries_controller.rb +24 -0
- data/app/controllers/ahoy_captain/devices_controller.rb +6 -3
- data/app/controllers/ahoy_captain/entry_pages_controller.rb +4 -2
- data/app/controllers/ahoy_captain/exit_pages_controller.rb +4 -3
- data/app/controllers/ahoy_captain/filters/base_controller.rb +3 -1
- data/app/controllers/ahoy_captain/filters/pages/actions_controller.rb +1 -1
- data/app/controllers/ahoy_captain/filters/pages/entry_pages_controller.rb +3 -3
- data/app/controllers/ahoy_captain/filters/pages/exit_pages_controller.rb +3 -2
- data/app/controllers/ahoy_captain/filters/sources_controller.rb +1 -1
- data/app/controllers/ahoy_captain/filters/utms_controller.rb +1 -1
- data/app/controllers/ahoy_captain/realtimes_controller.rb +1 -1
- data/app/controllers/ahoy_captain/regions_controller.rb +24 -0
- data/app/controllers/ahoy_captain/sources_controller.rb +5 -2
- data/app/controllers/ahoy_captain/stats/base_controller.rb +0 -142
- data/app/controllers/ahoy_captain/stats/bounce_rates_controller.rb +2 -4
- data/app/controllers/ahoy_captain/stats/total_pageviews_controller.rb +1 -2
- data/app/controllers/ahoy_captain/stats/total_visits_controller.rb +1 -2
- data/app/controllers/ahoy_captain/stats/unique_visitors_controller.rb +1 -3
- data/app/controllers/ahoy_captain/stats/views_per_visits_controller.rb +8 -3
- data/app/controllers/ahoy_captain/stats/visit_durations_controller.rb +1 -2
- data/app/controllers/ahoy_captain/top_pages_controller.rb +8 -2
- data/app/decorators/ahoy_captain/application_decorator.rb +3 -27
- data/app/decorators/ahoy_captain/campaign_decorator.rb +0 -8
- data/app/decorators/ahoy_captain/city_decorator.rb +0 -12
- data/app/decorators/ahoy_captain/country_decorator.rb +0 -10
- data/app/decorators/ahoy_captain/device_decorator.rb +2 -13
- data/app/decorators/ahoy_captain/page_decorator.rb +0 -11
- data/app/decorators/ahoy_captain/region_decorator.rb +0 -16
- data/app/decorators/ahoy_captain/source_decorator.rb +0 -7
- data/app/helpers/ahoy_captain/application_helper.rb +3 -60
- data/app/models/ahoy_captain/current.rb +9 -0
- data/app/models/ahoy_captain/rangeable.rb +3 -0
- data/app/models/ahoy_captain/url_helpers.rb +6 -0
- data/app/models/concerns/ahoy_captain/range_options.rb +14 -1
- data/app/presenters/ahoy_captain/dashboard_presenter.rb +46 -18
- data/app/presenters/ahoy_captain/funnel_presenter.rb +29 -32
- data/app/presenters/ahoy_captain/goals_presenter.rb +23 -33
- data/app/queries/ahoy_captain/application_query.rb +13 -81
- data/app/queries/ahoy_captain/entry_pages_query.rb +2 -3
- data/app/queries/ahoy_captain/event_query.rb +8 -30
- data/app/queries/ahoy_captain/exit_pages_query.rb +4 -6
- data/app/queries/ahoy_captain/stats/average_views_per_visit_query.rb +4 -11
- data/app/queries/ahoy_captain/stats/average_visit_duration_query.rb +7 -15
- data/app/queries/ahoy_captain/stats/bounce_rates_query.rb +7 -24
- data/app/queries/ahoy_captain/stats/total_pageviews_query.rb +2 -2
- data/app/queries/ahoy_captain/stats/total_visitors_query.rb +2 -2
- data/app/queries/ahoy_captain/stats/unique_visitors_query.rb +2 -2
- data/app/queries/ahoy_captain/stats/views_per_visit_query.rb +3 -3
- data/app/queries/ahoy_captain/stats/visit_duration_query.rb +5 -5
- data/app/queries/ahoy_captain/visit_query.rb +13 -12
- data/app/views/ahoy_captain/devices/index.html+details.erb +1 -1
- data/app/views/ahoy_captain/devices/index.html.erb +2 -2
- data/app/views/ahoy_captain/funnels/show.html.erb +2 -5
- data/app/views/ahoy_captain/goals/index.html.erb +37 -2
- data/app/views/ahoy_captain/layouts/application.html.erb +4 -3
- data/app/views/ahoy_captain/realtimes/show.html.erb +1 -1
- data/app/views/ahoy_captain/roots/show.html.erb +118 -117
- data/app/views/ahoy_captain/stats/base/index.html.erb +1 -38
- data/app/views/ahoy_captain/stats/show.html.erb +56 -14
- data/config/routes.rb +3 -16
- data/lib/ahoy_captain/ahoy/event_methods.rb +75 -36
- data/lib/ahoy_captain/ahoy/visit_methods.rb +1 -1
- data/lib/ahoy_captain/configuration.rb +7 -18
- data/lib/ahoy_captain/engine.rb +0 -22
- data/lib/ahoy_captain/goals.rb +4 -16
- data/lib/ahoy_captain/period_collection.rb +1 -1
- data/lib/ahoy_captain/version.rb +1 -1
- data/lib/ahoy_captain.rb +1 -8
- data/lib/generators/ahoy_captain/templates/config.rb.tt +3 -50
- metadata +17 -185
- data/app/assets/javascript/ahoy_captain/controllers/combobox_controller.js +0 -371
- data/app/assets/javascript/ahoy_captain/controllers/filter/item_controller.js +0 -12
- data/app/assets/javascript/ahoy_captain/controllers/filter_form_controller.js +0 -13
- data/app/assets/javascript/ahoy_captain/controllers/filter_modal_controller.js +0 -45
- data/app/assets/javascript/ahoy_captain/controllers/frame_link_controller.js +0 -20
- data/app/assets/javascript/ahoy_captain/controllers/interval_controller.js +0 -15
- data/app/assets/javascript/ahoy_captain/controllers/line_chart_controller.js +0 -251
- data/app/assets/javascript/ahoy_captain/controllers/map_controller.js +0 -47
- data/app/assets/javascript/ahoy_captain/controllers/predicate_select_controller.js +0 -10
- data/app/assets/javascript/ahoy_captain/controllers/properties_controller.js +0 -8
- data/app/assets/javascript/ahoy_captain/controllers/property_filter_controller.js +0 -45
- data/app/assets/javascript/ahoy_captain/controllers/tile_controller.js +0 -33
- data/app/assets/javascript/ahoy_captain/controllers/toggle_controller.js +0 -17
- data/app/assets/javascript/ahoy_captain/helpers/chart_utils.js +0 -156
- data/app/assets/javascript/ahoy_captain/helpers/countries.js +0 -2261
- data/app/assets/javascript/ahoy_captain/helpers/number_formatters.js +0 -55
- data/app/components/ahoy_captain/combobox_component.html.erb +0 -33
- data/app/components/ahoy_captain/combobox_component.rb +0 -13
- data/app/components/ahoy_captain/comparison_link_component.html.erb +0 -17
- data/app/components/ahoy_captain/comparison_link_component.rb +0 -44
- data/app/components/ahoy_captain/filter/dropdown_component.html.erb +0 -50
- data/app/components/ahoy_captain/filter/dropdown_component.rb +0 -51
- data/app/components/ahoy_captain/previous_next_component.html.erb +0 -8
- data/app/components/ahoy_captain/previous_next_component.rb +0 -11
- data/app/components/ahoy_captain/stats/comparable_container_component.html.erb +0 -25
- data/app/components/ahoy_captain/stats/comparable_container_component.rb +0 -86
- data/app/components/ahoy_captain/stats/container_component.html.erb +0 -15
- data/app/components/ahoy_captain/stats/container_component.rb +0 -26
- data/app/components/ahoy_captain/tables/devices_table_component.rb +0 -11
- data/app/components/ahoy_captain/tables/dynamic_table.rb +0 -13
- data/app/components/ahoy_captain/tables/dynamic_table_component.rb +0 -204
- data/app/components/ahoy_captain/tables/goals_table_component.rb +0 -17
- data/app/components/ahoy_captain/tables/header_component.html.erb +0 -5
- data/app/components/ahoy_captain/tables/header_component.rb +0 -18
- data/app/components/ahoy_captain/tables/headers/header_component.html.erb +0 -5
- data/app/components/ahoy_captain/tables/headers/header_component.rb +0 -16
- data/app/components/ahoy_captain/tables/properties_table_component.rb +0 -27
- data/app/components/ahoy_captain/tables/row_component.html.erb +0 -4
- data/app/components/ahoy_captain/tables/rows/row_component.html.erb +0 -6
- data/app/components/ahoy_captain/tables/rows/row_component.rb +0 -40
- data/app/controllers/ahoy_captain/exports_controller.rb +0 -14
- data/app/controllers/ahoy_captain/filters/goals_controller.rb +0 -9
- data/app/controllers/ahoy_captain/filters/properties/names_controller.rb +0 -11
- data/app/controllers/ahoy_captain/filters/properties/values_controller.rb +0 -15
- data/app/controllers/ahoy_captain/locations/cities_controller.rb +0 -22
- data/app/controllers/ahoy_captain/locations/countries_controller.rb +0 -22
- data/app/controllers/ahoy_captain/locations/maps_controller.rb +0 -24
- data/app/controllers/ahoy_captain/locations/regions_controller.rb +0 -22
- data/app/controllers/ahoy_captain/properties_controller.rb +0 -41
- data/app/models/ahoy_captain/comparison_mode.rb +0 -72
- data/app/models/ahoy_captain/export.rb +0 -48
- data/app/models/ahoy_captain/filter_parser.rb +0 -82
- data/app/models/ahoy_captain/range_from_params.rb +0 -78
- data/app/models/concerns/ahoy_captain/compare_mode.rb +0 -19
- data/app/models/concerns/ahoy_captain/limitable.rb +0 -17
- data/app/queries/ahoy_captain/campaign_query.rb +0 -14
- data/app/queries/ahoy_captain/city_query.rb +0 -11
- data/app/queries/ahoy_captain/country_query.rb +0 -10
- data/app/queries/ahoy_captain/device_query.rb +0 -10
- data/app/queries/ahoy_captain/region_query.rb +0 -11
- data/app/queries/ahoy_captain/source_query.rb +0 -10
- data/app/queries/ahoy_captain/stats/base_query.rb +0 -18
- data/app/queries/ahoy_captain/top_page_query.rb +0 -13
- data/app/queries/concerns/ahoy_captain/comparable_queries.rb +0 -25
- data/app/queries/concerns/ahoy_captain/comparable_query.rb +0 -138
- data/app/queries/concerns/ahoy_captain/lazy_comparable_query.rb +0 -42
- data/app/views/ahoy_captain/devices/_table.html.erb +0 -2
- data/app/views/ahoy_captain/layouts/shared/_tile_loader.html.erb +0 -12
- data/app/views/ahoy_captain/locations/maps/show.html.erb +0 -3
- data/app/views/ahoy_captain/properties/_form.html.erb +0 -6
- data/app/views/ahoy_captain/properties/index.html.erb +0 -3
- data/app/views/ahoy_captain/properties/show.html.erb +0 -6
- data/app/views/ahoy_captain/roots/_filters.html.erb +0 -80
- data/lib/ahoy_captain/filter_configuration/filter.rb +0 -16
- data/lib/ahoy_captain/filter_configuration/filter_collection.rb +0 -48
- data/lib/ahoy_captain/filters_configuration.rb +0 -77
- data/lib/ahoy_captain/predicate_label.rb +0 -7
- data/lib/generators/ahoy_captain/migration_generator.rb +0 -21
- data/lib/generators/ahoy_captain/templates/migration.rb.tt +0 -7
- /data/app/views/ahoy_captain/{locations/cities → cities}/index.html+details.erb +0 -0
- /data/app/views/ahoy_captain/{locations/cities → cities}/index.html.erb +0 -0
- /data/app/views/ahoy_captain/{locations/countries → countries}/index.html+details.erb +0 -0
- /data/app/views/ahoy_captain/{locations/countries → countries}/index.html.erb +0 -0
- /data/app/views/ahoy_captain/{locations/regions → regions}/index.html+details.erb +0 -0
- /data/app/views/ahoy_captain/{locations/regions → regions}/index.html.erb +0 -0
@@ -1,3 +1,3 @@
|
|
1
|
-
<div class="tooltip
|
1
|
+
<div class="tooltip" data-tip=<%= amount %>>
|
2
2
|
<p><%= abbreviate %></p>
|
3
|
-
</div>
|
3
|
+
</div>
|
@@ -1,35 +1,40 @@
|
|
1
|
+
|
2
|
+
|
1
3
|
module AhoyCaptain
|
4
|
+
module Limitable
|
5
|
+
private
|
6
|
+
|
7
|
+
def limit
|
8
|
+
if request.variant.include?(:details)
|
9
|
+
nil
|
10
|
+
else
|
11
|
+
if params[:limit]
|
12
|
+
params[:limit].to_i
|
13
|
+
else
|
14
|
+
10
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
2
20
|
class ApplicationController < ActionController::Base
|
3
21
|
include Pagy::Backend
|
4
|
-
include CompareMode
|
5
|
-
include RangeOptions
|
6
|
-
include Rangeable
|
7
22
|
|
8
23
|
layout 'ahoy_captain/layouts/application'
|
9
24
|
|
10
|
-
|
11
|
-
|
25
|
+
before_action do
|
26
|
+
Current.request = self
|
12
27
|
end
|
13
28
|
|
14
29
|
# show the details frame
|
15
|
-
before_action
|
16
|
-
|
17
|
-
# act like an spa without being an spa
|
18
|
-
before_action :act_like_an_spa
|
19
|
-
|
20
|
-
rescue_from Widget::WidgetDisabled do |e|
|
21
|
-
render template: 'ahoy_captain/shared/widget_disabled', locals: { frame: e.frame }
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
def use_details_frame
|
30
|
+
before_action do
|
27
31
|
if request.headers['Turbo-Frame'] == 'details'
|
28
32
|
request.variant = :details
|
29
33
|
end
|
30
34
|
end
|
31
35
|
|
32
|
-
|
36
|
+
# act like an spa without being an spa
|
37
|
+
before_action do
|
33
38
|
if request.format.html? && request.headers['Turbo-Frame'].blank?
|
34
39
|
if request.path != root_path
|
35
40
|
requested_params = Rails.application.routes.recognize_path(request.path).except(:controller, :action)
|
@@ -41,6 +46,12 @@ module AhoyCaptain
|
|
41
46
|
end
|
42
47
|
end
|
43
48
|
|
49
|
+
rescue_from Widget::WidgetDisabled do |e|
|
50
|
+
render template: 'ahoy_captain/shared/widget_disabled', locals: { frame: e.frame }
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
44
55
|
def visit_query
|
45
56
|
VisitQuery.call(params)
|
46
57
|
end
|
@@ -49,7 +60,6 @@ module AhoyCaptain
|
|
49
60
|
EventQuery.call(params)
|
50
61
|
end
|
51
62
|
|
52
|
-
# Only paginate details requests requests
|
53
63
|
def paginate(collection)
|
54
64
|
if paginate?
|
55
65
|
pagy, results = pagy(collection, page: params[:page])
|
@@ -65,10 +75,7 @@ module AhoyCaptain
|
|
65
75
|
end
|
66
76
|
|
67
77
|
def cached(*names)
|
68
|
-
|
69
|
-
return yield
|
70
|
-
end
|
71
|
-
AhoyCaptain.cache.fetch("ahoy_captain:#{names.join(":")}:#{request.query_parameters.sort.map { |k,v| "#{k}-#{v}" }.join(":")}", expire_in: AhoyCaptain.config.cache[:ttl]) do
|
78
|
+
AhoyCaptain.cache.fetch("ahoy_captain:#{names.join(":")}:#{request.query_parameters.sort.map { |k,v| "#{k}-#{v}" }.join(":")}", expire_in: AhoyCaptain.config.cache.ttl) do
|
72
79
|
yield
|
73
80
|
end
|
74
81
|
end
|
@@ -10,9 +10,17 @@ module AhoyCaptain
|
|
10
10
|
|
11
11
|
def index
|
12
12
|
results = cached(:campaigns, params[:campaigns_type]) do
|
13
|
-
|
13
|
+
visit_query
|
14
|
+
.select(
|
15
|
+
"COALESCE(#{params[:campaigns_type]}, 'Direct/None') as label",
|
16
|
+
"count(COALESCE(#{params[:campaigns_type]}, 'Direct/None')) as count",
|
17
|
+
"sum(count(COALESCE(#{params[:campaigns_type]}, 'Direct/None'))) OVER() as total_count"
|
18
|
+
)
|
19
|
+
.group("COALESCE(#{params[:campaigns_type]}, 'Direct/None')")
|
20
|
+
.order(Arel.sql("count(COALESCE(#{params[:campaigns_type]}, 'Direct/None')) desc"))
|
21
|
+
.limit(limit)
|
14
22
|
end
|
15
|
-
@campaigns = paginate(results).map { |campaign| CampaignDecorator.new(campaign
|
23
|
+
@campaigns = paginate(results).map { |campaign| CampaignDecorator.new(campaign) }
|
16
24
|
@campaign_type = params[:campaigns_type]&.titleize&.gsub("Utm", "UTM")
|
17
25
|
end
|
18
26
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module AhoyCaptain
|
2
|
+
class CitiesController < ApplicationController
|
3
|
+
include AhoyCaptain::Limitable
|
4
|
+
|
5
|
+
before_action do
|
6
|
+
if Widget.disabled?(:locations, :cities)
|
7
|
+
raise Widget::WidgetDisabled.new("Widget disabled", :geography)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def index
|
12
|
+
results = cached(:cities) do
|
13
|
+
visit_query
|
14
|
+
.select("city, country, count(concat(city, region, country)) as count, sum(count(concat(city, region, country))) over() as total_count")
|
15
|
+
.where.not(city: nil)
|
16
|
+
.group("city, region, country")
|
17
|
+
.order(Arel.sql "count(concat(city, region, country)) desc")
|
18
|
+
.limit(limit)
|
19
|
+
end
|
20
|
+
|
21
|
+
@cities = paginate(results).map { |city| CityDecorator.new(city) }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module AhoyCaptain
|
2
|
+
class CountriesController < ApplicationController
|
3
|
+
include Limitable
|
4
|
+
include Rangeable
|
5
|
+
|
6
|
+
before_action do
|
7
|
+
if Widget.disabled?(:locations, :countries)
|
8
|
+
raise Widget::WidgetDisabled.new("Widget disabled", :geography)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def index
|
13
|
+
results = cached(:countries) do
|
14
|
+
visit_query
|
15
|
+
.reselect("country as label, count(country) as count, sum(count(country)) OVER() as total_count")
|
16
|
+
.group("country")
|
17
|
+
.order("count(country) desc")
|
18
|
+
.limit(limit)
|
19
|
+
end
|
20
|
+
|
21
|
+
@countries = paginate(results).map { |country| CountryDecorator.new(country) }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -10,11 +10,14 @@ module AhoyCaptain
|
|
10
10
|
|
11
11
|
def index
|
12
12
|
results = cached(:devices, params[:devices_type]) do
|
13
|
-
|
14
|
-
|
13
|
+
visit_query
|
14
|
+
.select("#{params[:devices_type]} as label", "count(#{params[:devices_type]}) as count", "sum(count(#{params[:devices_type]})) over() as total_count")
|
15
|
+
.group(params[:devices_type])
|
16
|
+
.order("count(#{params[:devices_type]}) desc")
|
17
|
+
.limit(limit)
|
15
18
|
end
|
16
19
|
|
17
|
-
@devices = results.map { |device| DeviceDecorator.new(device
|
20
|
+
@devices = results.map { |device| DeviceDecorator.new(device) }
|
18
21
|
end
|
19
22
|
end
|
20
23
|
end
|
@@ -10,10 +10,12 @@ module AhoyCaptain
|
|
10
10
|
|
11
11
|
def index
|
12
12
|
results = cached(:entry_pages) do
|
13
|
-
EntryPagesQuery.call(params)
|
13
|
+
EntryPagesQuery.call(params, event_query)
|
14
|
+
.order(Arel.sql "count(#{AhoyCaptain.config.event[:url_column]}) desc")
|
15
|
+
.limit(limit)
|
14
16
|
end
|
15
17
|
|
16
|
-
@pages = paginate(results).map { |page| EntryPageDecorator.new(page
|
18
|
+
@pages = paginate(results).map { |page| EntryPageDecorator.new(page) }
|
17
19
|
end
|
18
20
|
end
|
19
21
|
end
|
@@ -10,10 +10,11 @@ module AhoyCaptain
|
|
10
10
|
|
11
11
|
def index
|
12
12
|
results = cached(:exit_pages) do
|
13
|
-
ExitPagesQuery.call(params)
|
14
|
-
.
|
13
|
+
ExitPagesQuery.call(params, event_query)
|
14
|
+
.order(Arel.sql "count(#{AhoyCaptain.config.event[:url_column]}) desc")
|
15
|
+
.limit(limit)
|
15
16
|
end
|
16
|
-
@pages = paginate(results).map { |page| ExitPageDecorator.new(page
|
17
|
+
@pages = paginate(results).map { |page| ExitPageDecorator.new(page) }
|
17
18
|
end
|
18
19
|
end
|
19
20
|
end
|
@@ -1,10 +1,12 @@
|
|
1
1
|
module AhoyCaptain
|
2
2
|
module Filters
|
3
3
|
class BaseController < ApplicationController
|
4
|
+
include Rangeable
|
5
|
+
|
4
6
|
private
|
5
7
|
|
6
8
|
def serialize(value)
|
7
|
-
{ text:
|
9
|
+
{ text: value }
|
8
10
|
end
|
9
11
|
|
10
12
|
def visit_query
|
@@ -1,11 +1,11 @@
|
|
1
1
|
module AhoyCaptain
|
2
2
|
module Filters
|
3
3
|
module Pages
|
4
|
+
# TODO: ACCOMODATE EXIT_PAGES
|
4
5
|
class EntryPagesController < BaseController
|
5
6
|
def index
|
6
|
-
query = event_query.all.
|
7
|
-
|
8
|
-
render json: query.map { |row| serialize(row.url) }
|
7
|
+
query = event_query.all.with_url.distinct_url
|
8
|
+
render json: query.map { |row| { text: row.url } }
|
9
9
|
end
|
10
10
|
|
11
11
|
end
|
@@ -1,11 +1,12 @@
|
|
1
1
|
module AhoyCaptain
|
2
2
|
module Filters
|
3
3
|
module Pages
|
4
|
+
# TODO: ACCOMODATE ENTRY_PAGES
|
4
5
|
class ExitPagesController < BaseController
|
5
6
|
def index
|
6
|
-
query = event_query.
|
7
|
+
query = event_query.with_url.distinct_url
|
7
8
|
|
8
|
-
render json: query.map { |row|
|
9
|
+
render json: query.map { |row| { text: row.url } }
|
9
10
|
end
|
10
11
|
|
11
12
|
end
|
@@ -4,7 +4,7 @@ module AhoyCaptain
|
|
4
4
|
def index
|
5
5
|
query = visit_query.all
|
6
6
|
|
7
|
-
render json: query.select("distinct referring_domain").where.not(referring_domain: nil).group(:referring_domain).order(Arel.sql "count(*) desc").pluck(:referring_domain).map { |city| serialize(city) }
|
7
|
+
render json: query.result.select("distinct referring_domain").where.not(referring_domain: nil).group(:referring_domain).order(Arel.sql "count(*) desc").pluck(:referring_domain).map { |city| serialize(city) }
|
8
8
|
end
|
9
9
|
end
|
10
10
|
end
|
@@ -2,7 +2,7 @@ module AhoyCaptain
|
|
2
2
|
module Filters
|
3
3
|
class UtmsController < BaseController
|
4
4
|
def index
|
5
|
-
query = visit_query.select("#{params[:type]}", "count(#{params[:type]}) as total").group(params[:type]).order(Arel.sql "count(#{params[:type]}) desc").pluck(params[:type]).map { |city| serialize(city) }
|
5
|
+
query = visit_query.select("#{params[:type]}", "count(#{params[:type]}) as total").group(params[:type]).order(Arel.sql "count(#{params[:type]}) desc").pluck(params[:type]).map { |city| serialize(city || "Direct/none") }
|
6
6
|
render json: query
|
7
7
|
end
|
8
8
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module AhoyCaptain
|
2
2
|
class RealtimesController < ApplicationController
|
3
3
|
def show
|
4
|
-
@total = event_query.where(
|
4
|
+
@total = event_query.where('time > ?', 1.minute.ago).distinct(:visit_id).count(:visit_id)
|
5
5
|
end
|
6
6
|
end
|
7
7
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module AhoyCaptain
|
2
|
+
class RegionsController < ApplicationController
|
3
|
+
include Limitable
|
4
|
+
|
5
|
+
before_action do
|
6
|
+
if Widget.disabled?(:locations, :regions)
|
7
|
+
raise Widget::WidgetDisabled.new("Widget disabled", :geography)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def index
|
12
|
+
results = cached(:regions) do
|
13
|
+
visit_query
|
14
|
+
.reselect("region, country, count(concat(region, country)) as count, sum(count(region)) over() as total_count")
|
15
|
+
.where.not(region: nil)
|
16
|
+
.group("region, country")
|
17
|
+
.order(Arel.sql "count(concat(region, country)) desc")
|
18
|
+
.limit(limit)
|
19
|
+
end
|
20
|
+
|
21
|
+
@regions = paginate(results).map { |region| RegionDecorator.new(region) }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -10,11 +10,14 @@ module AhoyCaptain
|
|
10
10
|
|
11
11
|
def index
|
12
12
|
results = cached(:sources) do
|
13
|
-
|
13
|
+
visit_query.select("substring(referring_domain from '(?:.*://)?(?:www\.)?([^/?]*)') as referring_domain, count(substring(referring_domain from '(?:.*://)?(?:www\.)?([^/?]*)')) as count, sum(count(substring(referring_domain from '(?:.*://)?(?:www\.)?([^/?]*)'))) OVER() as total_count")
|
14
|
+
.where.not(referring_domain: nil)
|
15
|
+
.group("substring(referring_domain from '(?:.*://)?(?:www\.)?([^/?]*)')")
|
16
|
+
.order(Arel.sql "count(substring(referring_domain from '(?:.*://)?(?:www\.)?([^/?]*)')) desc")
|
14
17
|
.limit(limit)
|
15
18
|
end
|
16
19
|
|
17
|
-
@sources = paginate(results).map { |source| AhoyCaptain::SourceDecorator.new(source
|
20
|
+
@sources = paginate(results).map { |source| AhoyCaptain::SourceDecorator.new(source) }
|
18
21
|
end
|
19
22
|
end
|
20
23
|
|
@@ -1,148 +1,6 @@
|
|
1
1
|
module AhoyCaptain
|
2
2
|
module Stats
|
3
3
|
class BaseController < ApplicationController
|
4
|
-
|
5
|
-
INTERVAL_PERIOD = {
|
6
|
-
"realtime" => ["minute"],
|
7
|
-
"day" => ["minute", "hour"],
|
8
|
-
"7d" => ["hour", "day"],
|
9
|
-
"month" => ["day", "week"],
|
10
|
-
"all" => ["day", "week", "month"]
|
11
|
-
}
|
12
|
-
|
13
|
-
INTERVALS = ["minute", "hour", "day", "week", "month"]
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
helper_method :metric_type
|
18
|
-
def metric_type(stats)
|
19
|
-
if compare_mode?
|
20
|
-
stats.current.values.first.try(:class) || stats.compared_to.values.first.try(:class)
|
21
|
-
else
|
22
|
-
stats.values.first.class
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
helper_method :selected_interval
|
27
|
-
def selected_interval
|
28
|
-
if params[:interval].in?(INTERVALS)
|
29
|
-
params[:interval]
|
30
|
-
else
|
31
|
-
default_interval_for_period
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def default_interval_for_period
|
36
|
-
default_interval_for_date_range(range)
|
37
|
-
end
|
38
|
-
|
39
|
-
def default_interval_for_date_range(range)
|
40
|
-
if range[1].nil?
|
41
|
-
# assume we're in a realtime
|
42
|
-
return INTERVAL_PERIOD["realtime"][0]
|
43
|
-
end
|
44
|
-
diff = (range[1] - range[0]).seconds.in_days
|
45
|
-
if diff >= 31
|
46
|
-
"month"
|
47
|
-
elsif diff > 1
|
48
|
-
"day"
|
49
|
-
elsif diff == 1
|
50
|
-
"hour"
|
51
|
-
else
|
52
|
-
"hour"
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
helper_method :available_intervals
|
57
|
-
def available_intervals
|
58
|
-
if range
|
59
|
-
return INTERVAL_PERIOD["realtime"] if range[1].nil?
|
60
|
-
|
61
|
-
diff = (range[1] - range[0]).seconds.in_days
|
62
|
-
|
63
|
-
if diff < 1
|
64
|
-
INTERVAL_PERIOD["day"]
|
65
|
-
elsif diff <= 7
|
66
|
-
INTERVAL_PERIOD["7d"]
|
67
|
-
elsif diff <= 31
|
68
|
-
INTERVAL_PERIOD["month"]
|
69
|
-
else
|
70
|
-
INTERVAL_PERIOD["all"]
|
71
|
-
end
|
72
|
-
else
|
73
|
-
INTERVAL_PERIOD["month"]
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def lazy_window(result, value = 0, base = nil)
|
78
|
-
if result.is_a?(AhoyCaptain::LazyComparableQuery::LazyComparison)
|
79
|
-
result.result.current = lazy_window(result.result.current, value, range)
|
80
|
-
result.result.compared_to = lazy_window(result.result.compared_to, value, result.compare_range)
|
81
|
-
return result.result
|
82
|
-
end
|
83
|
-
|
84
|
-
base ||= range
|
85
|
-
window = window_for(selected_interval, result.keys[0].class, base.numeric)
|
86
|
-
|
87
|
-
window.each do |item|
|
88
|
-
if result.key?(item)
|
89
|
-
next
|
90
|
-
end
|
91
|
-
|
92
|
-
result[item] ||= value
|
93
|
-
end
|
94
|
-
|
95
|
-
transform = interval_label_transformation(selected_interval)
|
96
|
-
|
97
|
-
if transform
|
98
|
-
result.transform_keys! { |key| key.strftime(transform) }
|
99
|
-
end
|
100
|
-
|
101
|
-
result
|
102
|
-
end
|
103
|
-
|
104
|
-
def interval_label_transformation(interval)
|
105
|
-
return nil
|
106
|
-
if interval == 'hour'
|
107
|
-
return '%H:%M %p'
|
108
|
-
end
|
109
|
-
|
110
|
-
nil
|
111
|
-
end
|
112
|
-
|
113
|
-
# base should be a range
|
114
|
-
def window_for(interval, type, base = nil)
|
115
|
-
function = case type.to_s
|
116
|
-
when 'Date', 'NilClass'
|
117
|
-
->(value) {
|
118
|
-
date = Time.at(value).utc
|
119
|
-
if interval == 'month'
|
120
|
-
date.change(day: 1)
|
121
|
-
elsif interval == 'week'
|
122
|
-
date.beginning_of_week
|
123
|
-
elsif interval == 'day'
|
124
|
-
date.beginning_of_day
|
125
|
-
elsif interval == 'hour'
|
126
|
-
date.beginning_of_hour
|
127
|
-
elsif interval == 'minute'
|
128
|
-
date.beginning_of_minute
|
129
|
-
else
|
130
|
-
abort
|
131
|
-
end.to_date
|
132
|
-
}
|
133
|
-
when 'DateTime'
|
134
|
-
->(value) { Time.at(value).utc.change(sec: 0) }
|
135
|
-
when 'ActiveSupport::TimeWithZone'
|
136
|
-
->(value) { Time.at(value).utc }
|
137
|
-
else
|
138
|
-
raise ArgumentError
|
139
|
-
end
|
140
|
-
|
141
|
-
base
|
142
|
-
.step(1.send(interval))
|
143
|
-
.to_a
|
144
|
-
.map { |value| function.call(value) }
|
145
|
-
end
|
146
4
|
end
|
147
5
|
end
|
148
6
|
end
|
@@ -1,11 +1,9 @@
|
|
1
1
|
module AhoyCaptain
|
2
2
|
module Stats
|
3
3
|
class BounceRatesController < BaseController
|
4
|
-
# @todo: this is lazy
|
5
4
|
def index
|
6
|
-
@stats = AhoyCaptain::Stats::BounceRatesQuery.call(params)
|
7
|
-
|
8
|
-
@label = "Bounce Rate"
|
5
|
+
@stats = AhoyCaptain::Stats::BounceRatesQuery.call(params).group_by_day("ahoy_visits.started_at").average("num_events * 100")
|
6
|
+
#.group_by_day("ahoy_visits.started_at").average("total_events")
|
9
7
|
end
|
10
8
|
end
|
11
9
|
end
|
@@ -2,8 +2,7 @@ module AhoyCaptain
|
|
2
2
|
module Stats
|
3
3
|
class TotalPageviewsController < BaseController
|
4
4
|
def index
|
5
|
-
@stats =
|
6
|
-
@label = "Visitors"
|
5
|
+
@stats = AhoyCaptain::Stats::TotalPageviewsQuery.call(params).group_by_day(:time).count
|
7
6
|
end
|
8
7
|
end
|
9
8
|
end
|
@@ -2,8 +2,7 @@ module AhoyCaptain
|
|
2
2
|
module Stats
|
3
3
|
class TotalVisitsController < BaseController
|
4
4
|
def index
|
5
|
-
@stats =
|
6
|
-
@label = "Visitors"
|
5
|
+
@stats = AhoyCaptain::Stats::TotalVisitorsQuery.call(params).group_by_day(:started_at).count
|
7
6
|
end
|
8
7
|
end
|
9
8
|
end
|
@@ -2,9 +2,7 @@ module AhoyCaptain
|
|
2
2
|
module Stats
|
3
3
|
class UniqueVisitorsController < BaseController
|
4
4
|
def index
|
5
|
-
@stats = AhoyCaptain::Stats::UniqueVisitorsQuery.call(params).
|
6
|
-
@stats = lazy_window(@stats)
|
7
|
-
@label = "Visitors"
|
5
|
+
@stats = AhoyCaptain::Stats::UniqueVisitorsQuery.call(params).group_by_day(:started_at).count
|
8
6
|
end
|
9
7
|
end
|
10
8
|
end
|
@@ -1,10 +1,15 @@
|
|
1
1
|
module AhoyCaptain
|
2
2
|
module Stats
|
3
3
|
class ViewsPerVisitsController < BaseController
|
4
|
-
|
5
|
-
@stats = lazy_window(AhoyCaptain::Stats::ViewsPerVisitQuery.call(params).with_lazy_comparison(compare_mode?).group_by_period(selected_interval, 'views_per_visit_table.started_at').average(:views_per_visit))
|
4
|
+
include Rangeable
|
6
5
|
|
7
|
-
|
6
|
+
def index
|
7
|
+
@stats = AhoyCaptain::Stats::ViewsPerVisitQuery.call(params).group_by_day('views_per_visit_table.started_at').average(:views_per_visit)
|
8
|
+
(range[0]..range[1]).to_a.each do |date|
|
9
|
+
unless @stats.key?(date.to_date)
|
10
|
+
@stats[date.to_date] = 2
|
11
|
+
end
|
12
|
+
end
|
8
13
|
end
|
9
14
|
end
|
10
15
|
end
|
@@ -2,8 +2,7 @@ module AhoyCaptain
|
|
2
2
|
module Stats
|
3
3
|
class VisitDurationsController < BaseController
|
4
4
|
def index
|
5
|
-
@stats =
|
6
|
-
@label = "Duration"
|
5
|
+
@stats = AhoyCaptain::Stats::VisitDurationQuery.call(params).group('started_at').average(:duration)
|
7
6
|
end
|
8
7
|
end
|
9
8
|
end
|
@@ -10,11 +10,17 @@ module AhoyCaptain
|
|
10
10
|
|
11
11
|
def index
|
12
12
|
results = cached(:top_pages) do
|
13
|
-
|
13
|
+
event_query.with_routes.select(
|
14
|
+
"#{AhoyCaptain.config.event[:url_column]} as url",
|
15
|
+
"count(*) as count",
|
16
|
+
"sum(count(*)) over() as total_count"
|
17
|
+
)
|
18
|
+
.group(Arel.sql ("(#{AhoyCaptain.config.event[:url_column]})"))
|
19
|
+
.order(Arel.sql("count(#{AhoyCaptain.config.event[:url_column]}) desc"))
|
14
20
|
.limit(limit)
|
15
21
|
end
|
16
22
|
|
17
|
-
@pages = paginate(results).map { |page| TopPageDecorator.new(page
|
23
|
+
@pages = paginate(results).map { |page| TopPageDecorator.new(page) }
|
18
24
|
end
|
19
25
|
end
|
20
26
|
end
|
@@ -1,39 +1,15 @@
|
|
1
|
-
require 'csv'
|
2
|
-
|
3
1
|
module AhoyCaptain
|
4
2
|
class ApplicationDecorator
|
5
3
|
attr_reader :object
|
6
4
|
|
7
|
-
def
|
8
|
-
rows = collection.map { |row| new(row, context) }
|
9
|
-
CSV.generate do |csv|
|
10
|
-
csv << csv_map(context.params).keys
|
11
|
-
|
12
|
-
rows.each do |row|
|
13
|
-
items = []
|
14
|
-
csv_map.values.each do |attr|
|
15
|
-
items << row.send(attr)
|
16
|
-
end
|
17
|
-
|
18
|
-
csv << items
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def self.csv_map(params = {})
|
24
|
-
raise NotImplementedError
|
25
|
-
end
|
26
|
-
|
27
|
-
delegate_missing_to :object
|
28
|
-
def initialize(object, context)
|
5
|
+
def initialize(object)
|
29
6
|
@object = object
|
30
|
-
@context = context
|
31
7
|
end
|
32
8
|
|
33
9
|
private
|
34
10
|
|
35
11
|
def h
|
36
|
-
@h ||=
|
12
|
+
@h ||= Current.request.view_context
|
37
13
|
end
|
38
14
|
|
39
15
|
def params
|
@@ -52,7 +28,7 @@ module AhoyCaptain
|
|
52
28
|
end
|
53
29
|
|
54
30
|
def request
|
55
|
-
|
31
|
+
Current.request.request
|
56
32
|
end
|
57
33
|
end
|
58
34
|
end
|