ahoy_captain 0.8 → 0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +21 -13
  3. data/app/assets/javascript/ahoy_captain/application.js +4 -4
  4. data/app/assets/javascript/ahoy_captain/controllers/active_links_controller.js +14 -0
  5. data/app/assets/javascript/ahoy_captain/controllers/application.js +5 -5
  6. data/app/assets/javascript/ahoy_captain/controllers/application_controller.js +9 -10
  7. data/app/assets/javascript/ahoy_captain/controllers/details_modal_controller.js +5 -5
  8. data/app/assets/javascript/ahoy_captain/controllers/dropdown_label_controller.js +2 -2
  9. data/app/assets/javascript/ahoy_captain/controllers/filter/item_controller.js +12 -0
  10. data/app/assets/javascript/ahoy_captain/controllers/filter_form_controller.js +13 -0
  11. data/app/assets/javascript/ahoy_captain/controllers/filter_tag_controller.js +11 -8
  12. data/app/assets/javascript/ahoy_captain/controllers/funnel_chart_controller.js +77 -107
  13. data/app/assets/javascript/ahoy_captain/controllers/index.js +4 -3
  14. data/app/assets/javascript/ahoy_captain/controllers/interval_controller.js +3 -3
  15. data/app/assets/javascript/ahoy_captain/controllers/line_chart_controller.js +37 -0
  16. data/app/assets/javascript/ahoy_captain/controllers/predicate_select_controller.js +10 -0
  17. data/app/assets/javascript/ahoy_captain/controllers/realtime_controller.js +9 -8
  18. data/app/assets/javascript/ahoy_captain/controllers/search_select_controller.js +65 -0
  19. data/app/assets/javascript/ahoy_captain/controllers/toggle_controller.js +17 -0
  20. data/app/components/ahoy_captain/dropdown_button_component.html.erb +5 -5
  21. data/app/components/ahoy_captain/dropdown_link_component.html.erb +5 -5
  22. data/app/components/ahoy_captain/filter/dropdown_component.html.erb +48 -0
  23. data/app/components/ahoy_captain/filter/dropdown_component.rb +51 -0
  24. data/app/components/ahoy_captain/filter/modal_component.html.erb +8 -7
  25. data/app/components/ahoy_captain/filter/select_component.html.erb +14 -12
  26. data/app/components/ahoy_captain/filter/select_component.rb +40 -9
  27. data/app/components/ahoy_captain/filter/tag_component.html.erb +8 -4
  28. data/app/components/ahoy_captain/filter/tag_component.rb +6 -30
  29. data/app/components/ahoy_captain/filter/tag_container_component.html.erb +2 -3
  30. data/app/components/ahoy_captain/filter/tag_container_component.rb +1 -8
  31. data/app/components/ahoy_captain/stats/container_component.html.erb +8 -0
  32. data/app/components/ahoy_captain/stats/container_component.rb +11 -0
  33. data/app/components/ahoy_captain/sticky_nav_component.html.erb +7 -19
  34. data/app/components/ahoy_captain/sticky_nav_component.rb +8 -0
  35. data/app/components/ahoy_captain/table_component.html.erb +4 -37
  36. data/app/components/ahoy_captain/table_component.rb +15 -4
  37. data/app/components/ahoy_captain/tables/headers/devices_header_component.html.erb +3 -0
  38. data/app/components/ahoy_captain/tables/headers/devices_header_component.rb +9 -0
  39. data/app/components/ahoy_captain/tables/headers/goals_header_component.html.erb +6 -0
  40. data/app/components/ahoy_captain/tables/headers/goals_header_component.rb +9 -0
  41. data/app/components/ahoy_captain/tables/headers/header_component.html.erb +5 -0
  42. data/app/components/ahoy_captain/tables/headers/header_component.rb +12 -0
  43. data/app/components/ahoy_captain/tables/rows/devices_row_component.html.erb +5 -0
  44. data/app/components/ahoy_captain/tables/rows/devices_row_component.rb +12 -0
  45. data/app/components/ahoy_captain/tables/rows/goals_row_component.html.erb +11 -0
  46. data/app/components/ahoy_captain/tables/rows/goals_row_component.rb +20 -0
  47. data/app/components/ahoy_captain/tables/rows/row_component.html.erb +6 -0
  48. data/app/components/ahoy_captain/tables/rows/row_component.rb +41 -0
  49. data/app/components/ahoy_captain/tile_component.html.erb +4 -3
  50. data/app/components/ahoy_captain/tile_component.rb +1 -1
  51. data/app/components/ahoy_captain/tooltip_component.html.erb +2 -2
  52. data/app/controllers/ahoy_captain/application_controller.rb +13 -14
  53. data/app/controllers/ahoy_captain/campaigns_controller.rb +2 -10
  54. data/app/controllers/ahoy_captain/cities_controller.rb +2 -6
  55. data/app/controllers/ahoy_captain/countries_controller.rb +2 -6
  56. data/app/controllers/ahoy_captain/devices_controller.rb +3 -6
  57. data/app/controllers/ahoy_captain/entry_pages_controller.rb +2 -4
  58. data/app/controllers/ahoy_captain/exit_pages_controller.rb +3 -4
  59. data/app/controllers/ahoy_captain/exports_controller.rb +15 -0
  60. data/app/controllers/ahoy_captain/filters/pages/entry_pages_controller.rb +2 -2
  61. data/app/controllers/ahoy_captain/filters/pages/exit_pages_controller.rb +1 -2
  62. data/app/controllers/ahoy_captain/filters/properties/names_controller.rb +11 -0
  63. data/app/controllers/ahoy_captain/filters/properties/values_controller.rb +15 -0
  64. data/app/controllers/ahoy_captain/filters/sources_controller.rb +1 -1
  65. data/app/controllers/ahoy_captain/regions_controller.rb +3 -7
  66. data/app/controllers/ahoy_captain/sources_controller.rb +2 -5
  67. data/app/controllers/ahoy_captain/stats/base_controller.rb +3 -3
  68. data/app/controllers/ahoy_captain/stats/bounce_rates_controller.rb +1 -0
  69. data/app/controllers/ahoy_captain/stats/total_pageviews_controller.rb +1 -0
  70. data/app/controllers/ahoy_captain/stats/total_visits_controller.rb +1 -0
  71. data/app/controllers/ahoy_captain/stats/unique_visitors_controller.rb +1 -0
  72. data/app/controllers/ahoy_captain/stats/views_per_visits_controller.rb +3 -2
  73. data/app/controllers/ahoy_captain/stats/visit_durations_controller.rb +1 -0
  74. data/app/controllers/ahoy_captain/top_pages_controller.rb +2 -8
  75. data/app/decorators/ahoy_captain/application_decorator.rb +27 -3
  76. data/app/decorators/ahoy_captain/campaign_decorator.rb +8 -0
  77. data/app/decorators/ahoy_captain/city_decorator.rb +12 -0
  78. data/app/decorators/ahoy_captain/country_decorator.rb +10 -0
  79. data/app/decorators/ahoy_captain/device_decorator.rb +13 -2
  80. data/app/decorators/ahoy_captain/page_decorator.rb +11 -0
  81. data/app/decorators/ahoy_captain/region_decorator.rb +16 -0
  82. data/app/decorators/ahoy_captain/source_decorator.rb +7 -0
  83. data/app/helpers/ahoy_captain/application_helper.rb +33 -0
  84. data/app/models/ahoy_captain/export.rb +48 -0
  85. data/app/models/ahoy_captain/filter_parser.rb +67 -0
  86. data/app/presenters/ahoy_captain/dashboard_presenter.rb +6 -1
  87. data/app/presenters/ahoy_captain/goals_presenter.rb +3 -2
  88. data/app/queries/ahoy_captain/application_query.rb +4 -3
  89. data/app/queries/ahoy_captain/campaign_query.rb +14 -0
  90. data/app/queries/ahoy_captain/city_query.rb +11 -0
  91. data/app/queries/ahoy_captain/country_query.rb +10 -0
  92. data/app/queries/ahoy_captain/device_query.rb +10 -0
  93. data/app/queries/ahoy_captain/entry_pages_query.rb +3 -2
  94. data/app/queries/ahoy_captain/event_query.rb +17 -15
  95. data/app/queries/ahoy_captain/exit_pages_query.rb +6 -4
  96. data/app/queries/ahoy_captain/region_query.rb +11 -0
  97. data/app/queries/ahoy_captain/source_query.rb +10 -0
  98. data/app/queries/ahoy_captain/top_page_query.rb +13 -0
  99. data/app/queries/ahoy_captain/visit_query.rb +1 -1
  100. data/app/views/ahoy_captain/devices/_table.html.erb +5 -0
  101. data/app/views/ahoy_captain/devices/index.html+details.erb +1 -1
  102. data/app/views/ahoy_captain/devices/index.html.erb +2 -2
  103. data/app/views/ahoy_captain/funnels/show.html.erb +5 -2
  104. data/app/views/ahoy_captain/goals/index.html.erb +3 -35
  105. data/app/views/ahoy_captain/layouts/application.html.erb +3 -3
  106. data/app/views/ahoy_captain/realtimes/show.html.erb +1 -1
  107. data/app/views/ahoy_captain/roots/_filters.html.erb +34 -0
  108. data/app/views/ahoy_captain/roots/show.html.erb +33 -95
  109. data/app/views/ahoy_captain/stats/base/index.html.erb +4 -7
  110. data/app/views/ahoy_captain/stats/show.html.erb +6 -51
  111. data/config/routes.rb +7 -0
  112. data/lib/ahoy_captain/ahoy/event_methods.rb +36 -73
  113. data/lib/ahoy_captain/ahoy/visit_methods.rb +1 -1
  114. data/lib/ahoy_captain/configuration.rb +13 -3
  115. data/lib/ahoy_captain/engine.rb +18 -0
  116. data/lib/ahoy_captain/filter_configuration/filter.rb +16 -0
  117. data/lib/ahoy_captain/filter_configuration/filter_collection.rb +48 -0
  118. data/lib/ahoy_captain/filters_configuration.rb +73 -0
  119. data/lib/ahoy_captain/goals.rb +10 -2
  120. data/lib/ahoy_captain/period_collection.rb +1 -1
  121. data/lib/ahoy_captain/predicate_label.rb +7 -0
  122. data/lib/ahoy_captain/version.rb +1 -1
  123. data/lib/ahoy_captain.rb +1 -0
  124. data/lib/generators/ahoy_captain/templates/config.rb.tt +25 -0
  125. metadata +56 -20
  126. data/app/assets/javascript/ahoy_captain/controllers/filter_controller.js +0 -145
  127. data/app/assets/javascript/ahoy_captain/controllers/link_controller.js +0 -43
  128. data/app/assets/javascript/ahoy_captain/controllers/navigation_controller.js +0 -25
  129. data/app/models/ahoy_captain/current.rb +0 -9
  130. data/app/models/ahoy_captain/url_helpers.rb +0 -6
