rails_pulse 0.2.5.pre.9 → 0.2.5.pre.11
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 +4 -4
- data/app/assets/stylesheets/rails_pulse/components/badge.css +2 -2
- data/app/assets/stylesheets/rails_pulse/components/button.css +1 -1
- data/app/assets/stylesheets/rails_pulse/components/datepicker.css +0 -2
- data/app/assets/stylesheets/rails_pulse/components/flash.css +1 -1
- data/app/assets/stylesheets/rails_pulse/components/layouts.css +2 -2
- data/app/assets/stylesheets/rails_pulse/components/prose.css +2 -2
- data/app/assets/stylesheets/rails_pulse/components/table.css +2 -2
- data/app/controllers/concerns/chart_table_concern.rb +1 -2
- data/app/controllers/rails_pulse/application_controller.rb +15 -20
- data/app/controllers/rails_pulse/job_runs_controller.rb +1 -1
- data/app/controllers/rails_pulse/jobs_controller.rb +2 -6
- data/app/controllers/rails_pulse/queries_controller.rb +2 -2
- data/app/controllers/rails_pulse/requests_controller.rb +1 -1
- data/app/controllers/rails_pulse/routes_controller.rb +1 -1
- data/app/helpers/rails_pulse/application_helper.rb +2 -44
- data/app/jobs/rails_pulse/backfill_summaries_job.rb +1 -1
- data/app/jobs/rails_pulse/cleanup_job.rb +4 -4
- data/app/jobs/rails_pulse/summary_job.rb +6 -6
- data/app/models/concerns/rails_pulse/taggable.rb +2 -2
- data/app/services/rails_pulse/analysis/explain_plan_analyzer.rb +1 -1
- data/app/services/rails_pulse/summary_service.rb +3 -3
- data/app/views/rails_pulse/components/_table_pagination.html.erb +9 -9
- data/lib/rails_pulse/cleanup_service.rb +10 -10
- data/lib/rails_pulse/configuration.rb +2 -14
- data/lib/rails_pulse/engine.rb +0 -7
- data/lib/rails_pulse/job_run_collector.rb +9 -5
- data/lib/rails_pulse/middleware/asset_server.rb +7 -8
- data/lib/rails_pulse/paginator.rb +23 -0
- data/lib/rails_pulse/subscribers/operation_subscriber.rb +13 -13
- data/lib/rails_pulse/tracker.rb +2 -5
- data/lib/rails_pulse/version.rb +1 -1
- data/lib/rails_pulse.rb +7 -2
- data/public/rails-pulse-assets/rails-pulse.css +1 -1
- data/public/rails-pulse-assets/rails-pulse.css.map +1 -1
- metadata +22 -38
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ce571d5ae696930e4885ac654389e354ef235f0b071046b95bfbd1089b92015d
|
|
4
|
+
data.tar.gz: 1b77c49cc62356cc0faa30b641cde07998ce6252c6ef155386dbd2ac6dbbeea4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7f2c84081607cc389a4098c3bd70c1df2a396aa2c569befff183f13d8dceb2b6e884559df26ac49b7c2cd10b79490e9e6d0366eb582450f85fdb02e938e1f75b
|
|
7
|
+
data.tar.gz: 6d096ff11eca6bd80968118bcb041ffb4dbd13ff58bf1108a69dec4eaefef44e229dba5700039b43cb4f55532fc16f25ed6ca4eb96b7d3e2243f2bd038ca3279
|
|
@@ -61,11 +61,11 @@
|
|
|
61
61
|
.badge--trend rails-pulse-icon { color: var(--badge-color, currentColor); }
|
|
62
62
|
html[data-color-scheme="dark"] .badge--trend rails-pulse-icon {
|
|
63
63
|
/* Lighten icon relative to badge text color for contrast */
|
|
64
|
-
|
|
64
|
+
opacity: 0.8;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
/* Trend amount lightening (dark mode only) */
|
|
68
68
|
.badge--trend .badge__trend-amount { color: var(--badge-color, currentColor); }
|
|
69
69
|
html[data-color-scheme="dark"] .badge--trend .badge__trend-amount {
|
|
70
|
-
|
|
70
|
+
opacity: 0.8;
|
|
71
71
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
align-items: center;
|
|
3
3
|
animation: appear-then-fade 4s 300ms both;
|
|
4
4
|
backdrop-filter: var(--blur-sm) var(--contrast-75);
|
|
5
|
-
background-color: var(--flash-background,
|
|
5
|
+
background-color: var(--flash-background, rgba(0, 0, 0, 0.65));
|
|
6
6
|
border-radius: var(--rounded-full);
|
|
7
7
|
color: var(--flash-color, var(--color-text-reversed));
|
|
8
8
|
column-gap: var(--size-2);
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
|
|
34
34
|
#header {
|
|
35
35
|
align-items: center;
|
|
36
|
-
background-color:
|
|
36
|
+
background-color: rgba(0, 0, 0, 0.05);
|
|
37
37
|
border-block-end-width: var(--border);
|
|
38
38
|
block-size: var(--size-16);
|
|
39
39
|
column-gap: var(--size-4);
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
#sidebar {
|
|
46
|
-
background-color:
|
|
46
|
+
background-color: rgba(0, 0, 0, 0.05);
|
|
47
47
|
border-inline-end-width: var(--sidebar-border-width, 0);
|
|
48
48
|
display: flex;
|
|
49
49
|
flex-direction: column;
|
|
@@ -122,12 +122,12 @@
|
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
del {
|
|
125
|
-
background-color:
|
|
125
|
+
background-color: rgba(220, 38, 38, 0.1);
|
|
126
126
|
color: var(--color-negative);
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
ins {
|
|
130
|
-
background-color:
|
|
130
|
+
background-color: rgba(34, 197, 94, 0.1);
|
|
131
131
|
color: var(--color-positive);
|
|
132
132
|
}
|
|
133
133
|
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
tr:hover {
|
|
20
|
-
background-color:
|
|
20
|
+
background-color: rgba(0, 0, 0, 0.05);
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
th {
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
tfoot {
|
|
48
|
-
background-color:
|
|
48
|
+
background-color: rgba(0, 0, 0, 0.05);
|
|
49
49
|
border-block-start-width: var(--border);
|
|
50
50
|
font-weight: var(--font-medium);
|
|
51
51
|
}
|
|
@@ -51,8 +51,7 @@ module ChartTableConcern
|
|
|
51
51
|
table_results = build_table_results
|
|
52
52
|
handle_pagination
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
@pagy, @table_data = pagy(table_results, **pagy_options(session_pagination_limit))
|
|
54
|
+
@pagination, @table_data = paginate(table_results, limit: session_pagination_limit)
|
|
56
55
|
end
|
|
57
56
|
|
|
58
57
|
def setup_zoom_range_data
|
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
module RailsPulse
|
|
2
2
|
class ApplicationController < ActionController::Base
|
|
3
|
-
# Support both Pagy 8.x (Backend) and Pagy 43+ (Method)
|
|
4
|
-
if defined?(Pagy::Method)
|
|
5
|
-
include Pagy::Method
|
|
6
|
-
else
|
|
7
|
-
include Pagy::Backend
|
|
8
|
-
end
|
|
9
|
-
|
|
10
3
|
before_action :authenticate_rails_pulse_user!
|
|
11
4
|
before_action :set_show_non_tagged_default
|
|
12
5
|
helper_method :session_global_filters, :session_disabled_tags
|
|
@@ -66,6 +59,10 @@ module RailsPulse
|
|
|
66
59
|
|
|
67
60
|
private
|
|
68
61
|
|
|
62
|
+
def logger
|
|
63
|
+
RailsPulse.logger
|
|
64
|
+
end
|
|
65
|
+
|
|
69
66
|
def authenticate_rails_pulse_user!
|
|
70
67
|
return unless RailsPulse.configuration.authentication_enabled
|
|
71
68
|
|
|
@@ -83,15 +80,15 @@ module RailsPulse
|
|
|
83
80
|
if respond_to?(method_name, true)
|
|
84
81
|
send(method_name)
|
|
85
82
|
else
|
|
86
|
-
|
|
83
|
+
logger.error "RailsPulse: Authentication method '#{method_name}' not found"
|
|
87
84
|
render plain: "Authentication configuration error", status: :internal_server_error
|
|
88
85
|
end
|
|
89
86
|
else
|
|
90
|
-
|
|
87
|
+
logger.error "RailsPulse: Invalid authentication method type: #{RailsPulse.configuration.authentication_method.class}"
|
|
91
88
|
render plain: "Authentication configuration error", status: :internal_server_error
|
|
92
89
|
end
|
|
93
90
|
rescue StandardError => e
|
|
94
|
-
|
|
91
|
+
logger.warn "RailsPulse authentication failed: #{e.message}"
|
|
95
92
|
redirect_to RailsPulse.configuration.authentication_redirect_path
|
|
96
93
|
end
|
|
97
94
|
|
|
@@ -102,7 +99,7 @@ module RailsPulse
|
|
|
102
99
|
expected_password = ENV.fetch("RAILS_PULSE_PASSWORD", nil)
|
|
103
100
|
|
|
104
101
|
if expected_password.nil?
|
|
105
|
-
|
|
102
|
+
logger.error "RailsPulse: No authentication method configured and RAILS_PULSE_PASSWORD not set. Access denied."
|
|
106
103
|
false
|
|
107
104
|
else
|
|
108
105
|
username == expected_username && password == expected_password
|
|
@@ -144,7 +141,7 @@ module RailsPulse
|
|
|
144
141
|
|
|
145
142
|
thresholds[threshold.to_sym]
|
|
146
143
|
rescue StandardError => e
|
|
147
|
-
|
|
144
|
+
logger.warn "Failed to get performance threshold: #{e.message}"
|
|
148
145
|
nil
|
|
149
146
|
end
|
|
150
147
|
|
|
@@ -153,14 +150,12 @@ module RailsPulse
|
|
|
153
150
|
session[:show_non_tagged] = true if session[:show_non_tagged].nil?
|
|
154
151
|
end
|
|
155
152
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
{ items: count } # Pagy 8.x
|
|
163
|
-
end
|
|
153
|
+
def paginate(collection, limit:)
|
|
154
|
+
page = [ params[:page].to_i, 1 ].max
|
|
155
|
+
raw = collection.count(:all)
|
|
156
|
+
count = raw.is_a?(Hash) ? raw.size : raw
|
|
157
|
+
records = collection.offset((page - 1) * limit).limit(limit)
|
|
158
|
+
[ RailsPulse::Paginator.new(count: count, page: page, limit: limit), records ]
|
|
164
159
|
end
|
|
165
160
|
end
|
|
166
161
|
end
|
|
@@ -7,7 +7,7 @@ module RailsPulse
|
|
|
7
7
|
|
|
8
8
|
def index
|
|
9
9
|
@ransack_query = @job.runs.ransack(params[:q])
|
|
10
|
-
@
|
|
10
|
+
@pagination, @runs = paginate(@ransack_query.result.order(occurred_at: :desc), limit: session_pagination_limit)
|
|
11
11
|
@table_data = @runs
|
|
12
12
|
end
|
|
13
13
|
|
|
@@ -20,9 +20,7 @@ module RailsPulse
|
|
|
20
20
|
# Apply tag filters from session
|
|
21
21
|
base_query = apply_tag_filters(@ransack_query.result)
|
|
22
22
|
|
|
23
|
-
@
|
|
24
|
-
**pagy_options(session_pagination_limit),
|
|
25
|
-
overflow: :last_page)
|
|
23
|
+
@pagination, @jobs = paginate(base_query.order(runs_count: :desc), limit: session_pagination_limit)
|
|
26
24
|
@table_data = @jobs
|
|
27
25
|
@available_queues = RailsPulse::Job.distinct.pluck(:queue_name).compact.sort
|
|
28
26
|
end
|
|
@@ -56,9 +54,7 @@ module RailsPulse
|
|
|
56
54
|
# Apply tag filters from session
|
|
57
55
|
base_query = apply_tag_filters(@ransack_query.result)
|
|
58
56
|
|
|
59
|
-
@
|
|
60
|
-
**pagy_options(session_pagination_limit),
|
|
61
|
-
overflow: :last_page)
|
|
57
|
+
@pagination, @recent_runs = paginate(base_query, limit: session_pagination_limit)
|
|
62
58
|
@table_data = @recent_runs
|
|
63
59
|
end
|
|
64
60
|
|
|
@@ -32,7 +32,7 @@ module RailsPulse
|
|
|
32
32
|
}
|
|
33
33
|
end
|
|
34
34
|
rescue => e
|
|
35
|
-
|
|
35
|
+
logger.error("[QueryAnalysis] Analysis failed for query #{@query.id}: #{e.message}")
|
|
36
36
|
|
|
37
37
|
respond_to do |format|
|
|
38
38
|
format.turbo_stream {
|
|
@@ -163,7 +163,7 @@ module RailsPulse
|
|
|
163
163
|
table_results = build_table_results
|
|
164
164
|
handle_pagination
|
|
165
165
|
|
|
166
|
-
@
|
|
166
|
+
@pagination, @table_data = paginate(table_results, limit: session_pagination_limit)
|
|
167
167
|
end
|
|
168
168
|
|
|
169
169
|
def handle_pagination
|
|
@@ -123,7 +123,7 @@ module RailsPulse
|
|
|
123
123
|
table_results = build_table_results
|
|
124
124
|
handle_pagination
|
|
125
125
|
|
|
126
|
-
@
|
|
126
|
+
@pagination, @table_data = paginate(table_results, limit: session_pagination_limit)
|
|
127
127
|
end
|
|
128
128
|
|
|
129
129
|
def handle_pagination
|
|
@@ -142,7 +142,7 @@ module RailsPulse
|
|
|
142
142
|
table_results = build_table_results
|
|
143
143
|
handle_pagination
|
|
144
144
|
|
|
145
|
-
@
|
|
145
|
+
@pagination, @table_data = paginate(table_results, limit: session_pagination_limit)
|
|
146
146
|
end
|
|
147
147
|
|
|
148
148
|
def handle_pagination
|
|
@@ -8,10 +8,6 @@ module RailsPulse
|
|
|
8
8
|
include FormHelper
|
|
9
9
|
include TagsHelper
|
|
10
10
|
|
|
11
|
-
# Include Pagy frontend helpers for Pagy 8.x compatibility
|
|
12
|
-
# Pagy 43+ doesn't need this, but it doesn't hurt to include it
|
|
13
|
-
include Pagy::Frontend if defined?(Pagy::Frontend)
|
|
14
|
-
|
|
15
11
|
# Replacement for lucide_icon helper that works with pre-compiled assets
|
|
16
12
|
# Outputs a custom element that will be hydrated by Stimulus
|
|
17
13
|
def rails_pulse_icon(name, options = {})
|
|
@@ -69,47 +65,9 @@ module RailsPulse
|
|
|
69
65
|
end
|
|
70
66
|
|
|
71
67
|
private :normalize_dimension
|
|
72
|
-
# Get items per page from Pagy instance (compatible with Pagy 8.x and 43+)
|
|
73
|
-
def pagy_items(pagy)
|
|
74
|
-
# Pagy 43+ uses options[:items] or has a limit method
|
|
75
|
-
if pagy.respond_to?(:options) && pagy.options.is_a?(Hash)
|
|
76
|
-
pagy.options[:items]
|
|
77
|
-
# Pagy 8.x uses vars[:items]
|
|
78
|
-
elsif pagy.respond_to?(:vars)
|
|
79
|
-
pagy.vars[:items]
|
|
80
|
-
# Fallback
|
|
81
|
-
else
|
|
82
|
-
pagy.limit || 10
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
# Get page URL from Pagy instance (compatible with Pagy 8.x and 43+)
|
|
87
|
-
def pagy_page_url(pagy, page_number)
|
|
88
|
-
# Pagy 43+ has page_url method
|
|
89
|
-
if pagy.respond_to?(:page_url)
|
|
90
|
-
pagy.page_url(page_number)
|
|
91
|
-
# Pagy 8.x requires using pagy_url_for helper
|
|
92
|
-
else
|
|
93
|
-
pagy_url_for(pagy, page_number)
|
|
94
|
-
end
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
# Get previous page number (compatible with Pagy 8.x and 43+)
|
|
98
|
-
def pagy_previous(pagy)
|
|
99
|
-
# Pagy 43+ uses 'previous'
|
|
100
|
-
if pagy.respond_to?(:previous)
|
|
101
|
-
pagy.previous
|
|
102
|
-
# Pagy 8.x uses 'prev'
|
|
103
|
-
elsif pagy.respond_to?(:prev)
|
|
104
|
-
pagy.prev
|
|
105
|
-
else
|
|
106
|
-
nil
|
|
107
|
-
end
|
|
108
|
-
end
|
|
109
68
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
pagy.respond_to?(:next) ? pagy.next : nil
|
|
69
|
+
def page_url(page_number)
|
|
70
|
+
url_for(request.query_parameters.merge(page: page_number))
|
|
113
71
|
end
|
|
114
72
|
|
|
115
73
|
# Make Rails Pulse routes available as rails_pulse in views
|
|
@@ -16,7 +16,7 @@ module RailsPulse
|
|
|
16
16
|
period_end = Summary.calculate_period_end(period_type, end_date)
|
|
17
17
|
|
|
18
18
|
while current <= period_end
|
|
19
|
-
|
|
19
|
+
RailsPulse.logger.info "Backfilling #{period_type} summary for #{current}"
|
|
20
20
|
|
|
21
21
|
SummaryService.new(period_type, current).perform
|
|
22
22
|
|
|
@@ -3,16 +3,16 @@ module RailsPulse
|
|
|
3
3
|
def perform
|
|
4
4
|
return unless RailsPulse.configuration.archiving_enabled
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
RailsPulse.logger.info "[CleanupJob] Starting scheduled cleanup"
|
|
7
7
|
|
|
8
8
|
stats = CleanupService.perform
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
RailsPulse.logger.info "[CleanupJob] Cleanup completed - #{stats[:total_deleted]} records deleted"
|
|
11
11
|
|
|
12
12
|
stats
|
|
13
13
|
rescue => e
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
RailsPulse.logger.error "[CleanupJob] Cleanup failed: #{e.message}"
|
|
15
|
+
RailsPulse.logger.error e.backtrace.join("\n")
|
|
16
16
|
raise
|
|
17
17
|
end
|
|
18
18
|
end
|
|
@@ -21,30 +21,30 @@ module RailsPulse
|
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
23
|
rescue => e
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
RailsPulse.logger.error "Summary job failed: #{e.message}"
|
|
25
|
+
RailsPulse.logger.error e.backtrace.join("\n")
|
|
26
26
|
raise
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
private
|
|
30
30
|
|
|
31
31
|
def process_hourly_summary(hour)
|
|
32
|
-
|
|
32
|
+
RailsPulse.logger.info "Processing hourly summary for #{hour}"
|
|
33
33
|
SummaryService.new("hour", hour).perform
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
def process_daily_summary(date)
|
|
37
|
-
|
|
37
|
+
RailsPulse.logger.info "Processing daily summary for #{date}"
|
|
38
38
|
SummaryService.new("day", date).perform
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
def process_weekly_summary(week_start)
|
|
42
|
-
|
|
42
|
+
RailsPulse.logger.info "Processing weekly summary for week starting #{week_start}"
|
|
43
43
|
SummaryService.new("week", week_start).perform
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
def process_monthly_summary(month_start)
|
|
47
|
-
|
|
47
|
+
RailsPulse.logger.info "Processing monthly summary for month starting #{month_start}"
|
|
48
48
|
SummaryService.new("month", month_start).perform
|
|
49
49
|
end
|
|
50
50
|
end
|
|
@@ -14,11 +14,11 @@ module RailsPulse
|
|
|
14
14
|
# Note: LIKE patterns are sanitized to prevent SQL injection via wildcards
|
|
15
15
|
scope :with_tag, ->(tag) {
|
|
16
16
|
sanitized_tag = sanitize_sql_like(tag.to_s, "\\")
|
|
17
|
-
where("#{table_name}.tags LIKE ?", "
|
|
17
|
+
where("#{table_name}.tags LIKE ?", "%\"#{sanitized_tag}\"%")
|
|
18
18
|
}
|
|
19
19
|
scope :without_tag, ->(tag) {
|
|
20
20
|
sanitized_tag = sanitize_sql_like(tag.to_s, "\\")
|
|
21
|
-
where.not("#{table_name}.tags LIKE ?", "
|
|
21
|
+
where.not("#{table_name}.tags LIKE ?", "%\"#{sanitized_tag}\"%")
|
|
22
22
|
}
|
|
23
23
|
scope :with_tags, -> { where("#{table_name}.tags IS NOT NULL AND #{table_name}.tags != '[]'") }
|
|
24
24
|
end
|
|
@@ -41,7 +41,7 @@ module RailsPulse
|
|
|
41
41
|
end
|
|
42
42
|
end
|
|
43
43
|
rescue => e
|
|
44
|
-
|
|
44
|
+
RailsPulse.logger.warn("[ExplainPlanAnalyzer] EXPLAIN failed for query #{query.id}: #{e.message}")
|
|
45
45
|
nil
|
|
46
46
|
end
|
|
47
47
|
end
|
|
@@ -10,7 +10,7 @@ module RailsPulse
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def perform
|
|
13
|
-
|
|
13
|
+
RailsPulse.logger.info "Starting #{period_type} summary for #{start_time}"
|
|
14
14
|
|
|
15
15
|
ActiveRecord::Base.transaction do
|
|
16
16
|
aggregate_requests # Overall system metrics
|
|
@@ -19,9 +19,9 @@ module RailsPulse
|
|
|
19
19
|
aggregate_jobs # Per-job metrics
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
RailsPulse.logger.info "Completed #{period_type} summary"
|
|
23
23
|
rescue => e
|
|
24
|
-
|
|
24
|
+
RailsPulse.logger.error "Summary failed: #{e.message}"
|
|
25
25
|
raise
|
|
26
26
|
end
|
|
27
27
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<div class="flex items-center mbs-4">
|
|
2
|
-
<div class="text-sm text-subtle show@md">Total of <%= @
|
|
2
|
+
<div class="text-sm text-subtle show@md">Total of <%= @pagination.count %> record(s).</div>
|
|
3
3
|
|
|
4
4
|
<div class="flex items-center mis-auto justify-end" style="column-gap: 1rem">
|
|
5
5
|
<div class="flex items-center gap show@md"
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
data-rails-pulse--pagination-url-value="<%= rails_pulse.pagination_limit_path %>">
|
|
8
8
|
<label for="pagination_limit" class="text-sm font-medium">Rows per page</label>
|
|
9
9
|
<%= select_tag :limit,
|
|
10
|
-
options_for_select([[10, 10], [20, 20], [30, 30], [40, 40], [50, 50]],
|
|
10
|
+
options_for_select([[10, 10], [20, 20], [30, 30], [40, 40], [50, 50]], @pagination.limit),
|
|
11
11
|
{
|
|
12
12
|
id: "pagination_limit",
|
|
13
13
|
class: "input",
|
|
@@ -21,24 +21,24 @@
|
|
|
21
21
|
%>
|
|
22
22
|
</div>
|
|
23
23
|
|
|
24
|
-
<div class="text-sm font-medium"><%= "Page #{@
|
|
24
|
+
<div class="text-sm font-medium"><%= "Page #{@pagination.page} of #{@pagination.last}" %></div>
|
|
25
25
|
|
|
26
26
|
<nav class="flex items-center gap shrink-0" style="--btn-padding: .5rem;" aria-label="Pagination">
|
|
27
|
-
<%
|
|
28
|
-
<% next_page =
|
|
29
|
-
<%= link_to
|
|
27
|
+
<% prev_page = @pagination.previous %>
|
|
28
|
+
<% next_page = @pagination.next %>
|
|
29
|
+
<%= link_to page_url(1), class: "btn", aria: { disabled: prev_page.nil? }.compact_blank do %>
|
|
30
30
|
<%= rails_pulse_icon 'chevrons-left', width: '16', height: '16' %>
|
|
31
31
|
<span class="sr-only">Go to first page</span>
|
|
32
32
|
<% end %>
|
|
33
|
-
<%= link_to
|
|
33
|
+
<%= link_to page_url(prev_page || @pagination.page), class: "btn", aria: { disabled: prev_page.nil? }.compact_blank do %>
|
|
34
34
|
<%= rails_pulse_icon 'chevron-left', width: '16', height: '16' %>
|
|
35
35
|
<span class="sr-only">Go to previous page</span>
|
|
36
36
|
<% end %>
|
|
37
|
-
<%= link_to
|
|
37
|
+
<%= link_to page_url(next_page || @pagination.page), class: "btn", aria: { disabled: next_page.nil? }.compact_blank do %>
|
|
38
38
|
<%= rails_pulse_icon 'chevron-right', width: '16', height: '16' %>
|
|
39
39
|
<span class="sr-only">Go to next page</span>
|
|
40
40
|
<% end %>
|
|
41
|
-
<%= link_to
|
|
41
|
+
<%= link_to page_url(@pagination.last), class: "btn", aria: { disabled: next_page.nil? }.compact_blank do %>
|
|
42
42
|
<%= rails_pulse_icon 'chevrons-right', width: '16', height: '16' %>
|
|
43
43
|
<span class="sr-only">Go to last page</span>
|
|
44
44
|
<% end %>
|
|
@@ -16,7 +16,7 @@ module RailsPulse
|
|
|
16
16
|
def perform
|
|
17
17
|
return unless cleanup_enabled?
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
RailsPulse.logger.info "Starting data cleanup..."
|
|
20
20
|
|
|
21
21
|
perform_time_based_cleanup
|
|
22
22
|
perform_count_based_cleanup
|
|
@@ -35,7 +35,7 @@ module RailsPulse
|
|
|
35
35
|
return unless @config.full_retention_period
|
|
36
36
|
|
|
37
37
|
cutoff_time = @config.full_retention_period.ago
|
|
38
|
-
|
|
38
|
+
RailsPulse.logger.info "Time-based cleanup: removing records older than #{cutoff_time}"
|
|
39
39
|
|
|
40
40
|
# Clean up in order that respects foreign key constraints
|
|
41
41
|
@stats[:time_based][:operations] = cleanup_operations_by_time(cutoff_time)
|
|
@@ -49,7 +49,7 @@ module RailsPulse
|
|
|
49
49
|
def perform_count_based_cleanup
|
|
50
50
|
return unless @config.max_table_records&.any?
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
RailsPulse.logger.info "Count-based cleanup: enforcing table record limits"
|
|
53
53
|
|
|
54
54
|
# Clean up in order that respects foreign key constraints
|
|
55
55
|
@stats[:count_based][:operations] = cleanup_operations_by_count
|
|
@@ -266,18 +266,18 @@ module RailsPulse
|
|
|
266
266
|
total_count_based = @stats[:count_based].values.sum
|
|
267
267
|
@stats[:total_deleted] = total_time_based + total_count_based
|
|
268
268
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
269
|
+
RailsPulse.logger.info "Cleanup completed:"
|
|
270
|
+
RailsPulse.logger.info " Time-based: #{total_time_based} records deleted"
|
|
271
|
+
RailsPulse.logger.info " Count-based: #{total_count_based} records deleted"
|
|
272
|
+
RailsPulse.logger.info " Total: #{@stats[:total_deleted]} records deleted"
|
|
273
273
|
|
|
274
274
|
if @stats[:total_deleted] > 0
|
|
275
|
-
|
|
275
|
+
RailsPulse.logger.info " Breakdown:"
|
|
276
276
|
@stats[:time_based].each do |table, count|
|
|
277
|
-
|
|
277
|
+
RailsPulse.logger.info " #{table} (time): #{count}" if count > 0
|
|
278
278
|
end
|
|
279
279
|
@stats[:count_based].each do |table, count|
|
|
280
|
-
|
|
280
|
+
RailsPulse.logger.info " #{table} (count): #{count}" if count > 0
|
|
281
281
|
end
|
|
282
282
|
end
|
|
283
283
|
end
|
|
@@ -75,8 +75,6 @@ module RailsPulse
|
|
|
75
75
|
|
|
76
76
|
# Tracking mode settings
|
|
77
77
|
@async = true
|
|
78
|
-
|
|
79
|
-
validate_configuration!
|
|
80
78
|
end
|
|
81
79
|
|
|
82
80
|
# Get all routes to ignore, including asset patterns if track_assets is false
|
|
@@ -104,11 +102,6 @@ module RailsPulse
|
|
|
104
102
|
validate_tracking_settings!
|
|
105
103
|
end
|
|
106
104
|
|
|
107
|
-
# Revalidate configuration after changes
|
|
108
|
-
def revalidate!
|
|
109
|
-
validate_configuration!
|
|
110
|
-
end
|
|
111
|
-
|
|
112
105
|
private
|
|
113
106
|
|
|
114
107
|
def validate_thresholds!
|
|
@@ -160,15 +153,10 @@ module RailsPulse
|
|
|
160
153
|
|
|
161
154
|
def validate_authentication_settings!
|
|
162
155
|
if @authentication_enabled && @authentication_method.nil?
|
|
163
|
-
|
|
164
|
-
if Rails.logger
|
|
165
|
-
Rails.logger.warn "RailsPulse: Authentication is enabled but no authentication method is configured. This will deny all access."
|
|
166
|
-
else
|
|
167
|
-
puts "RailsPulse: Authentication is enabled but no authentication method is configured. This will deny all access."
|
|
168
|
-
end
|
|
156
|
+
RailsPulse.logger.warn "Authentication is enabled but no authentication method is configured. This will deny all access."
|
|
169
157
|
end
|
|
170
158
|
|
|
171
|
-
if @authentication_method && ![ Proc, Symbol, String
|
|
159
|
+
if @authentication_method && ![ Proc, Symbol, String ].include?(@authentication_method.class)
|
|
172
160
|
raise ArgumentError, "authentication_method must be a Proc, Symbol, String, or nil, got #{@authentication_method.class}"
|
|
173
161
|
end
|
|
174
162
|
end
|
data/lib/rails_pulse/engine.rb
CHANGED
|
@@ -8,7 +8,6 @@ require "rails_pulse/extensions/active_record"
|
|
|
8
8
|
require "request_store"
|
|
9
9
|
require "rack/static"
|
|
10
10
|
require "ransack"
|
|
11
|
-
require "pagy"
|
|
12
11
|
require "turbo-rails"
|
|
13
12
|
|
|
14
13
|
module RailsPulse
|
|
@@ -107,12 +106,6 @@ module RailsPulse
|
|
|
107
106
|
# Our custom group_by_date extension works regardless of ActiveRecord.default_timezone
|
|
108
107
|
end
|
|
109
108
|
|
|
110
|
-
initializer "rails_pulse.configure_logger", before: :initialize_logger do
|
|
111
|
-
RailsPulse.configure do |config|
|
|
112
|
-
config.logger ||= Rails.logger
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
|
|
116
109
|
# CSP helper methods
|
|
117
110
|
def self.csp_sources
|
|
118
111
|
{
|