trackguard 0.21.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7c250ded678f9970940e87fff8a0d46ff58f8e504a0f63b1abcdd3a2a7955ec7
4
- data.tar.gz: 33d162a61e298288facf7f02424864b8f0588cd7f6cfce437cb866f6c82944e8
3
+ metadata.gz: d17d909f51f058510417e8624ab06dbab2c6aaef25335d4e1b5aee1611452cf6
4
+ data.tar.gz: d39ced082e7e2a16ddf4f08d0681cafe34517cf04811777bc9e99b93623b8f0a
5
5
  SHA512:
6
- metadata.gz: 6fcf99a57cbc641734aa16923597924c5cd795074592e3f63d4f8c747c25f2182cf9b2a170d5fdc2ad4ee6913bed7a56e40c65ba39d2bbfa2b47fb338915db96
7
- data.tar.gz: c7e9dab2b98f2b5c0d790714a9fbffd81fb3e7028559fe6acebdb7f1946eae7108c41aa847fbbb431270a344516714eea35c5aa4b41cf598db29c90e76b0a480
6
+ metadata.gz: 5e942af4746f0198a375fdef13011e65afd2e07b80a4663e1b4a1cb0b6f8c87857818b0f4d3f4e960386221aeb06a889d0c67c89f647ce640473191eb676560c
7
+ data.tar.gz: 3bb04dd3cdeee9f5a304e0160a5ab4a7aa16f1a5b8889f0f4bbb671b4d428d1e8fa10667f3693b943fb807ae4401fe949ed01acd2c0d7f33d075146660adf20f
@@ -15,9 +15,9 @@
15
15
 
16
16
  /* ── Layout ────────────────────────────────────────────────────────── */
17
17
  .tg-container {
18
- max-width: 1100px;
18
+ max-width: var(--tg-container-max-width, 1100px);
19
19
  margin: 0 auto;
20
- padding: 0 1.5rem;
20
+ padding: 0 var(--tg-container-padding, 1.5rem);
21
21
  }
22
22
 
23
23
  /* ── Header ────────────────────────────────────────────────────────── */
@@ -6,5 +6,25 @@ module Trackguard
6
6
  tag.meta(name: "trace-id", content: @trace_id)
7
7
  ], "\n")
8
8
  end
9
+
10
+ def trackguard_nav_links
11
+ [
12
+ { label: "Dashboard", url: dashboard_path, active: request.path == dashboard_path },
13
+ { label: "All Visits", url: visits_path, active: request.path.start_with?(visits_path) }
14
+ ]
15
+ end
16
+
17
+ def trackguard_visits_page_url
18
+ ->(n) { visits_path(page: n) }
19
+ end
20
+
21
+ def trackguard_visit_row_actions(visitor)
22
+ {
23
+ flag: { url: flag_visitor_path, method: :patch, params: { id: visitor.id } },
24
+ unflag: { url: unflag_visitor_path, method: :patch, params: { id: visitor.id } },
25
+ whitelist: { url: whitelist_visitor_path, method: :patch, params: { id: visitor.id } },
26
+ unwhitelist: { url: unwhitelist_visitor_path, method: :patch, params: { id: visitor.id } }
27
+ }
28
+ end
9
29
  end
10
30
  end
@@ -25,12 +25,7 @@
25
25
  </div>
26
26
  </div>
27
27
  </header>
28
- <nav class="tg-nav">
29
- <div class="tg-container">
30
- <a href="<%= dashboard_path %>" class="tg-nav__link<%= ' tg-nav__link--active' if request.path == dashboard_path %>">Dashboard</a>
31
- <a href="<%= visits_path %>" class="tg-nav__link<%= ' tg-nav__link--active' if request.path.start_with?(visits_path) %>">All Visits</a>
32
- </div>
33
- </nav>
28
+ <%= render "trackguard/admin/nav" %>
34
29
  <main class="tg-main">