@@ -0,0 +1,73 @@
1
+ require 'ahoy_captain/filter_configuration/filter'
2
+ require 'ahoy_captain/filter_configuration/filter_collection'
3
+
4
+ module AhoyCaptain
5
+ class FiltersConfiguration
6
+ def self.load_default
7
+ new.tap do |config|
8
+ config.register("Page") do
9
+ filter column: :route, label: "Route", url: :filters_actions_path, predicates: [:in, :not_in]
10
+ filter column: :entry_page, label: "Entry Page", url: :filters_entry_pages_path, predicates: [:in, :not_in]
11
+ filter column: :exit_page, label: "Exit Page", url: :filters_exit_pages_path, predicates: [:in, :not_in]
12
+ end
13
+
14
+ config.register("Geography") do
15
+ filter column: :country, label: "Country", url: :filters_locations_countries_path, predicates: [:in, :not_in]
16
+ filter column: :region, label: "Region", url: :filters_locations_regions_path, predicates: [:in, :not_in]
17
+ filter column: :city, label: "City", url: :filters_locations_cities_path, predicates: [:in, :not_in]
18
+ end
19
+
20
+ config.register("Source") do
21
+ filter column: :referring_domain, label: "Source", url: :filters_sources_path, predicates: [:in, :not_in]
22
+ end
23
+
24
+ config.register("Screen size") do
25
+ filter column: :device_type, label: "Screen size", url: :filters_screens_path, predicates: [:in, :not_in]
26
+ end
27
+
28
+ config.register("Operating System") do
29
+ filter column: :os, label: "OS Name", url: :filters_names_path, predicates: [:in, :not_in]
30
+ filter column: :os_version, label: "OS Version", url: :filters_versions_path, predicates: [:in, :not_in]
31
+ end
32
+
33
+ config.register("UTM Tag") do
34
+ filter column: :utm_medium, label: "UTM Medium", url: :filters_utm_mediums_path, predicates: [:in, :not_in]
35
+ filter column: :utm_source, label: "UTM Source", url: :filters_utm_sources_path, predicates: [:in, :not_in]
36
+ filter column: :utm_campaign, label: "UTM Campaign", url: :filters_utm_campaigns_path, predicates: [:in, :not_in]
37
+ filter column: :utm_term, label: "UTM Term", url: :filters_utm_terms_path, predicates: [:in, :not_in]
38
+ filter column: :utm_content, label: "UTM Content", url: :filters_utm_contents_path, predicates: [:in, :not_in]
39
+ end
40
+ end
41
+ end
42
+
43
+ def initialize
44
+ @registry = {}
45
+ end
46
+
47
+ def register(label, &block)
48
+ item = FilterConfiguration::FilterCollection.new(label)
49
+ item.instance_exec(&block)
50
+ @registry[label] = item
51
+ end
52
+
53
+ def [](val)
54
+ @registry[val]
55
+ end
56
+
57
+ def delete(name)
58
+ @registry.delete(name)
59
+ end
60
+
61
+ def reset
62
+ @registry = {}
63
+ end
64
+
65
+ def each(&block)
66
+ @registry.each(&block)
67
+ end
68
+
69
+ def detect(&block)
70
+ @registry.detect(&block)
71
+ end
72
+ end
73
+ end
@@ -13,7 +13,15 @@ module AhoyCaptain
13
13
  end
