matey 0.1.1 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.devcontainer/devcontainer.json +1 -1
- data/CHANGELOG.md +1 -1
- data/COLOR_SCHEMES.md +24 -0
- data/COMPONENTS.md +75 -0
- data/Gemfile +2 -13
- data/Gemfile.lock +148 -143
- data/README.md +53 -100
- data/app/components/matey/active_users_component.html.erb +2 -2
- data/app/components/matey/active_users_component.rb +5 -3
- data/app/components/{application_component.rb → matey/application_component.rb} +3 -1
- data/app/components/matey/bounce_rate_component.html.erb +35 -0
- data/app/components/matey/bounce_rate_component.rb +24 -0
- data/app/components/matey/browser_os_breakdown_component.html.erb +38 -0
- data/app/components/matey/browser_os_breakdown_component.rb +11 -0
- data/app/components/matey/daily_active_users_component.html.erb +15 -0
- data/app/components/matey/daily_active_users_component.rb +11 -0
- data/app/components/matey/new_activity_component.html.erb +2 -2
- data/app/components/matey/new_activity_component.rb +5 -3
- data/app/components/matey/new_users_component.html.erb +2 -2
- data/app/components/matey/new_users_component.rb +5 -3
- data/app/components/matey/top_events_component.html.erb +2 -2
- data/app/components/matey/top_events_component.rb +4 -2
- data/app/components/matey/top_visited_pages_table_component.html.erb +2 -2
- data/app/components/matey/top_visited_pages_table_component.rb +4 -2
- data/app/components/matey/user_engagement_component.html.erb +27 -0
- data/app/components/matey/user_engagement_component.rb +12 -0
- data/app/components/matey/visits_by_day_of_week_component.html.erb +26 -0
- data/app/components/matey/visits_by_day_of_week_component.rb +24 -0
- data/docs/CONTRIBUTING.md +22 -0
- data/images/bounceRateComponent.png +0 -0
- data/images/colorSchemeBlue.png +0 -0
- data/images/colorSchemeNeutral.png +0 -0
- data/lib/helpers.rb +12 -0
- data/lib/matey/version.rb +1 -1
- data/lib/matey.rb +7 -2
- data/matey.gemspec +12 -5
- metadata +54 -12
data/README.md
CHANGED
@@ -4,25 +4,24 @@
|
|
4
4
|
![GitHub issues](https://img.shields.io/github/issues-raw/harled/matey)
|
5
5
|
![GitHub Repo stars](https://img.shields.io/github/stars/harled/matey?logoColor=purple&style=social)
|
6
6
|
|
7
|
-
📈 User Engagement Tracking
|
7
|
+
📈 User Engagement Tracking ViewComponents for [Ahoy](https://github.com/ankane/ahoy) data 🏴☠️
|
8
8
|
|
9
|
-
|
10
|
-
No need to spend time finding what information you need and how to write the queries to set that up.
|
11
|
-
Simply install the gem, input the required data and track how your users are responding to your application!
|
9
|
+
This gem provides a suite of prebuilt [ViewComponents](https://github.com/github/view_component) to observe user engagement in an Ahoy-powered Ruby on Rails application.
|
12
10
|
|
13
|
-
Project Lead: Caitlin Henry
|
14
|
-
[**caitmich**](https://github.com/caitmich) | (*caitlin@harled.ca*)
|
15
|
-
|
16
|
-
This gem assumes that event data is coming from [Ahoy](https://github.com/ankane/ahoy) which is a fantastic library
|
17
|
-
for tracking visits and events. Your project must have Ahoy installed and configured in order to benefit from Matey.
|
18
|
-
|
19
|
-
This gem assumes that you have [Bootstrap 5.1](https://getbootstrap.com/docs/5.1/getting-started/introduction/) loaded in your project. It will work without Bootstrap, however, you will need to provide your own custom styling for the Bootstrap equivalent classes.
|
20
11
|
|
21
12
|
## Installation
|
22
13
|
|
23
|
-
|
14
|
+
`matey` depends on:
|
15
|
+
* [Ahoy](https://github.com/ankane/ahoy) installed, configured and tracking user visit and event data
|
16
|
+
* [Bootstrap 5.1](https://getbootstrap.com/docs/5.1/getting-started/introduction/) available for styling
|
17
|
+
|
18
|
+
Add this line to the Gemfile:
|
24
19
|
|
25
20
|
```ruby
|
21
|
+
# latest from rubygems
|
22
|
+
gem 'matey'
|
23
|
+
|
24
|
+
# or latest from github
|
26
25
|
gem 'matey', github: 'harled/matey', branch: 'main'
|
27
26
|
```
|
28
27
|
|
@@ -30,126 +29,80 @@ And then execute:
|
|
30
29
|
|
31
30
|
$ bundle install
|
32
31
|
|
33
|
-
You will now have the latest version of Matey on your project. Checkout the Usage section to see what components there are and how to use them in your app!
|
34
|
-
|
35
32
|
## Usage
|
36
33
|
|
37
|
-
|
34
|
+
Once `matey` is installed, the next step is to render a component. The data required varies by component.
|
35
|
+
Below is an example of how the `Matey::ActiveUsersComponent` would be
|
36
|
+
called in an application. This component reports on the number of active users within the past two weeks.
|
38
37
|
|
39
|
-
|
38
|
+
Below the component is called with two named parameters which include `events` (ahoy event data) and
|
39
|
+
the `time_window`, which is the period to report on.
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
<%= render Matey::ComponentName.new(events: Ahoy::Event.all, time_window: 1.week) %>
|
41
|
+
```ruby
|
42
|
+
# dashboard.html.erb
|
43
|
+
<%= render Matey::ActiveUsersComponent.new(events: Ahoy::Event.all, time_window: 1.week) %>
|
45
44
|
```
|
46
45
|
|
47
|
-
|
48
|
-
|
49
|
-
The **`time_window`** takes in an amount of time that the component will look calculate the data for and uses this to set the specific date range that the data will be taken from. This is an optional parameter and the default will be a 1 week time window.
|
50
|
-
|
51
|
-
In this example, the component will take the **`Ahoy::Events`** data and show information about the week of data.
|
52
|
-
|
53
|
-
**Note**: The data the component is completely limited by the extent of your [Ahoy](https://github.com/ankane/ahoy) data. Setting up events on each controller action can be seen [here](https://github.com/ankane/ahoy#ruby) and can be done in the base controller so that all other controllers inherit from here and will create Ahoy events.
|
54
|
-
|
55
|
-
Also, if you have a lot of data, you can cut down the data that you are passing through by reducing the time the events have occurred, however the comparison between the current and previous `time_window` will require two time windows worth of data (ie. for data from last week, this will compare to data from 2 weeks ago)
|
56
|
-
|
57
|
-
### New Users Component
|
58
|
-
|
59
|
-
![New Users Component](./images/newUsersComponent.png)
|
60
|
-
|
61
|
-
The New Users component will calculate the number of new users that have been created in the given time window and show you the amount and percentage change from the previous time period. The code should look like this:
|
62
|
-
|
63
|
-
```
|
64
|
-
<%= render Matey::NewUsersComponent.new(users: User.all, time_window: 2.month) %>
|
65
|
-
```
|
46
|
+
It is that simple! There should now be a card displaying the number of active users within the past week.
|
66
47
|
|
67
|
-
|
68
|
-
### Active Users
|
48
|
+
View the available component color schemes [here](COLOR_SCHEMES.md).
|
69
49
|
|
70
|
-
|
50
|
+
View the list of available components [here](COMPONENTS.md).
|
71
51
|
|
72
|
-
The
|
52
|
+
**Note**: The more data, the more interesting the components will be. A common and helpful pattern is to capture events on all controller actions. Details on doing this can be found [here](https://github.com/ankane/ahoy#ruby).
|
73
53
|
|
74
|
-
|
75
|
-
<%= render Matey::ActiveUsersComponent.new(events: Ahoy::Event.all, time_window: 1.month) %>
|
76
|
-
```
|
54
|
+
## Development
|
77
55
|
|
78
|
-
|
56
|
+
After checking out the repository, run the following commands to get started:
|
79
57
|
|
80
|
-
|
58
|
+
```bash
|
59
|
+
# install required packages
|
60
|
+
bin/setup
|
81
61
|
|
82
|
-
|
62
|
+
# install spec/sample packages
|
63
|
+
bundle install --gemfile spec/sample/Gemfile
|
83
64
|
|
84
|
-
|
65
|
+
# run test cases and ensure everything is passing
|
66
|
+
rake spec
|
85
67
|
|
86
|
-
|
87
|
-
|
68
|
+
# an interactive prompt that will allow you to experiment with matey (currently broken!)
|
69
|
+
bin/console
|
88
70
|
```
|
89
71
|
|
90
|
-
|
91
|
-
### Top Visited Landing Pages Component
|
72
|
+
To install `matey` and make it available as a regular rubygem, run the following command: `bundle exec rake install`
|
92
73
|
|
93
|
-
|
74
|
+
### Sample Application
|
94
75
|
|
95
|
-
|
76
|
+
ViewComponents are pretty hard to test without a Ruby on Rails application. This repository includes a sample application that makes it easy to see how a component renders and make quick adjustments.
|
96
77
|
|
97
|
-
|
98
|
-
<%= render(Matey::TopVisitedPagesTableComponent.new(events: Ahoy::Visit.all, time_window: 1.month, limit: 10)) %>
|
99
|
-
```
|
100
|
-
|
101
|
-
### Top Events Component
|
78
|
+
To use the sample application:
|
102
79
|
|
103
|
-
|
80
|
+
1. `cd spec/sample`
|
81
|
+
2. `bundle`
|
82
|
+
3. `bundle exec rails s`
|
83
|
+
4. Open a browser to `localhost:3000`
|
104
84
|
|
105
|
-
|
106
|
-
|
107
|
-
```
|
108
|
-
<%= render(Matey::TopEventsComponent.new(events: Ahoy::Event.all, time_window: 1.month, limit: 10)) %>
|
109
|
-
```
|
110
|
-
|
111
|
-
### Custom Card Component
|
112
|
-
*Coming Soon...*
|
113
|
-
### Custom Table Component
|
114
|
-
*Coming Soon...*
|
115
|
-
## Development
|
85
|
+
## Testing
|
116
86
|
|
117
|
-
|
87
|
+
To run the test cases:
|
118
88
|
|
119
|
-
|
89
|
+
1. `rails db:test:prepare`
|
90
|
+
2. `bundle exec rake`
|
120
91
|
|
121
|
-
|
122
|
-
sample application:
|
92
|
+
## Releasing a New Version
|
123
93
|
|
124
|
-
|
125
|
-
2. bundle
|
126
|
-
3. rails s
|
127
|
-
4. Open a browser to localhost:3000
|
94
|
+
To release a new version:
|
128
95
|
|
129
|
-
|
96
|
+
1. Update the version number in `version.rb`
|
97
|
+
2. Run `bundle exec rake release`
|
130
98
|
|
131
|
-
|
99
|
+
The rake task will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
132
100
|
|
133
|
-
1. rails db:test:prepare
|
134
|
-
2. bundle exec rake
|
135
101
|
|
136
102
|
## Contributing
|
137
103
|
|
138
|
-
|
139
|
-
|
140
|
-
### Contribution Steps:
|
141
|
-
|
142
|
-
Want to help us out? Here are some steps to make sure you are contributing
|
143
|
-
|
144
|
-
1. Find an issue you like, or create a new issue [here](https://github.com/harled/matey/issues)
|
145
|
-
- Please ask for any questions or clarifications in the associated issues or in new issues! 🤔
|
146
|
-
2. Assign yourself to the issue and create a branch , following GitHub Issue's naming scheme. 🛠️
|
147
|
-
- The naming scheme should follow (#issueNumber-issue-name) ie. (#10-create-new-component)
|
148
|
-
3. Get on your local machine and [ensure you have the repo cloned](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository). Checkout the branch you just made with `git checkout branch-name` and pull the latest merged changes from the repo with `git pull origin main` to make sure you have the most up-to-date code from the repo. 👩💻
|
149
|
-
4. Add your amazing changes along with any documentation you feel would be useful. Then commit and push your changes. 🌟
|
150
|
-
5. Go back to the repo on GitHub and create a pull request! Then wait for an admin of the repo to get back to your pull request, address any comments and once you are finally approved, merge your code into Matey! 🎉
|
104
|
+
Please take a look at our [Contribution Guidelines](https://github.com/harled/matey/blob/main/docs/CONTRIBUTING.md).
|
151
105
|
|
152
|
-
If you want some more tips on contributing to GitHub projects, [check out this resource from Data School](https://www.dataschool.io/how-to-contribute-on-github/).
|
153
106
|
|
154
107
|
## License
|
155
108
|
|
@@ -157,4 +110,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
157
110
|
|
158
111
|
## Code of Conduct
|
159
112
|
|
160
|
-
Everyone interacting in the Matey project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/harled/matey/blob/master/CODE_OF_CONDUCT.md).
|
113
|
+
Everyone interacting in the *Matey* project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/harled/matey/blob/master/CODE_OF_CONDUCT.md).
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<div class="card
|
1
|
+
<div class="card <%= @color_scheme %>">
|
2
2
|
<div class="card-body">
|
3
3
|
<div class="row">
|
4
4
|
<div class="col">
|
@@ -6,7 +6,7 @@
|
|
6
6
|
</div>
|
7
7
|
<div class="col-auto">
|
8
8
|
<p class="card-text text-end mb-0">
|
9
|
-
<%= (@change_active_number > 0 ? "+" : "") + @change_active_number.to_s + " / " + @change_active_percent.to_s + "%" %>
|
9
|
+
<%= (@change_active_number > 0 ? "+" : "") + @change_active_number.to_s + " / " + @change_active_percent.to_s + "%" %> compared to last period.
|
10
10
|
</p>
|
11
11
|
</div><!-- .col -->
|
12
12
|
</div><!-- .row -->
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require "ahoy_matey"
|
2
2
|
|
3
|
-
class Matey::ActiveUsersComponent < ApplicationComponent
|
4
|
-
def initialize(events:, time_window: 1.week)
|
3
|
+
class Matey::ActiveUsersComponent < Matey::ApplicationComponent
|
4
|
+
def initialize(events:, time_window: 1.week, color_scheme: "neutral")
|
5
5
|
raise ArgumentError unless events.is_a?(ActiveRecord::Relation)
|
6
6
|
raise ArgumentError unless time_window.is_a?(Integer)
|
7
7
|
|
@@ -9,8 +9,10 @@ class Matey::ActiveUsersComponent < ApplicationComponent
|
|
9
9
|
previous_period = events.where(time: (2 * time_window).ago..time_window.ago).pluck(:user_id).uniq.count
|
10
10
|
|
11
11
|
@change_active_number = @current_period - previous_period
|
12
|
-
@change_active_percent = ((@change_active_number.to_f / (previous_period == 0 ? 1 : previous_period)) * 100).truncate(2)
|
12
|
+
@change_active_percent = ((@change_active_number.to_f / ((previous_period == 0) ? 1 : previous_period)) * 100).truncate(2)
|
13
13
|
|
14
14
|
@time_window = time_window
|
15
|
+
|
16
|
+
@color_scheme = color_scheme(scheme: color_scheme)
|
15
17
|
end
|
16
18
|
end
|
@@ -1,8 +1,10 @@
|
|
1
1
|
require "view_component"
|
2
2
|
require "ahoy_matey"
|
3
|
+
require_relative "../../../lib/helpers"
|
3
4
|
|
4
|
-
class ApplicationComponent < ViewComponent::Base
|
5
|
+
class Matey::ApplicationComponent < ViewComponent::Base
|
5
6
|
include ActiveModel::Validations
|
7
|
+
include ColorSchemeHelper
|
6
8
|
|
7
9
|
def before_render
|
8
10
|
validate!
|
@@ -0,0 +1,35 @@
|
|
1
|
+
<div class="card <%= @color_scheme %>">
|
2
|
+
<div class="card-body">
|
3
|
+
<h5 class = "text-center"><strong>The Bounce Rate of your Application is: <u><%= @percentage_of_visits_that_were_bounced %>%</u></strong></h5>
|
4
|
+
<div>
|
5
|
+
<table class="table table-hover table-borderless table-sm">
|
6
|
+
<tr class="table-dark">
|
7
|
+
<td><strong>Total Number of Bounced Visits:</strong></td>
|
8
|
+
<td class="text-end"><%= @total_number_of_single_event_visits %></td>
|
9
|
+
</tr>
|
10
|
+
<tr class="table-dark">
|
11
|
+
<td><strong>Total Number of Visits:</strong></td>
|
12
|
+
<td class="text-end"><%= @total_number_of_user_visits %></td>
|
13
|
+
</tr>
|
14
|
+
</table>
|
15
|
+
</div>
|
16
|
+
<div>
|
17
|
+
<table class="table table-hover table-borderless table-sm">
|
18
|
+
<thead class="table-dark">
|
19
|
+
<tr>
|
20
|
+
<th>Bounced Page</th>
|
21
|
+
<th class="text-end">Bounce Count</th>
|
22
|
+
</tr>
|
23
|
+
</thead>
|
24
|
+
<tbody class="text-dark border-dark">
|
25
|
+
<% @most_bounced_pages.each do |controller_name_and_action, count| %>
|
26
|
+
<tr>
|
27
|
+
<td><%= controller_name_and_action %></td>
|
28
|
+
<td class="text-end"><%= count %></td>
|
29
|
+
</tr>
|
30
|
+
<% end %>
|
31
|
+
</tbody>
|
32
|
+
</table>
|
33
|
+
</div>
|
34
|
+
</div>
|
35
|
+
</div>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "ahoy_matey"
|
2
|
+
|
3
|
+
class Matey::BounceRateComponent < Matey::ApplicationComponent
|
4
|
+
def initialize(events:, visits:, limit: 5, color_scheme: "neutral")
|
5
|
+
# Determine the total number of user sessions to the website
|
6
|
+
@total_number_of_user_visits = events.pluck(:visit_id).uniq.count
|
7
|
+
|
8
|
+
# First we group by visit_id and scope to visits containing ONLY 1 event
|
9
|
+
@visits_having_only_one_event = events.group(:visit_id).having("count(ahoy_events.id) == 1")
|
10
|
+
# We then count each unique occurence of a visit with 1 event
|
11
|
+
@total_number_of_single_event_visits = @visits_having_only_one_event.uniq.count
|
12
|
+
|
13
|
+
# Determine pages in which the most bounces occur
|
14
|
+
@single_event_visits_landing_page_count = visits.where(id: @visits_having_only_one_event.pluck(:visit_id)).pluck(:landing_page).tally
|
15
|
+
|
16
|
+
# Scope the results to the given limit and sort them in descending order
|
17
|
+
@most_bounced_pages = @single_event_visits_landing_page_count.sort_by { |controller_name_and_action, count| count }.last(limit).reverse
|
18
|
+
|
19
|
+
# Get the percentage as #-One-Page-Visits / Total-#-Of-Visits
|
20
|
+
@percentage_of_visits_that_were_bounced = ((@total_number_of_single_event_visits.to_f / ((@total_number_of_user_visits == 0) ? 1 : @total_number_of_user_visits)) * 100).round(1)
|
21
|
+
|
22
|
+
@color_scheme = color_scheme(scheme: color_scheme)
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
<div class="card <%= @color_scheme %>">
|
2
|
+
<div class="card-body">
|
3
|
+
<div class="row">
|
4
|
+
<h5 class="text-center">Browser and OS Breakdown</h5>
|
5
|
+
<div class="col">
|
6
|
+
<p class="text-center">Since <%= time_ago_in_words(@time_window.ago).titleize %> Ago</p>
|
7
|
+
<table class='table table-hover table-borderless'>
|
8
|
+
<thead class='table-dark'>
|
9
|
+
<th>Browser</th>
|
10
|
+
<th class='text-center'>Visitor Count</th>
|
11
|
+
</thead>
|
12
|
+
<tbody class='text-dark border-dark'>
|
13
|
+
<% @browsers.each do |browser_name, visitor_count| %>
|
14
|
+
<tr>
|
15
|
+
<td><%= browser_name %></td>
|
16
|
+
<td class='text-center'><%= visitor_count %></td>
|
17
|
+
</tr>
|
18
|
+
<% end %>
|
19
|
+
</tbody>
|
20
|
+
</table>
|
21
|
+
<table class='table table-hover table-borderless'>
|
22
|
+
<thead class='table-dark'>
|
23
|
+
<th>OS</th>
|
24
|
+
<th class='text-center'>Visitor Count</th>
|
25
|
+
</thead>
|
26
|
+
<tbody class='text-dark border-dark'>
|
27
|
+
<% @operating_systems.each do |operating_system, visitor_count| %>
|
28
|
+
<tr>
|
29
|
+
<td><%= operating_system %></td>
|
30
|
+
<td class='text-center'><%= visitor_count %></td>
|
31
|
+
</tr>
|
32
|
+
<% end %>
|
33
|
+
</tbody>
|
34
|
+
</table>
|
35
|
+
</div>
|
36
|
+
</div>
|
37
|
+
</div>
|
38
|
+
</div>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class Matey::BrowserOsBreakdownComponent < Matey::ApplicationComponent
|
2
|
+
def initialize(visits:, time_window:, color_scheme: "neutral")
|
3
|
+
visits_in_time_window = visits.where(started_at: time_window.ago..)
|
4
|
+
@visits_in_time_window = visits_in_time_window.count
|
5
|
+
@browsers = visits_in_time_window.group(:browser).count
|
6
|
+
@operating_systems = visits_in_time_window.group(:os).count
|
7
|
+
@time_window = time_window
|
8
|
+
|
9
|
+
@color_scheme = color_scheme(scheme: color_scheme)
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<div class="card <%= @color_scheme %>">
|
2
|
+
<div class="card-body">
|
3
|
+
<div class="col">
|
4
|
+
<div class="col">
|
5
|
+
<h5>Daily Active Users</h5>
|
6
|
+
</div>
|
7
|
+
<div class="col-auto">
|
8
|
+
<p>Since <%= time_ago_in_words(@time_window.ago).titleize %> Ago</p>
|
9
|
+
<p><%= @distinct_user_visits_by_day %></p>
|
10
|
+
<p><%# @distinct_user_visits_by_day2 %></p>
|
11
|
+
<%# @visits.each {|e| e} %>
|
12
|
+
</div>
|
13
|
+
</div>
|
14
|
+
</div>
|
15
|
+
</div>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class Matey::DailyActiveUsersComponent < Matey::ApplicationComponent
|
2
|
+
def initialize(visits:, time_window:, color_scheme: "neutral")
|
3
|
+
@visits = visits
|
4
|
+
@time_window = time_window
|
5
|
+
visits_in_time_window = visits.where(started_at: time_window.ago..)
|
6
|
+
@distinct_user_visits_by_day = visits_in_time_window.order(:day).group(:day).uniq.count
|
7
|
+
# @distinct_user_visits_by_day2 = visits_in_time_window.order(:day).group("DATE(started_at)").map { |k, v| [k, v] }.sort
|
8
|
+
|
9
|
+
@color_scheme = color_scheme(scheme: color_scheme)
|
10
|
+
end
|
11
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<div class="card
|
1
|
+
<div class="card <%= @color_scheme %>">
|
2
2
|
<div class="card-body">
|
3
3
|
<div class="row">
|
4
4
|
<div class="col">
|
@@ -6,7 +6,7 @@
|
|
6
6
|
</div>
|
7
7
|
<div class="col-auto">
|
8
8
|
<p class="card-text text-end mb-0">
|
9
|
-
<%= (@change_active_number > 0 ? "+" : "") + @change_active_number.to_s + " / " + @change_active_percent.to_s + "%" %>
|
9
|
+
<%= (@change_active_number > 0 ? "+" : "") + @change_active_number.to_s + " / " + @change_active_percent.to_s + "%" %> compared to last period.
|
10
10
|
</p>
|
11
11
|
</div><!-- .col -->
|
12
12
|
</div><!-- .row -->
|
@@ -1,5 +1,5 @@
|
|
1
|
-
class Matey::NewActivityComponent < ApplicationComponent
|
2
|
-
def initialize(events:, time_window: 1.week)
|
1
|
+
class Matey::NewActivityComponent < Matey::ApplicationComponent
|
2
|
+
def initialize(events:, time_window: 1.week, color_scheme: "neutral")
|
3
3
|
raise ArgumentError unless events.is_a?(ActiveRecord::Relation)
|
4
4
|
raise ArgumentError unless time_window.is_a?(Integer)
|
5
5
|
|
@@ -7,8 +7,10 @@ class Matey::NewActivityComponent < ApplicationComponent
|
|
7
7
|
previous_period = events.where(time: (2 * time_window).ago..time_window.ago).pluck(:user_id).count
|
8
8
|
|
9
9
|
@change_active_number = @current_period - previous_period
|
10
|
-
@change_active_percent = ((@change_active_number.to_f / (previous_period == 0 ? 1 : previous_period)) * 100).truncate(2)
|
10
|
+
@change_active_percent = ((@change_active_number.to_f / ((previous_period == 0) ? 1 : previous_period)) * 100).truncate(2)
|
11
11
|
|
12
12
|
@time_window = time_window
|
13
|
+
|
14
|
+
@color_scheme = color_scheme(scheme: color_scheme)
|
13
15
|
end
|
14
16
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<div class="card
|
1
|
+
<div class="card <%= @color_scheme %>">
|
2
2
|
<div class="card-body">
|
3
3
|
<div class="row">
|
4
4
|
<div class="col">
|
@@ -6,7 +6,7 @@
|
|
6
6
|
</div>
|
7
7
|
<div class="col-auto">
|
8
8
|
<p class="card-text text-end mb-0">
|
9
|
-
<%= (@change_new_number > 0 ? "+" : "") + @change_new_number.to_s + " / " + @change_new_percent.to_s + "%" %>
|
9
|
+
<%= (@change_new_number > 0 ? "+" : "") + @change_new_number.to_s + " / " + @change_new_percent.to_s + "%" %> compared to last period.
|
10
10
|
</p>
|
11
11
|
</div><!-- .col -->
|
12
12
|
</div><!-- .row -->
|
@@ -1,11 +1,13 @@
|
|
1
|
-
class Matey::NewUsersComponent < ApplicationComponent
|
2
|
-
def initialize(users:, time_window: 1.week)
|
1
|
+
class Matey::NewUsersComponent < Matey::ApplicationComponent
|
2
|
+
def initialize(users:, time_window: 1.week, color_scheme: "neutral")
|
3
3
|
@current_period = users.where(created_at: time_window.ago..Time.current).count
|
4
4
|
previous_period = users.where(created_at: (2 * time_window).ago..time_window.ago).count
|
5
5
|
|
6
6
|
@change_new_number = @current_period - previous_period
|
7
|
-
@change_new_percent = ((@change_new_number.to_f / (previous_period == 0 ? 1 : previous_period)) * 100).truncate(2)
|
7
|
+
@change_new_percent = ((@change_new_number.to_f / ((previous_period == 0) ? 1 : previous_period)) * 100).truncate(2)
|
8
8
|
|
9
9
|
@time_window = time_window
|
10
|
+
|
11
|
+
@color_scheme = color_scheme(scheme: color_scheme)
|
10
12
|
end
|
11
13
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
|
2
2
|
|
3
|
-
<div class="card
|
3
|
+
<div class="card <%= @color_scheme %>">
|
4
4
|
<div class="card-body">
|
5
5
|
<h5>Top Events Since <%= time_ago_in_words(@time_window.ago).titleize %> Ago (<%= @time_window.ago.strftime("%m/%d/%Y") %>)</h5>
|
6
6
|
<div>
|
@@ -11,7 +11,7 @@
|
|
11
11
|
<th>Count</th>
|
12
12
|
</tr>
|
13
13
|
</thead>
|
14
|
-
<tbody class="text-
|
14
|
+
<tbody class="text-dark border-dark">
|
15
15
|
<% @events.each do |action, count| %>
|
16
16
|
<tr>
|
17
17
|
<td><%= action %></td>
|
@@ -1,11 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
class Matey::TopEventsComponent < ApplicationComponent
|
4
|
-
def initialize(events:, time_window: 1.week, limit: 5)
|
3
|
+
class Matey::TopEventsComponent < Matey::ApplicationComponent
|
4
|
+
def initialize(events:, time_window: 1.week, limit: 5, color_scheme: "neutral")
|
5
5
|
raise ArgumentError unless events.is_a?(ActiveRecord::Relation)
|
6
6
|
raise ArgumentError unless time_window.is_a?(Integer)
|
7
7
|
|
8
8
|
@events = events.where(time: time_window.ago..Time.current).limit(limit).order("count(name) DESC").group(:name).count
|
9
9
|
@time_window = time_window
|
10
|
+
|
11
|
+
@color_scheme = color_scheme(scheme: color_scheme)
|
10
12
|
end
|
11
13
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<div class="card
|
1
|
+
<div class="card <%= @color_scheme %>">
|
2
2
|
<div class="card-body">
|
3
3
|
<h5>Top Landing Page Visits Since <%= time_ago_in_words(@time_window.ago).titleize %> Ago (<%= @time_window.ago.strftime("%m/%d/%Y") %>)</h5>
|
4
4
|
<div>
|
@@ -9,7 +9,7 @@
|
|
9
9
|
<th>Count</th>
|
10
10
|
</tr>
|
11
11
|
</thead>
|
12
|
-
<tbody class="text-
|
12
|
+
<tbody class="text-dark border-dark">
|
13
13
|
<% @user_count_by_event.each do |controller_name_and_action, count| %>
|
14
14
|
<tr>
|
15
15
|
<td><%= controller_name_and_action %></td>
|
@@ -1,5 +1,5 @@
|
|
1
|
-
class Matey::TopVisitedPagesTableComponent < ApplicationComponent
|
2
|
-
def initialize(events:, time_window: 1.week, limit: 10)
|
1
|
+
class Matey::TopVisitedPagesTableComponent < Matey::ApplicationComponent
|
2
|
+
def initialize(events:, time_window: 1.week, limit: 10, color_scheme: "neutral")
|
3
3
|
# Group events by controller (:name) and action. Aggregate number of unique user actions
|
4
4
|
@user_count_by_event = events.where(started_at: time_window.ago..).pluck(:landing_page).tally
|
5
5
|
|
@@ -7,5 +7,7 @@ class Matey::TopVisitedPagesTableComponent < ApplicationComponent
|
|
7
7
|
@user_count_by_event = @user_count_by_event.sort_by { |controller_name_and_action, count| count }.last(limit).reverse
|
8
8
|
|
9
9
|
@time_window = time_window
|
10
|
+
|
11
|
+
@color_scheme = color_scheme(scheme: color_scheme)
|
10
12
|
end
|
11
13
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
<div class="card <%= @color_scheme %>">
|
2
|
+
<div class="card-body">
|
3
|
+
<h5>User Activity for <i>user id: <%=@user_id%></i> since <i><%= time_ago_in_words(@time_window.ago).titleize %></i> ago </h5>
|
4
|
+
<div>
|
5
|
+
<table class="table table-hover table-borderless table-sm">
|
6
|
+
<thead class="table-dark">
|
7
|
+
<tr>
|
8
|
+
<th class="text-start">Event</th>
|
9
|
+
<th class="text-end">Count</th>
|
10
|
+
</tr>
|
11
|
+
</thead>
|
12
|
+
<tbody class="text-dark border-dark">
|
13
|
+
<% @count_by_event.each do |event, count| %>
|
14
|
+
<tr>
|
15
|
+
<td><%= event %></td>
|
16
|
+
<td class="text-end"><%= count %></td>
|
17
|
+
</tr>
|
18
|
+
<% end %>
|
19
|
+
<tr class="table-dark">
|
20
|
+
<td><strong>Total:</strong></td>
|
21
|
+
<td class="text-end"><%= @count_by_event.sum {|event, count| count} %></td>
|
22
|
+
</tr>
|
23
|
+
</tbody>
|
24
|
+
</table>
|
25
|
+
</div>
|
26
|
+
</div><!-- .card-body -->
|
27
|
+
</div><!-- .card -->
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require "ahoy_matey"
|
2
|
+
|
3
|
+
class Matey::UserEngagementComponent < Matey::ApplicationComponent
|
4
|
+
def initialize(events:, user_id:, time_window: 1.week, limit: 10, color_scheme: "neutral")
|
5
|
+
@events_for_user = events.where_props(user_id: user_id).where(time: time_window.ago..Time.current).group(:name).count
|
6
|
+
@count_by_event = @events_for_user.sort_by { |event, count| count }.last(limit).reverse
|
7
|
+
@time_window = time_window
|
8
|
+
@user_id = user_id
|
9
|
+
|
10
|
+
@color_scheme = color_scheme(scheme: color_scheme)
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<div class="card <%= @color_scheme %>">
|
2
|
+
<div class="card-header">
|
3
|
+
<h5>Visits By Day of Week since <%= time_ago_in_words(@time_window.ago).titleize %> Ago (<%= @time_window.ago.strftime("%m/%d/%Y") %>) </h5>
|
4
|
+
<% if @exclude_days %>
|
5
|
+
<p>Excluding <%= @exclude_days%>
|
6
|
+
<% end %>
|
7
|
+
</div>
|
8
|
+
<div class="card-body">
|
9
|
+
<table class="table table-hover table-borderless table-sm">
|
10
|
+
<thead class="table-dark">
|
11
|
+
<tr>
|
12
|
+
<th class="text-start">DayOfWeek</th>
|
13
|
+
<th class="text-end">Count</th>
|
14
|
+
</tr>
|
15
|
+
</thead>
|
16
|
+
<tbody class="text-dark border-dark">
|
17
|
+
<% @visits_by_day_of_week.each do |day_of_week, count| %>
|
18
|
+
<tr>
|
19
|
+
<td><%= day_of_week %></td>
|
20
|
+
<td class="text-end"><%= count %></td>
|
21
|
+
</tr>
|
22
|
+
<% end %>
|
23
|
+
</tbody>
|
24
|
+
</table>
|
25
|
+
</div><!-- .card-body -->
|
26
|
+
</div><!-- .card -->
|