35
30
  <div class="tg-container">
36
31
  <%= yield %>
@@ -0,0 +1,7 @@
1
+ <nav class="tg-nav">
2
+ <div class="tg-container">
3
+ <% trackguard_nav_links.each do |link| %>
4
+ <a href="<%= link[:url] %>" class="tg-nav__link<%= ' tg-nav__link--active' if link[:active] %>"><%= link[:label] %></a>
5
+ <% end %>
6
+ </div>
7
+ </nav>
@@ -0,0 +1,27 @@
1
+ <div class="tg-panel">
2
+ <h2 class="tg-panel__heading">
3
+ <%= title %><% if local_assigns[:subtitle] %> <span class="tg-panel__sub"><%= subtitle %></span><% end %>
4
+ </h2>
5
+ <% if rows.any? %>
6
+ <table class="tg-table">
7
+ <% if local_assigns[:row_label] %>
8
+ <thead>
9
+ <tr>
10
+ <th class="tg-th"><%= row_label %></th>
11
+ <th class="tg-th tg-th--right">Views</th>
12
+ </tr>
13
+ </thead>
14
+ <% end %>
15
+ <tbody>
16
+ <% rows.each do |label, count| %>
17
+ <tr>
18
+ <td class="tg-td"><%= label %></td>
19
+ <td class="tg-td tg-td--num"><%= count %></td>
20
+ </tr>
21
+ <% end %>
22
+ </tbody>
23
+ </table>
24
+ <% else %>
25
+ <p class="tg-empty"><%= local_assigns.fetch(:empty_message, "No data yet.") %></p>
26
+ <% end %>
27
+ </div>
@@ -31,25 +31,31 @@
31
31
  </summary>
32
32
  <div class="tg-detail">
33
33
  <% if visitor %>
34
+ <% _actions = trackguard_visit_row_actions(visitor) %>
34
35
  <div class="tg-detail__actions">
35
36
  <% if whitelisted %>
36
- <%= button_to "Remove from whitelist", unwhitelist_visitor_path,
37
- params: { id: visitor.id },
38
- method: :patch,
37
+ <%= button_to "Remove from whitelist", _actions[:unwhitelist][:url],
38
+ method: _actions[:unwhitelist][:method],
39
+ params: _actions[:unwhitelist][:params],
39
40
  class: "tg-btn tg-btn--ghost",
40
41
  data: { confirm: "Remove whitelist entry for #{visitor.ip}?" } %>
41
42
  <% else %>
42
- <%= button_to "Whitelist", whitelist_visitor_path,
43
- params: { id: visitor.id },
44
- method: :patch,
43
+ <%= button_to "Whitelist", _actions[:whitelist][:url],
44
+ method: _actions[:whitelist][:method],
45
+ params: _actions[:whitelist][:params],
45
46
  class: "tg-btn tg-btn--whitelist",
46
47
  data: { confirm: "Whitelist #{visitor.ip} for 7 days?" } %>
47
48
  <% end %>
48
49
  <% if flagged %>
49
- <%= button_to "Unflag", unflag_visitor_path, params: { id: visitor.id }, method: :patch, class: "tg-btn tg-btn--ghost" %>
50
+ <%= button_to "Unflag", _actions[:unflag][:url],
51
+ method: _actions[:unflag][:method],
52
+ params: _actions[:unflag][:params],
53
+ class: "tg-btn tg-btn--ghost" %>
50
54
  <% else %>
51
- <%= form_with url: flag_visitor_path, method: :patch, class: "tg-flag-form" do |f| %>
52
- <%= hidden_field_tag :id, visitor.id %>
55
+ <%= form_with url: _actions[:flag][:url], method: _actions[:flag][:method], class: "tg-flag-form" do |f| %>
56
+ <% (_actions[:flag][:params] || {}).each do |k, v| %>
57
+ <%= hidden_field_tag k, v %>
58
+ <% end %>
53
59
  <%= f.submit "Flag", class: "tg-btn tg-btn--danger" %>