14
14
 
15
15
  def name(value)
16
- @event_query = -> { AhoyCaptain.event.where(name: value) }
16
+ @event_query = -> { ::AhoyCaptain.event.where(name: value) }
17
+ end
18
+
19
+ def event(value)
20
+ ActiveSupport::Deprecation.warn(
21
+ "event is deprecated. " \
22
+ "Use name instead."
23
+ )
24
+ name(value)
17
25
  end
18
26
 
19
27
  def query(&block)
@@ -25,7 +33,7 @@ module AhoyCaptain
25
33
  include Enumerable
26
34
 
27
35
  def initialize
28
- @goals = {}
36
+ @goals = {}.with_indifferent_access
29
37
  end
30
38
 
31
39
  def register(goal)
@@ -51,7 +51,7 @@ module AhoyCaptain
51
51
  }.each do |param, options|
52
52
  instance.add(param, options[:label], options[:range])
53
53
  end
54
- instance.default = :mtd
54
+ instance.default = :'30d'
55
55
  instance
56
56
  end
57
57
 
@@ -0,0 +1,7 @@
1
+ module AhoyCaptain
2
+ class PredicateLabel
3
+ def self.[](value)
4
+ AhoyCaptain.config.predicate_labels[value.to_sym] || value.to_s.titleize
5
+ end
6
+ end
7
+ end
@@ -1,3 +1,3 @@
1
1
  module AhoyCaptain
2
- VERSION = "0.8"
2
+ VERSION = "0.9"
3
3
  end
data/lib/ahoy_captain.rb CHANGED
@@ -4,6 +4,7 @@ require "ahoy_captain/engine"
4
4
  require "ahoy_captain/goals"
5
5
  require "ahoy_captain/funnels"
6
6
  require "ahoy_captain/configuration"
7
+ require "ahoy_captain/predicate_label"
7
8
  require 'ahoy_captain/ahoy/visit_methods'
8
9
  require 'ahoy_captain/ahoy/event_methods'
9
10
 
@@ -81,6 +81,31 @@ AhoyCaptain.configure do |config|
81
81
  # Set to false to disable custom ranges
82
82
  # config.ranges.custom = true
83
83
 
84
+ # ==> Filters
85
+ #
86
+ # Defaults come from lib/ahoy_captain/filter_configuration.rb
87
+ #
88
+ # If you want your own entirely, first call reset.
89
+ # config.filters.reset
90
+ #
91
+ # Then you can add your own.
92
+ #
93
+ # config.filters.register "Group label" do
94
+ # filter label: "Some label", column: :column_name, url: :url_for_options, predicates: [:in, :not_in], multiple: true
95
+ # end
96
+ #
97
+ # You can also remove an existing group:
98
+ #
99
+ # config.filters.delete("Group label")
100
+ #
101
+ # Remove a specific filter from a group:
102
+ #
103
+ # config.filters["Group label"].delete(:column_name)
104
+ #
105
+ # You can add to an existing group:
106
+ #
107
+ # config.filters["Group label"].filter label: "Some label", column: :column_name, url: :url_for_options, predicates: [:in, :not_in], multiple: true
108
+
84
109
  # ==> Caching
85
110
  # config.cache.enabled = false
86
111
  #
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ahoy_captain
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.8'
4
+ version: '0.9'
5
5
  platform: ruby
6
6
  authors:
7
7
  - joshmn
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-03 00:00:00.000000000 Z
11
+ date: 2023-08-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -151,35 +151,35 @@ dependencies:
151
151
  - !ruby/object:Gem::Version
152
152
  version: '4'
153
153
  - !ruby/object:Gem::Dependency
154
- name: rails
154
+ name: rubyzip
155
155
  requirement: !ruby/object:Gem::Requirement
156
156
  requirements:
157
157
  - - ">="
158
158
  - !ruby/object:Gem::Version
159
- version: '6'
160
- type: :development
159
+ version: '0'
160
+ type: :runtime
161
161
  prerelease: false
162
162
  version_requirements: !ruby/object:Gem::Requirement
163
163
  requirements:
164
164
  - - ">="
165
165
  - !ruby/object:Gem::Version
166
- version: '6'
166
+ version: '0'
167
167
  - !ruby/object:Gem::Dependency
168
- name: sprockets-rails
168
+ name: rails
169
169
  requirement: !ruby/object:Gem::Requirement
170
170
  requirements:
171
171
  - - ">="
172
172
  - !ruby/object:Gem::Version
173
- version: '0'
173
+ version: '6'
174
174
  type: :development
175
175
  prerelease: false
176
176
  version_requirements: !ruby/object:Gem::Requirement
177
177
  requirements:
178
178
  - - ">="
179
179
  - !ruby/object:Gem::Version
180
- version: '0'
180
+ version: '6'
181
181
  - !ruby/object:Gem::Dependency
182
- name: better_errors
182
+ name: sprockets-rails
183
183
  requirement: !ruby/object:Gem::Requirement
184
184
  requirements:
185
185
  - - ">="
@@ -193,7 +193,7 @@ dependencies:
193
193
  - !ruby/object:Gem::Version
194
194
  version: '0'
195
195
  - !ruby/object:Gem::Dependency
196
- name: binding_of_caller
196
+ name: better_errors
197
197
  requirement: !ruby/object:Gem::Requirement
198
198
  requirements:
199
199
  - - ">="
@@ -207,7 +207,7 @@ dependencies:
207
207
  - !ruby/object:Gem::Version
208
208
  version: '0'