54
60
  <%= f.text_field :flag_reason, placeholder: "Flag reason (optional)", class: "tg-input", autocomplete: "off" %>
55
61
  <%= f.text_field :name, placeholder: "Name (optional, auto-detected if blank)", class: "tg-input", autocomplete: "off" %>
@@ -0,0 +1,38 @@
1
+ <%# Summary cards %>
2
+ <div class="tg-stats">
3
+ <div class="tg-stat">
4
+ <p class="tg-stat__label">Today</p>
5
+ <p class="tg-stat__value"><%= @total_today %></p>
6
+ </div>
7
+ <div class="tg-stat">
8
+ <p class="tg-stat__label">This Week</p>
9
+ <p class="tg-stat__value"><%= @total_week %></p>
10
+ </div>
11
+ <div class="tg-stat">
12
+ <p class="tg-stat__label">This Month</p>
13
+ <p class="tg-stat__value"><%= @total_month %></p>
14
+ </div>
15
+ </div>
16
+
17
+ <%# Top pages / referrers / sources grid %>
18
+ <div class="tg-panels">
19
+ <%= render "trackguard/admin/stats_panel", title: "Top Pages", subtitle: "last 30 days", rows: @top_pages, row_label: "Path" %>
20
+ <%= render "trackguard/admin/stats_panel", title: "Top Referrers", subtitle: "last 30 days", rows: @top_referrers, row_label: "Referrer" %>
21
+ <%= render "trackguard/admin/stats_panel", title: "Top Sources", subtitle: "last 30 days", rows: @top_sources, row_label: "Source" %>
22
+ </div>
23
+
24
+ <%# Recent visits %>
25
+ <div class="tg-panel">
26
+ <h2 class="tg-panel__heading">Recent Visits</h2>
27
+ <% if @recent.any? %>
28
+ <table class="tg-table">
29
+ <tbody>
30
+ <% @recent.each do |pv| %>
31
+ <%= render "trackguard/admin/visit_row", pv: pv %>
32
+ <% end %>
33
+ </tbody>
34
+ </table>
35
+ <% else %>
36
+ <p class="tg-empty">No visits recorded yet.</p>
37
+ <% end %>
38
+ </div>
@@ -1,108 +1,3 @@
1
1
  <% content_for :title, "Trackguard" %>
2
2
 