209
209
  - !ruby/object:Gem::Dependency
210
- name: sassc
210
+ name: binding_of_caller
211
211
  requirement: !ruby/object:Gem::Requirement
212
212
  requirements:
213
213
  - - ">="
@@ -221,7 +221,7 @@ dependencies:
221
221
  - !ruby/object:Gem::Version
222
222
  version: '0'
223
223
  - !ruby/object:Gem::Dependency
224
- name: puma
224
+ name: sassc
225
225
  requirement: !ruby/object:Gem::Requirement
226
226
  requirements:
227
227
  - - ">="
@@ -235,7 +235,7 @@ dependencies:
235
235
  - !ruby/object:Gem::Version
236
236
  version: '0'
237
237
  - !ruby/object:Gem::Dependency
238
- name: pg
238
+ name: puma
239
239
  requirement: !ruby/object:Gem::Requirement
240
240
  requirements:
241
241
  - - ">="
@@ -249,7 +249,7 @@ dependencies:
249
249
  - !ruby/object:Gem::Version
250
250
  version: '0'
251
251
  - !ruby/object:Gem::Dependency
252
- name: pp_sql
252
+ name: pg
253
253
  requirement: !ruby/object:Gem::Requirement
254
254
  requirements:
255
255
  - - ">="
@@ -278,23 +278,29 @@ files:
278
278
  - app/assets/images/ahoy_captain/logo.png
279
279
  - app/assets/images/ahoy_captain/safari-pinned-tab.svg
280
280
  - app/assets/javascript/ahoy_captain/application.js
281
+ - app/assets/javascript/ahoy_captain/controllers/active_links_controller.js
281
282
  - app/assets/javascript/ahoy_captain/controllers/application.js
282
283
  - app/assets/javascript/ahoy_captain/controllers/application_controller.js
283
284
  - app/assets/javascript/ahoy_captain/controllers/details_modal_controller.js
284
285
  - app/assets/javascript/ahoy_captain/controllers/dropdown_label_controller.js
285
- - app/assets/javascript/ahoy_captain/controllers/filter_controller.js
286
+ - app/assets/javascript/ahoy_captain/controllers/filter/item_controller.js
287
+ - app/assets/javascript/ahoy_captain/controllers/filter_form_controller.js
286
288
  - app/assets/javascript/ahoy_captain/controllers/filter_tag_controller.js
287
289
  - app/assets/javascript/ahoy_captain/controllers/funnel_chart_controller.js
288
290
  - app/assets/javascript/ahoy_captain/controllers/index.js
289
291
  - app/assets/javascript/ahoy_captain/controllers/interval_controller.js
290
- - app/assets/javascript/ahoy_captain/controllers/link_controller.js
291
- - app/assets/javascript/ahoy_captain/controllers/navigation_controller.js
292
+ - app/assets/javascript/ahoy_captain/controllers/line_chart_controller.js
293
+ - app/assets/javascript/ahoy_captain/controllers/predicate_select_controller.js
292
294
  - app/assets/javascript/ahoy_captain/controllers/realtime_controller.js
295
+ - app/assets/javascript/ahoy_captain/controllers/search_select_controller.js
296
+ - app/assets/javascript/ahoy_captain/controllers/toggle_controller.js
293
297
  - app/assets/manifest/ahoy_captain/manifest.js
294
298
  - app/components/ahoy_captain/dropdown_button_component.html.erb
295
299
  - app/components/ahoy_captain/dropdown_button_component.rb
296
300
  - app/components/ahoy_captain/dropdown_link_component.html.erb
297
301
  - app/components/ahoy_captain/dropdown_link_component.rb
302
+ - app/components/ahoy_captain/filter/dropdown_component.html.erb
303
+ - app/components/ahoy_captain/filter/dropdown_component.rb
298
304
  - app/components/ahoy_captain/filter/modal_component.html.erb
299
305
  - app/components/ahoy_captain/filter/modal_component.rb
300
306
  - app/components/ahoy_captain/filter/select_component.html.erb
@@ -303,10 +309,24 @@ files:
303
309
  - app/components/ahoy_captain/filter/tag_component.rb
304
310
  - app/components/ahoy_captain/filter/tag_container_component.html.erb
305
311
  - app/components/ahoy_captain/filter/tag_container_component.rb
312
+ - app/components/ahoy_captain/stats/container_component.html.erb
313
+ - app/components/ahoy_captain/stats/container_component.rb
306
314
  - app/components/ahoy_captain/sticky_nav_component.html.erb
307
315
  - app/components/ahoy_captain/sticky_nav_component.rb
308
316
  - app/components/ahoy_captain/table_component.html.erb
309
317
  - app/components/ahoy_captain/table_component.rb
318
+ - app/components/ahoy_captain/tables/headers/devices_header_component.html.erb
319
+ - app/components/ahoy_captain/tables/headers/devices_header_component.rb
320
+ - app/components/ahoy_captain/tables/headers/goals_header_component.html.erb
321
+ - app/components/ahoy_captain/tables/headers/goals_header_component.rb
322
+ - app/components/ahoy_captain/tables/headers/header_component.html.erb
323
+ - app/components/ahoy_captain/tables/headers/header_component.rb
324
+ - app/components/ahoy_captain/tables/rows/devices_row_component.html.erb
325
+ - app/components/ahoy_captain/tables/rows/devices_row_component.rb
326
+ - app/components/ahoy_captain/tables/rows/goals_row_component.html.erb
327
+ - app/components/ahoy_captain/tables/rows/goals_row_component.rb
328
+ - app/components/ahoy_captain/tables/rows/row_component.html.erb
329
+ - app/components/ahoy_captain/tables/rows/row_component.rb
310
330
  - app/components/ahoy_captain/tile_component.html.erb
311
331
  - app/components/ahoy_captain/tile_component.rb
312
332
  - app/components/ahoy_captain/tooltip_component.html.erb
@@ -318,6 +338,7 @@ files:
318
338
  - app/controllers/ahoy_captain/devices_controller.rb
319
339
  - app/controllers/ahoy_captain/entry_pages_controller.rb
320
340
  - app/controllers/ahoy_captain/exit_pages_controller.rb
341
+ - app/controllers/ahoy_captain/exports_controller.rb
321
342
  - app/controllers/ahoy_captain/filters/base_controller.rb
322
343
  - app/controllers/ahoy_captain/filters/locations_controller.rb
323
344
  - app/controllers/ahoy_captain/filters/operating_systems/names_controller.rb
@@ -325,6 +346,8 @@ files:
325
346
  - app/controllers/ahoy_captain/filters/pages/actions_controller.rb
326
347
  - app/controllers/ahoy_captain/filters/pages/entry_pages_controller.rb
327
348
  - app/controllers/ahoy_captain/filters/pages/exit_pages_controller.rb
349
+ - app/controllers/ahoy_captain/filters/properties/names_controller.rb
350
+ - app/controllers/ahoy_captain/filters/properties/values_controller.rb
328
351
  - app/controllers/ahoy_captain/filters/screens_controller.rb
329
352
  - app/controllers/ahoy_captain/filters/sources_controller.rb
330
353
  - app/controllers/ahoy_captain/filters/utms_controller.rb
@@ -355,18 +378,24 @@ files:
355
378
  - app/decorators/ahoy_captain/source_decorator.rb
356
379
  - app/decorators/ahoy_captain/top_page_decorator.rb
357
380
  - app/helpers/ahoy_captain/application_helper.rb
358
- - app/models/ahoy_captain/current.rb
381
+ - app/models/ahoy_captain/export.rb
382
+ - app/models/ahoy_captain/filter_parser.rb
359
383
  - app/models/ahoy_captain/rangeable.rb
360
- - app/models/ahoy_captain/url_helpers.rb
361
384
  - app/models/ahoy_captain/widget.rb
362
385
  - app/models/concerns/ahoy_captain/range_options.rb
363
386
  - app/presenters/ahoy_captain/dashboard_presenter.rb
364
387
  - app/presenters/ahoy_captain/funnel_presenter.rb
365
388
  - app/presenters/ahoy_captain/goals_presenter.rb
366
389
  - app/queries/ahoy_captain/application_query.rb
390
+ - app/queries/ahoy_captain/campaign_query.rb
391
+ - app/queries/ahoy_captain/city_query.rb
392
+ - app/queries/ahoy_captain/country_query.rb
393
+ - app/queries/ahoy_captain/device_query.rb
367
394
  - app/queries/ahoy_captain/entry_pages_query.rb
368
395
  - app/queries/ahoy_captain/event_query.rb
369
396
  - app/queries/ahoy_captain/exit_pages_query.rb
397
+ - app/queries/ahoy_captain/region_query.rb
398
+ - app/queries/ahoy_captain/source_query.rb
370
399
  - app/queries/ahoy_captain/stats/average_views_per_visit_query.rb
371
400
  - app/queries/ahoy_captain/stats/average_visit_duration_query.rb
372
401
  - app/queries/ahoy_captain/stats/bounce_rates_query.rb
@@ -375,6 +404,7 @@ files:
375
404
  - app/queries/ahoy_captain/stats/unique_visitors_query.rb
376
405
  - app/queries/ahoy_captain/stats/views_per_visit_query.rb
377
406
  - app/queries/ahoy_captain/stats/visit_duration_query.rb
407
+ - app/queries/ahoy_captain/top_page_query.rb
378
408
  - app/queries/ahoy_captain/visit_query.rb
379
409
  - app/views/ahoy_captain/campaigns/index.html+details.erb
380
410
  - app/views/ahoy_captain/campaigns/index.html.erb
@@ -382,6 +412,7 @@ files:
382
412
  - app/views/ahoy_captain/cities/index.html.erb
383
413
  - app/views/ahoy_captain/countries/index.html+details.erb
384
414
  - app/views/ahoy_captain/countries/index.html.erb