3
- <%# Summary cards %>
4
- <div class="tg-stats">
5
- <div class="tg-stat">
6
- <p class="tg-stat__label">Today</p>
7
- <p class="tg-stat__value"><%= @total_today %></p>
8
- </div>
9
- <div class="tg-stat">
10
- <p class="tg-stat__label">This Week</p>
11
- <p class="tg-stat__value"><%= @total_week %></p>
12
- </div>
13
- <div class="tg-stat">
14
- <p class="tg-stat__label">This Month</p>
15
- <p class="tg-stat__value"><%= @total_month %></p>
16
- </div>
17
- </div>
18
-
19
- <%# Top pages / referrers / sources grid %>
20
- <div class="tg-panels">
21
- <div class="tg-panel">
22
- <h2 class="tg-panel__heading">Top Pages <span class="tg-panel__sub">last 30 days</span></h2>
23
- <% if @top_pages.any? %>
24
- <table class="tg-table">
25
- <thead>
26
- <tr>
27
- <th class="tg-th">Path</th>
28
- <th class="tg-th tg-th--right">Views</th>
29
- </tr>
30
- </thead>
31
- <tbody>
32
- <% @top_pages.each do |path, count| %>
33
- <tr>
34
- <td class="tg-td"><%= path %></td>
35
- <td class="tg-td tg-td--num"><%= count %></td>
36
- </tr>
37
- <% end %>
38
- </tbody>
39
- </table>
40
- <% else %>
41
- <p class="tg-empty">No data yet.</p>
42
- <% end %>
43
- </div>
44
-
45
- <div class="tg-panel">
46
- <h2 class="tg-panel__heading">Top Referrers <span class="tg-panel__sub">last 30 days</span></h2>
47
- <% if @top_referrers.any? %>
48
- <table class="tg-table">
49
- <thead>
50
- <tr>
51
- <th class="tg-th">Referrer</th>
52
- <th class="tg-th tg-th--right">Views</th>
53
- </tr>
54
- </thead>
55
- <tbody>
56
- <% @top_referrers.each do |referer, count| %>
57
- <tr>
58
- <td class="tg-td tg-td--break"><%= referer %></td>
59
- <td class="tg-td tg-td--num"><%= count %></td>
60
- </tr>
61
- <% end %>
62
- </tbody>
63
- </table>
64
- <% else %>
65
- <p class="tg-empty">No referrer data yet.</p>
66
- <% end %>
67
- </div>
68
-
69
- <div class="tg-panel">
70
- <h2 class="tg-panel__heading">Top Sources <span class="tg-panel__sub">last 30 days</span></h2>
71
- <% if @top_sources.any? %>
72
- <table class="tg-table">
73
- <thead>
74
- <tr>
75
- <th class="tg-th">Source</th>
76
- <th class="tg-th tg-th--right">Views</th>
77
- </tr>
78
- </thead>
79
- <tbody>
80
- <% @top_sources.each do |source, count| %>
81
- <tr>
82
- <td class="tg-td"><%= source %></td>
83
- <td class="tg-td tg-td--num"><%= count %></td>
84
- </tr>
85
- <% end %>
86
- </tbody>
87
- </table>
88
- <% else %>
89
- <p class="tg-empty">No source data yet.</p>
90
- <% end %>
91
- </div>
92
- </div>
93
-
94
- <%# Recent visits %>
95
- <div class="tg-panel">
96
- <h2 class="tg-panel__heading">Recent Visits</h2>
97
- <% if @recent.any? %>
98
- <table class="tg-table">
99
- <tbody>
100
- <% @recent.each do |pv| %>
101
- <%= render "trackguard/admin/visit_row", pv: pv %>
102
- <% end %>
103
- </tbody>
104
- </table>
105
- <% else %>
106
- <p class="tg-empty">No visits recorded yet.</p>
107
- <% end %>
108
- </div>
3
+ <%= render "trackguard/admin/dashboards/body" %>
@@ -0,0 +1,15 @@
1
+ <div class="tg-panel">
2
+ <% if @visits.any? %>
3
+ <%= render "trackguard/admin/visits/pagination", page_url: trackguard_visits_page_url %>
4
+ <table class="tg-table">
5
+ <tbody>
6
+ <% @visits.each do |pv| %>
7
+ <%= render "trackguard/admin/visit_row", pv: pv %>
8
+ <% end %>
9
+ </tbody>
10
+ </table>
11
+ <%= render "trackguard/admin/visits/pagination", page_url: trackguard_visits_page_url %>
12
+ <% else %>
13
+ <p class="tg-empty">No visits recorded yet.</p>
14
+ <% end %>
15
+ </div>
@@ -1,9 +1,10 @@
1
+ <% page_url = local_assigns.fetch(:page_url) { ->(n) { visits_path(page: n) } } %>
1
2
  <% if @pages > 1 %>
2
3
  <% window_start = [ @page - 1, 2 ].max %>
3
4
  <% window_end = [ @page + 1, @pages - 1 ].min %>
4
5
  <nav class="tg-pagination" aria-label="Pagination">
5
6
  <% if @page > 1 %>
6
- <a href="<%= visits_path(page: @page - 1) %>" class="tg-pagination__link">← Prev</a>
7
+ <a href="<%= page_url.call(@page - 1) %>" class="tg-pagination__link">← Prev</a>
7
8
  <% else %>