415
+ - app/views/ahoy_captain/devices/_table.html.erb
385
416
  - app/views/ahoy_captain/devices/index.html+details.erb
386
417
  - app/views/ahoy_captain/devices/index.html.erb
387
418
  - app/views/ahoy_captain/entry_pages/index.html+details.erb
@@ -395,6 +426,7 @@ files:
395
426
  - app/views/ahoy_captain/realtimes/show.html.erb
396
427
  - app/views/ahoy_captain/regions/index.html+details.erb
397
428
  - app/views/ahoy_captain/regions/index.html.erb
429
+ - app/views/ahoy_captain/roots/_filters.html.erb
398
430
  - app/views/ahoy_captain/roots/show.html.erb
399
431
  - app/views/ahoy_captain/sources/index.html+details.erb
400
432
  - app/views/ahoy_captain/sources/index.html.erb
@@ -409,9 +441,13 @@ files:
409
441
  - lib/ahoy_captain/ahoy/visit_methods.rb
410
442
  - lib/ahoy_captain/configuration.rb
411
443
  - lib/ahoy_captain/engine.rb
444
+ - lib/ahoy_captain/filter_configuration/filter.rb
445
+ - lib/ahoy_captain/filter_configuration/filter_collection.rb
446
+ - lib/ahoy_captain/filters_configuration.rb
412
447
  - lib/ahoy_captain/funnels.rb
413
448
  - lib/ahoy_captain/goals.rb
414
449
  - lib/ahoy_captain/period_collection.rb
450
+ - lib/ahoy_captain/predicate_label.rb
415
451
  - lib/ahoy_captain/railtie.rb
416
452
  - lib/ahoy_captain/version.rb
417
453
  - lib/generators/ahoy_captain/install_generator.rb
@@ -1,145 +0,0 @@
1
- import {Controller} from "@hotwired/stimulus"
2
- import SlimSelect from 'slim-select'
3
-
4
- export default class extends Controller {
5
- static values = {
6
- url: String,
7
- column: String,
8
- };
9
- static targets = ["select", 'predicate'];
10
- connect() {
11
- this.selectTargets.forEach(async (target) => {
12
- const url = target.dataset.filterUrlValue;
13
- const optionsSearch = this.fetchOptions(url, target);
14
- const select = await new SlimSelect({
15
- select: target,
16
- data: [],
17
- settings: {
18
- contentPosition: 'relative',
19
- contentLocation: target.closest('fieldset'),
20
- searchText: 'Sorry, no results found',
21
- searchPlaceholder: 'Type to populate results',
22
- placeholderText: `Search for ${target.dataset.filterColumnValue}`,
23
- searchHighlight: true
24
- },
25
- events: {
26
- beforeOpen: async () => {
27
- if (!this.#hasData(target) & !this.#hasSelections(target) ) {
28
- const data = await optionsSearch();
29
- target.slim.setData(data);
30
- }
31
- },
32
- search: async (search, currentData) => {
33
- const data = await optionsSearch(search);
34
- const filteredData = data.filter(item => !currentData.some((selectedItem) => selectedItem.text == item.text ))
35
- return filteredData;
36
- },
37
- beforeChange: this.#beforeChange(target, url),
38
- }
39
- });
40
- const json = JSON.parse(target.dataset.filterSelected)
41
- if(json.length) {
42
- select.setData(json.map(item => ({ "text": item, "value": item })))
43
- select.setSelected(json)
44
- }
45
- })
46
- }
47
-
48
- fetchOptions(url, target) {
49
- return async (search) => {
50
- const query = this.#buildQueryFilters(search, target);
51
- const response = await fetch(`${url}?${query.toString()}`);
52
- const data = await response.json();
53
- return data;
54
- }
55
- }
56
-
57
- #buildQueryFilters(search, target) {
58
- const query = new URLSearchParams(window.location.search);
59
- const otherFilters = this.selectTargets.filter(filter => filter != target);
60
- otherFilters.forEach(function(filter) {
61
- filter.slim.getSelected().forEach(val => {
62
- const filterName = `${filter.name}[]`
63
- if(query.has(filterName)) {
64
- console.log("has the filter")
65
- if(!query.get(`${filter.name}[]`).includes(val)) {
66
- query.append(filterName, value)
67
- }
68
- } else {
69
- query.append(filterName, value)
70
- }
71
- })
72
- });
73
- query.set(`q[${target.dataset.filterColumnValue}_i_cont]`, search || "");
74
- return query;
75
- }
76
-
77
- #beforeChange(target, url) {
78
- return () => {
79
- const otherFilters = this.selectTargets.filter(filter => filter != target);
80
- otherFilters.forEach(async target => {
81
- if (this.#hasData(target)) {
82
- const selected = target.slim.getSelected()
83
- target.slim.setData(selected.map(text => ({ text })))
84
- // setting data triggers a slim render, so need to also set selected again
85
- target.slim.setSelected(selected)
86
- }
87
- })
88
- return true;
89
- }
90
- }
91
-
92
- #hasData(target) {
93
- return target.slim.getData().length !== 0;
94
- }
95
-
96
- #hasSelections(target) {
97
- return target.slim.getSelected().length !== 0;
98
- }
99
-
100
- #filtersForQuery() {
101
- const predicates = this.predicateTargets.map(el => ({name: el.name, column_predicate: el.value}));
102
- const filterValues = this.selectTargets.map(el => ({name: el.name, selections: el.slim.getSelected()}));
103
- const mergedData = predicates.map(predicate => {
104
- const matchingFilter = filterValues.find(filter => filter.name === predicate.name);
105
- if (matchingFilter.selections.length > 0) {
106
- return {...predicate, ...matchingFilter}
107
- }
108
- }).filter(el => el !== undefined);
109
- return mergedData;
110
- }
111
-
112
- resetFilters(event) {
113
- this.selectTargets.forEach(el => {
114
- el.slim.setSelected([])
115
- })
116
- this.applyFilters(event)
117
- }
118
-
119
- applyFilters(e) {
120
- e.preventDefault();
121
- const searchParams = new URLSearchParams(window.location.search);
122
- const filters = this.#filtersForQuery();
123
- filters.forEach(filter => {
124
- const name = `q[${filter.column_predicate}][]`
125
- const selectedValues = searchParams.getAll(name)
126
- filter.selections.forEach(selection => {
127
- if(selectedValues) {
128
- if(!selectedValues.includes(selection)) {
129
- searchParams.append(name, selection)
130
- }
131
- } else {
132
- searchParams.append(name, selection)
133
- }
134
- })
135
- });
136
- ['input[name="start_date"]', 'input[name="end_date"]'].forEach(selector => {
137
- const el = document.querySelector(selector)
138
- if(el.value.length) {
139
- searchParams.delete("period")
140
- }
141
- searchParams.set(el.name, el.value);
142
- });
143
- Turbo.visit(window.location.pathname.replace(/\/$/, "") + `?${searchParams.toString()}`)
144
- }
145
- }
@@ -1,43 +0,0 @@
1
- import { Controller } from "@hotwired/stimulus"
2
-
3
- export default class extends Controller {
4
- static targets = ["countriesLink", "top_pagesLink", "devicesLink", "top_sourcesLink"]
5
- static classes = ["countries", "top_pages", "devices", "top_sources"]
6
-
7
- changeCountries(event) {
8
- console.log(...this.countriesClasses)
9
- event.currentTarget.classList.add(...this.countriesClasses)
10
- this.countriesLinkTargets.forEach((target) => {
11
- if (target != event.currentTarget) {
12
- target.classList.remove(...this.countriesClasses)
13
- }
14
- })
15
- }
16
-
17
- changeTopSources(event) {
18
- event.currentTarget.classList.add(...this.top_sourcesClasses)
19
- this.top_sourcesLinkTargets.forEach((target) => {
20
- if (target != event.currentTarget) {
21
- target.classList.remove(...this.top_sourcesClasses)
22
- }
23
- })
24
- }
25
-
26
- changeTopPages(event) {
27
- event.currentTarget.classList.add(...this.top_pagesClasses)
28
- this.top_pagesLinkTargets.forEach((target) => {
29
- if (target != event.currentTarget) {
30
- target.classList.remove(...this.top_pagesClasses)
31
- }
32
- })
33
- }
34
-
35
- changeDevices(event) {
36
- event.currentTarget.classList.add(...this.devicesClasses)
37
- this.devicesLinkTargets.forEach((target) => {
38
- if (target != event.currentTarget) {
39
- target.classList.remove(...this.devicesClasses)
40
- }
41
- })
42
- }
43
- }
@@ -1,25 +0,0 @@
1
- import {Controller} from "@hotwired/stimulus"
2
-
3
- export default class extends Controller {
4
- connect() {
5
- this.queryString = new URLSearchParams(window.location.search);
6
- this.baseURL = window.location.pathname.replace(/\/$/, "");
7
- }
8
-
9
- navigate() {
10
- const url = `${this.baseURL}?${this.queryString.toString()}`;
11
- Turbo.visit(url, { action: "replace"})
12
- }
13
-
14
- addQueryParam({ detail: { paramKey, paramValue } }) {
15
- this.queryString.append(paramKey, paramValue)
16
- }
17
-
18
- removeQueryParam({ detail: { paramKey, paramValue } }) {
19
- if (!this.queryString.has(paramKey)) {
20
- paramKey += "[]"
21
- }
22
- this.queryString.delete(paramKey,paramValue)
23
- this.navigate()
24
- }
25
- }
@@ -1,9 +0,0 @@
1
- module AhoyCaptain
2
- class Current < ActiveSupport::CurrentAttributes
3
- attribute :request
4
-
5
- after_reset do
6
- self.request = nil
7
- end
8
- end
9
- end
@@ -1,6 +0,0 @@
1
- module AhoyCaptain
2
- class UrlHelpers
3
- include AhoyCaptain::Engine.routes.url_helpers
4
- include Singleton
5
- end
6
- end