8
9
  <span class="tg-pagination__link tg-pagination__link--disabled">← Prev</span>
9
10
  <% end %>
@@ -12,7 +13,7 @@
12
13
  <% if @page == 1 %>
13
14
  <span class="tg-pagination__link tg-pagination__link--active">1</span>
14
15
  <% else %>
15
- <a href="<%= visits_path(page: 1) %>" class="tg-pagination__link">1</a>
16
+ <a href="<%= page_url.call(1) %>" class="tg-pagination__link">1</a>
16
17
  <% end %>
17
18
 
18
19
  <% if window_start > 2 %>
@@ -24,7 +25,7 @@
24
25
  <% if n == @page %>
25
26
  <span class="tg-pagination__link tg-pagination__link--active"><%= n %></span>
26
27
  <% else %>
27
- <a href="<%= visits_path(page: n) %>" class="tg-pagination__link"><%= n %></a>
28
+ <a href="<%= page_url.call(n) %>" class="tg-pagination__link"><%= n %></a>
28
29
  <% end %>
29
30
  <% end %>
30
31
 
@@ -36,11 +37,11 @@
36
37
  <% if @page == @pages %>
37
38
  <span class="tg-pagination__link tg-pagination__link--active"><%= @pages %></span>
38
39
  <% else %>
39
- <a href="<%= visits_path(page: @pages) %>" class="tg-pagination__link"><%= @pages %></a>
40
+ <a href="<%= page_url.call(@pages) %>" class="tg-pagination__link"><%= @pages %></a>
40
41
  <% end %>
41
42
 
42
43
  <% if @page < @pages %>
43
- <a href="<%= visits_path(page: @page + 1) %>" class="tg-pagination__link">Next →</a>
44
+ <a href="<%= page_url.call(@page + 1) %>" class="tg-pagination__link">Next →</a>
44
45
  <% else %>
45
46
  <span class="tg-pagination__link tg-pagination__link--disabled">Next →</span>
46
47
  <% end %>
@@ -4,19 +4,4 @@
4
4
  <h1 class="tg-page-title">All Visits <span class="tg-page-title__count"><%= @total %></span></h1>
5
5
  </div>
6
6
 
7
- <div class="tg-panel">
8
- <% if @visits.any? %>
9
- <%= render "pagination" %>
10
- <table class="tg-table">
11
- <tbody>
12
- <% @visits.each do |pv| %>
13
- <%= render "trackguard/admin/visit_row", pv: pv %>
14
- <% end %>
15
- </tbody>
16
- </table>
17
-
18
- <%= render "pagination" %>
19
- <% else %>
20
- <p class="tg-empty">No visits recorded yet.</p>
21
- <% end %>
22
- </div>
7
+ <%= render "trackguard/admin/visits/body" %>
@@ -1,3 +1,3 @@
1
1
  module Trackguard
2
- VERSION = "0.21.0".freeze
2
+ VERSION = "0.22.0".freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trackguard
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.21.0
4
+ version: 0.22.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Krzysztof Rygielski
@@ -70,8 +70,12 @@ files:
70
70
  - app/services/trackguard/application_service.rb
71
71
  - app/services/trackguard/page_view_recorder.rb
72
72
  - app/views/layouts/trackguard/admin.html.erb
73
+ - app/views/trackguard/admin/_nav.html.erb
74
+ - app/views/trackguard/admin/_stats_panel.html.erb
73
75
  - app/views/trackguard/admin/_visit_row.html.erb
76
+ - app/views/trackguard/admin/dashboards/_body.html.erb
74
77
  - app/views/trackguard/admin/dashboards/show.html.erb
78
+ - app/views/trackguard/admin/visits/_body.html.erb
75
79
  - app/views/trackguard/admin/visits/_pagination.html.erb
76
80
  - app/views/trackguard/admin/visits/index.html.erb
77
81
  - config/importmap.rb