rails_pulse 0.3.3 → 0.4.0.pre.2

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.
Files changed (169) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +299 -0
  3. data/README.md +44 -3
  4. data/app/assets/stylesheets/rails_pulse/application.css +21 -32
  5. data/app/assets/stylesheets/rails_pulse/components/backtrace.css +238 -0
  6. data/app/assets/stylesheets/rails_pulse/components/badge.css +32 -0
  7. data/app/assets/stylesheets/rails_pulse/components/button.css +2 -36
  8. data/app/assets/stylesheets/rails_pulse/components/card.css +8 -11
  9. data/app/assets/stylesheets/rails_pulse/components/chart.css +16 -3
  10. data/app/assets/stylesheets/rails_pulse/components/csp_safe_positioning.css +5 -39
  11. data/app/assets/stylesheets/rails_pulse/components/dashboard.css +0 -52
  12. data/app/assets/stylesheets/rails_pulse/components/deployments.css +39 -0
  13. data/app/assets/stylesheets/rails_pulse/components/dialog.css +0 -5
  14. data/app/assets/stylesheets/rails_pulse/components/input.css +0 -14
  15. data/app/assets/stylesheets/rails_pulse/components/layouts.css +0 -20
  16. data/app/assets/stylesheets/rails_pulse/components/menu.css +0 -16
  17. data/app/assets/stylesheets/rails_pulse/components/sidebar_menu.css +0 -16
  18. data/app/assets/stylesheets/rails_pulse/components/storage.css +187 -0
  19. data/app/assets/stylesheets/rails_pulse/components/tags.css +0 -14
  20. data/app/assets/stylesheets/rails_pulse/components/time_range_selector.css +5 -5
  21. data/app/assets/stylesheets/rails_pulse/components/utilities.css +0 -17
  22. data/app/controllers/concerns/chart_table_concern.rb +15 -3
  23. data/app/controllers/concerns/ransack_params_concern.rb +18 -0
  24. data/app/controllers/concerns/response_range_concern.rb +1 -1
  25. data/app/controllers/concerns/time_range_concern.rb +28 -14
  26. data/app/controllers/rails_pulse/application_controller.rb +104 -31
  27. data/app/controllers/rails_pulse/dashboard_controller.rb +9 -0
  28. data/app/controllers/rails_pulse/deployments_controller.rb +26 -5
  29. data/app/controllers/rails_pulse/exception_occurrences_controller.rb +19 -0
  30. data/app/controllers/rails_pulse/exceptions_controller.rb +119 -0
  31. data/app/controllers/rails_pulse/job_runs_controller.rb +1 -1
  32. data/app/controllers/rails_pulse/requests_controller.rb +1 -1
  33. data/app/controllers/rails_pulse/routes_controller.rb +7 -1
  34. data/app/controllers/rails_pulse/storage_controller.rb +7 -0
  35. data/app/controllers/rails_pulse/tags_controller.rb +2 -2
  36. data/app/helpers/rails_pulse/application_helper.rb +1 -0
  37. data/app/helpers/rails_pulse/backtrace_helper.rb +85 -0
  38. data/app/helpers/rails_pulse/breadcrumbs_helper.rb +4 -1
  39. data/app/helpers/rails_pulse/chart_helper.rb +0 -3
  40. data/app/helpers/rails_pulse/route_helper.rb +8 -16
  41. data/app/javascript/rails_pulse/application.js +29 -8
  42. data/app/javascript/rails_pulse/controllers/clipboard_controller.js +58 -0
  43. data/app/javascript/rails_pulse/controllers/index_controller.js +16 -10
  44. data/app/javascript/rails_pulse/controllers/pagination_controller.js +6 -2
  45. data/app/javascript/rails_pulse/controllers/popover_controller.js +4 -0
  46. data/app/models/concerns/rails_pulse/taggable.rb +11 -6
  47. data/app/models/rails_pulse/cards/base.rb +53 -0
  48. data/app/models/rails_pulse/dashboard/health_summary.rb +52 -0
  49. data/app/models/rails_pulse/dashboard/needs_attention.rb +73 -1
  50. data/app/models/rails_pulse/dashboard/storage_status.rb +490 -0
  51. data/app/models/rails_pulse/deployment.rb +47 -1
  52. data/app/models/rails_pulse/exception_group.rb +37 -0
  53. data/app/models/rails_pulse/exception_occurrence.rb +27 -0
  54. data/app/models/rails_pulse/exceptions/cards/exception_rate.rb +116 -0
  55. data/app/models/rails_pulse/exceptions/cards/open_groups.rb +49 -0
  56. data/app/models/rails_pulse/exceptions/cards/total_occurrences.rb +62 -0
  57. data/app/models/rails_pulse/exceptions/charts/occurrence_volume.rb +56 -0
  58. data/app/models/rails_pulse/exceptions/raw_data.rb +216 -0
  59. data/app/models/rails_pulse/jobs/cards/p95_duration.rb +8 -2
  60. data/app/models/rails_pulse/operation.rb +13 -4
  61. data/app/models/rails_pulse/queries/cards/percentile_query_times.rb +8 -3
  62. data/app/models/rails_pulse/request.rb +5 -1
  63. data/app/models/rails_pulse/route.rb +71 -21
  64. data/app/models/rails_pulse/routes/cards/error_rates.rb +6 -3
  65. data/app/models/rails_pulse/routes/cards/percentile_response_times.rb +8 -3
  66. data/app/models/rails_pulse/routes/tables/index.rb +8 -6
  67. data/app/models/rails_pulse/summary.rb +21 -10
  68. data/app/models/rails_pulse/tables/base.rb +4 -2
  69. data/app/services/rails_pulse/analysis/explain_plan_analyzer.rb +47 -12
  70. data/app/services/rails_pulse/exception_capture_service.rb +228 -0
  71. data/app/services/rails_pulse/exception_message_sanitizer.rb +152 -0
  72. data/app/services/rails_pulse/operations/change_point.rb +144 -0
  73. data/app/services/rails_pulse/operations/compare.rb +92 -0
  74. data/app/services/rails_pulse/operations/comparison.rb +126 -0
  75. data/app/services/rails_pulse/operations/metric.rb +63 -0
  76. data/app/services/rails_pulse/operations/series.rb +84 -0
  77. data/app/services/rails_pulse/operations/subject.rb +77 -0
  78. data/app/services/rails_pulse/route_controller_action_backfiller.rb +110 -0
  79. data/app/services/rails_pulse/route_merger.rb +99 -0
  80. data/app/services/rails_pulse/route_migrator.rb +139 -0
  81. data/app/services/rails_pulse/route_path_normalizer.rb +79 -0
  82. data/app/services/rails_pulse/route_recognizer.rb +47 -0
  83. data/app/services/rails_pulse/summary_service.rb +45 -0
  84. data/app/services/rails_pulse/tag_filter_service.rb +5 -3
  85. data/app/views/layouts/rails_pulse/_menu_items.html.erb +7 -0
  86. data/app/views/layouts/rails_pulse/_onboarding_banner.html.erb +8 -0
  87. data/app/views/layouts/rails_pulse/_setup_screen.html.erb +5 -5
  88. data/app/views/layouts/rails_pulse/application.html.erb +4 -4
  89. data/app/views/rails_pulse/components/_empty_state.html.erb +1 -1
  90. data/app/views/rails_pulse/components/_panel.html.erb +16 -6
  91. data/app/views/rails_pulse/components/_raw_data.html.erb +34 -0
  92. data/app/views/rails_pulse/dashboard/_chart_panel.html.erb +6 -8
  93. data/app/views/rails_pulse/dashboard/_deployments_panel.html.erb +64 -0
  94. data/app/views/rails_pulse/dashboard/_health_badge.html.erb +21 -10
  95. data/app/views/rails_pulse/dashboard/_storage_panel.html.erb +67 -0
  96. data/app/views/rails_pulse/dashboard/index.html.erb +22 -1
  97. data/app/views/rails_pulse/deployments/_status_badge.html.erb +5 -0
  98. data/app/views/rails_pulse/deployments/_table.html.erb +29 -0
  99. data/app/views/rails_pulse/deployments/index.html.erb +15 -0
  100. data/app/views/rails_pulse/deployments/show.html.erb +62 -0
  101. data/app/views/rails_pulse/exception_occurrences/show.html.erb +45 -0
  102. data/app/views/rails_pulse/exceptions/_backtrace.html.erb +33 -0
  103. data/app/views/rails_pulse/exceptions/_metric_cards.html.erb +6 -0
  104. data/app/views/rails_pulse/exceptions/_occurrences_table.html.erb +23 -0
  105. data/app/views/rails_pulse/exceptions/_status_badge.html.erb +6 -0
  106. data/app/views/rails_pulse/exceptions/_table.html.erb +33 -0
  107. data/app/views/rails_pulse/exceptions/index.html.erb +66 -0
  108. data/app/views/rails_pulse/exceptions/show.html.erb +52 -0
  109. data/app/views/rails_pulse/queries/_raw_data.html.erb +1 -23
  110. data/app/views/rails_pulse/requests/_table.html.erb +1 -1
  111. data/app/views/rails_pulse/routes/_requests_table.html.erb +5 -0
  112. data/app/views/rails_pulse/routes/_table.html.erb +22 -8
  113. data/app/views/rails_pulse/routes/index.html.erb +5 -1
  114. data/app/views/rails_pulse/routes/show.html.erb +5 -0
  115. data/app/views/rails_pulse/storage/show.html.erb +123 -0
  116. data/config/routes.rb +13 -4
  117. data/db/rails_pulse_migrate/20260506000001_create_rails_pulse_exceptions.rb +50 -0
  118. data/db/rails_pulse_migrate/20260507000001_add_actual_query_to_operations.rb +10 -5
  119. data/db/rails_pulse_migrate/20260610000001_add_controller_action_to_rails_pulse_routes.rb +8 -0
  120. data/db/rails_pulse_migrate/20260610000002_change_rails_pulse_routes_to_multi_verb_model.rb +185 -0
  121. data/db/rails_pulse_migrate/20260610000003_add_null_action_unique_index_to_routes.rb +32 -0
  122. data/db/rails_pulse_migrate/20260823000001_add_location_to_exception_groups.rb +12 -0
  123. data/db/rails_pulse_schema.rb +54 -6
  124. data/lib/generators/rails_pulse/base_methods.rb +2 -0
  125. data/lib/generators/rails_pulse/install_generator.rb +5 -0
  126. data/lib/generators/rails_pulse/schema_parser.rb +22 -2
  127. data/lib/generators/rails_pulse/templates/db/rails_pulse_schema.rb +54 -6
  128. data/lib/generators/rails_pulse/templates/migrations/upgrade_rails_pulse_tables.rb +1 -1
  129. data/lib/generators/rails_pulse/templates/rails_pulse.rb +157 -16
  130. data/lib/generators/rails_pulse/upgrade_generator.rb +166 -38
  131. data/lib/rails_pulse/cleanup_service.rb +110 -15
  132. data/lib/rails_pulse/configuration.rb +125 -6
  133. data/lib/rails_pulse/engine.rb +32 -17
  134. data/lib/rails_pulse/installers/config_updater.rb +202 -0
  135. data/lib/rails_pulse/job_run_collector.rb +43 -16
  136. data/lib/rails_pulse/middleware/asset_server.rb +11 -0
  137. data/lib/rails_pulse/middleware/request_collector.rb +9 -4
  138. data/lib/rails_pulse/packaged_assets.rb +147 -0
  139. data/lib/rails_pulse/route_indexes.rb +66 -0
  140. data/lib/rails_pulse/subscribers/exception_subscriber.rb +36 -0
  141. data/lib/rails_pulse/tracker.rb +29 -10
  142. data/lib/rails_pulse/version.rb +1 -1
  143. data/lib/rails_pulse.rb +1 -0
  144. data/lib/rails_pulse_server.ru +16 -47
  145. data/lib/tasks/rails_pulse.rake +83 -4
  146. data/lib/tasks/rails_pulse_assets.rake +15 -0
  147. data/lib/tasks/rails_pulse_tasks.rake +29 -0
  148. data/public/rails-pulse-assets/rails-pulse-icons.js +6 -2
  149. data/public/rails-pulse-assets/rails-pulse.css +1 -1
  150. data/public/rails-pulse-assets/rails-pulse.js +18 -117
  151. metadata +78 -37
  152. data/Rakefile +0 -554
  153. data/app/javascript/rails_pulse/controllers/form_controller.js +0 -39
  154. data/app/javascript/rails_pulse/controllers/period_selector_controller.js +0 -19
  155. data/app/javascript/rails_pulse/controllers/timezone_controller.js +0 -89
  156. data/app/javascript/rails_pulse/theme.js +0 -416
  157. data/config/brakeman.ignore +0 -190
  158. data/config/brakeman.yml +0 -68
  159. data/config/initializers/rails_pulse.rb +0 -287
  160. data/public/rails-pulse-assets/csp-test.js +0 -120
  161. data/public/rails-pulse-assets/rails-pulse-icons.js.map +0 -13
  162. data/public/rails-pulse-assets/rails-pulse.css.map +0 -1
  163. data/public/rails-pulse-assets/rails-pulse.js.map +0 -7
  164. data/vendor/assets/javascripts/rails-pulse-icons.js +0 -93
  165. data/vendor/assets/javascripts/rails-pulse-icons.js.map +0 -13
  166. data/vendor/assets/javascripts/rails-pulse.js +0 -157
  167. data/vendor/assets/javascripts/rails-pulse.js.map +0 -7
  168. data/vendor/assets/stylesheets/rails-pulse.css +0 -1
  169. data/vendor/assets/stylesheets/rails-pulse.css.map +0 -1
@@ -1,287 +0,0 @@
1
- RailsPulse.configure do |config|
2
- # ====================================================================================================
3
- # GLOBAL CONFIGURATION
4
- # ====================================================================================================
5
-
6
- # Enable or disable Rails Pulse
7
- config.enabled = true
8
-
9
- # ====================================================================================================
10
- # THRESHOLDS
11
- # ====================================================================================================
12
- # These thresholds are used to determine if a route, request, or query is slow, very slow, or critical.
13
- # Values are in milliseconds (ms). Adjust these based on your application's performance requirements.
14
-
15
- # Thresholds for an individual route
16
- config.route_thresholds = {
17
- slow: 500,
18
- very_slow: 1500,
19
- critical: 3000
20
- }
21
-
22
- # Thresholds for an individual request
23
- config.request_thresholds = {
24
- slow: 700,
25
- very_slow: 2000,
26
- critical: 4000
27
- }
28
-
29
- # Thresholds for an individual database query
30
- config.query_thresholds = {
31
- slow: 100,
32
- very_slow: 500,
33
- critical: 1000
34
- }
35
-
36
- # ====================================================================================================
37
- # SERVICE LEVEL OBJECTIVES (SLO)
38
- # ====================================================================================================
39
- # Define Service Level Objectives to visualize performance targets on the dashboard.
40
- # These SLOs appear as dashed threshold lines on the performance charts, color-matched
41
- # to their percentile series (green for P95, blue for P99).
42
- #
43
- # SLO Configuration:
44
- # :percentile - Must be 95 or 99 (binds to the matching chart series)
45
- # :threshold - Maximum acceptable response time in milliseconds
46
-
47
- # SLO for HTTP request response times (shown on Response Time Percentiles chart)
48
- # config.service_level_objectives = [
49
- # { percentile: 95, threshold: 200 },
50
- # { percentile: 99, threshold: 500 }
51
- # ]
52
-
53
- # SLO for database query execution times (shown on Query Performance chart)
54
- # Query SLOs should typically be 5-10x stricter than request SLOs
55
- # config.query_service_level_objectives = [
56
- # { percentile: 95, threshold: 50 },
57
- # { percentile: 99, threshold: 100 }
58
- # ]
59
-
60
- # ====================================================================================================
61
- # FILTERING
62
- # ====================================================================================================
63
-
64
- # Asset Tracking Configuration
65
- # By default, Rails Pulse ignores asset requests (images, CSS, JS files) to focus on application performance.
66
- # Set track_assets to true if you want to monitor asset delivery performance.
67
- config.track_assets = false
68
-
69
- # Custom asset patterns to ignore (in addition to the built-in defaults)
70
- # Only applies when track_assets is false. Add patterns for app-specific asset paths.
71
- config.custom_asset_patterns = [
72
- # Example: ignore specific asset directories
73
- # %r{^/uploads/},
74
- # %r{^/media/},
75
- # "/special-assets/"
76
- ]
77
-
78
- # Rails Pulse Mount Path (optional)
79
- # If Rails Pulse is mounted at a custom path, specify it here to prevent
80
- # Rails Pulse from tracking its own requests. Leave as nil for default '/rails_pulse'.
81
- # Examples:
82
- # config.mount_path = "/admin/monitoring"
83
- config.mount_path = nil
84
-
85
- # Manual route filtering
86
- # Specify additional routes, requests, or queries to ignore from performance tracking.
87
- # Each array can include strings (exact matches) or regular expressions.
88
- #
89
- # Examples:
90
- # config.ignored_routes = ["/health_check", %r{^/admin}]
91
- # config.ignored_requests = ["GET /status", %r{POST /api/v1/.*}]
92
- # config.ignored_queries = ["SELECT 1", %r{FROM \"schema_migrations\"}]
93
-
94
- config.ignored_routes = []
95
- config.ignored_requests = []
96
- config.ignored_queries = []
97
-
98
- # ====================================================================================================
99
- # TAGGING
100
- # ====================================================================================================
101
- # Define custom tags for categorizing routes, requests, and queries.
102
- # You can add any custom tags you want for filtering and organization.
103
- #
104
- # Tag names should be in present tense and describe the current state or category.
105
- # Examples of good tag names:
106
- # - "critical" (for high-priority endpoints)
107
- # - "experimental" (for routes under development)
108
- # - "deprecated" (for routes being phased out)
109
- # - "external" (for third-party API calls)
110
- # - "background" (for async job-related operations)
111
- # - "admin" (for administrative routes)
112
- # - "public" (for public-facing routes)
113
- #
114
- # Example configuration:
115
- # config.tags = ["ignored", "critical", "experimental", "deprecated", "external", "admin"]
116
-
117
- config.tags = [ "ignored", "critical", "experimental" ]
118
-
119
- # ====================================================================================================
120
- # BACKGROUND JOBS
121
- # ====================================================================================================
122
- # Configure background job monitoring and tracking.
123
- # When enabled, Rails Pulse will track job executions, durations, failures, and retries.
124
- # Supports ActiveJob, Sidekiq, and Delayed Job.
125
-
126
- # Enable or disable background job tracking
127
- config.track_jobs = false
128
-
129
- # Thresholds for job execution times (in milliseconds)
130
- config.job_thresholds = {
131
- slow: 5_000, # 5 seconds
132
- very_slow: 30_000, # 30 seconds
133
- critical: 60_000 # 1 minute
134
- }
135
-
136
- # Job classes to ignore from tracking (by class name)
137
- # Examples:
138
- # config.ignored_jobs = ["ActionMailer::MailDeliveryJob", "MyApp::HealthCheckJob"]
139
- config.ignored_jobs = []
140
-
141
- # Queue names to ignore from tracking
142
- # Examples:
143
- # config.ignored_queues = ["low_priority", "mailers"]
144
- config.ignored_queues = []
145
-
146
- # Capture job arguments for debugging (may contain sensitive data)
147
- # Set to false in production to avoid storing potentially sensitive information
148
- config.capture_job_arguments = true
149
-
150
- # ====================================================================================================
151
- # DATABASE CONFIGURATION
152
- # ====================================================================================================
153
- # Configure Rails Pulse to use a separate database for performance monitoring data.
154
- # This is optional but recommended for production applications to isolate performance
155
- # data from your main application database.
156
- #
157
- # Uncomment and configure one of the following patterns:
158
-
159
- # Option 1: Separate single database for Rails Pulse
160
- # config.connects_to = {
161
- # database: { writing: :rails_pulse, reading: :rails_pulse }
162
- # }
163
-
164
- # Option 2: Primary/replica configuration for Rails Pulse
165
- # config.connects_to = {
166
- # database: { writing: :rails_pulse_primary, reading: :rails_pulse_replica }
167
- # }
168
-
169
- # Don't forget to add the database configuration to config/database.yml:
170
- #
171
- # production:
172
- # # ... your main database config ...
173
- # rails_pulse:
174
- # adapter: postgresql # or mysql2, sqlite3
175
- # database: myapp_rails_pulse_production
176
- # username: rails_pulse_user
177
- # password: <%= Rails.application.credentials.dig(:rails_pulse, :database_password) %>
178
- # host: localhost
179
- # pool: 5
180
-
181
- # ====================================================================================================
182
- # AUTHENTICATION
183
- # ====================================================================================================
184
- # Configure authentication to secure access to the Rails Pulse dashboard.
185
- # Authentication is ENABLED BY DEFAULT in production environments for security.
186
- #
187
- # If no authentication method is configured, Rails Pulse will use HTTP Basic Auth
188
- # with credentials from RAILS_PULSE_USERNAME (default: 'admin') and RAILS_PULSE_PASSWORD
189
- # environment variables. Set RAILS_PULSE_PASSWORD to enable this fallback.
190
- #
191
- # Uncomment and configure one of the following patterns based on your authentication system:
192
-
193
- # Enable/disable authentication (enabled by default in production)
194
- # config.authentication_enabled = Rails.env.production?
195
-
196
- # Where to redirect unauthorized users
197
- # config.authentication_redirect_path = "/"
198
-
199
- # Custom authentication method - choose one of the examples below:
200
-
201
- # Example 1: Devise with admin role check
202
- # config.authentication_method = proc {
203
- # unless user_signed_in? && current_user.admin?
204
- # redirect_to main_app.root_path, alert: "Access denied"
205
- # end
206
- # }
207
-
208
- # Example 2: Custom session-based authentication
209
- # config.authentication_method = proc {
210
- # unless session[:user_id] && User.find_by(id: session[:user_id])&.admin?
211
- # redirect_to main_app.login_path, alert: "Please log in as an admin"
212
- # end
213
- # }
214
-
215
- # Example 3: Warden authentication
216
- # config.authentication_method = proc {
217
- # warden.authenticate!(:scope => :admin)
218
- # }
219
-
220
- # Example 4: Basic HTTP authentication
221
- # config.authentication_method = proc {
222
- # authenticate_or_request_with_http_basic do |username, password|
223
- # username == ENV['RAILS_PULSE_USERNAME'] && password == ENV['RAILS_PULSE_PASSWORD']
224
- # end
225
- # }
226
-
227
- # Example 5: Custom authorization check
228
- # config.authentication_method = proc {
229
- # current_user = User.find_by(id: session[:user_id])
230
- # unless current_user&.can_access_rails_pulse?
231
- # render plain: "Forbidden", status: :forbidden
232
- # end
233
- # }
234
-
235
- # ====================================================================================================
236
- # DEPLOYMENT TRACKING
237
- # ====================================================================================================
238
- # Record deployments to display vertical marker lines on performance charts, making it easy
239
- # to correlate performance changes with specific releases.
240
- #
241
- # API token for the POST /rails_pulse/deployments endpoint.
242
- # When set, requests must include an `X-Rails-Pulse-Token` header matching this value.
243
- # When nil, the endpoint falls back to the standard dashboard authentication.
244
- #
245
- # Set this in your CI/CD pipeline and store the value in credentials or an environment variable:
246
- # config.deployment_api_token = Rails.application.credentials.dig(:rails_pulse, :deployment_api_token)
247
- # config.deployment_api_token = ENV["RAILS_PULSE_DEPLOYMENT_TOKEN"]
248
- #
249
- # Record a deployment from your CI/CD pipeline:
250
- # curl -X POST https://yourapp.com/rails_pulse/deployments \
251
- # -H "X-Rails-Pulse-Token: $RAILS_PULSE_DEPLOYMENT_TOKEN" \
252
- # -H "Content-Type: application/json" \
253
- # -d '{"deployment": {"revision": "abc1234", "metadata": {"environment": "production"}}}'
254
- #
255
- # Or use the rake task for simple shell-based deploys:
256
- # rake rails_pulse:record_deployment[abc1234]
257
-
258
- # config.deployment_api_token = ENV["RAILS_PULSE_DEPLOYMENT_TOKEN"]
259
-
260
- # ====================================================================================================
261
- # DATA CLEANUP
262
- # ====================================================================================================
263
- # Configure automatic cleanup of old performance data to manage database size.
264
- # Rails Pulse provides two cleanup mechanisms that work together:
265
- #
266
- # 1. Time-based cleanup: Delete records older than the retention period
267
- # 2. Count-based cleanup: Keep only the specified number of records per table
268
- #
269
- # Cleanup order respects foreign key constraints:
270
- # operations → requests → queries/routes
271
-
272
- # Enable or disable automatic data cleanup
273
- config.archiving_enabled = true
274
-
275
- # Time-based retention - delete records older than this period
276
- config.full_retention_period = 2.weeks
277
-
278
- # Count-based retention - maximum records to keep per table
279
- # After time-based cleanup, if tables still exceed these limits,
280
- # the oldest remaining records will be deleted to stay under the limit
281
- config.max_table_records = {
282
- rails_pulse_requests: 10000, # HTTP requests (moderate volume)
283
- rails_pulse_operations: 50000, # Operations within requests (high volume)
284
- rails_pulse_routes: 1000, # Unique routes (low volume)
285
- rails_pulse_queries: 500 # Normalized SQL queries (low volume)
286
- }
287
- end
@@ -1,120 +0,0 @@
1
- // CSP Test functionality
2
- // Tests asset loading and AJAX requests under strict Content Security Policy
3
-
4
- document.addEventListener('DOMContentLoaded', function() {
5
- // Check asset loading status
6
- checkAssetLoadingStatus();
7
-
8
- // Setup AJAX button
9
- setupAjaxButton();
10
-
11
- // Check for CSP violations
12
- checkCspViolations();
13
- });
14
-
15
- function checkAssetLoadingStatus() {
16
- const cssStatus = document.getElementById('css-status');
17
- const jsStatus = document.getElementById('js-status');
18
- const iconsStatus = document.getElementById('icons-status');
19
- const stimulusStatus = document.getElementById('stimulus-status');
20
-
21
- // Check if CSS is loaded by testing if styles are applied
22
- if (cssStatus) {
23
- const testElement = document.querySelector('.card');
24
- if (testElement && getComputedStyle(testElement).backgroundColor !== 'rgba(0, 0, 0, 0)') {
25
- cssStatus.textContent = 'Loaded';
26
- cssStatus.className = 'badge badge--success';
27
- } else {
28
- cssStatus.textContent = 'Failed';
29
- cssStatus.className = 'badge badge--error';
30
- }
31
- }
32
-
33
- // Check if JS is loaded (this script proves it)
34
- if (jsStatus) {
35
- jsStatus.textContent = 'Loaded';
36
- jsStatus.className = 'badge badge--success';
37
- }
38
-
39
- // Check if icons script is loaded
40
- if (iconsStatus) {
41
- if (typeof window.RailsPulseIcons !== 'undefined') {
42
- iconsStatus.textContent = 'Loaded';
43
- iconsStatus.className = 'badge badge--success';
44
- } else {
45
- iconsStatus.textContent = 'Failed';
46
- iconsStatus.className = 'badge badge--error';
47
- }
48
- }
49
-
50
- // Check if Stimulus is active
51
- if (stimulusStatus) {
52
- if (window.Stimulus && typeof window.Stimulus.getControllerForElementAndIdentifier === 'function') {
53
- stimulusStatus.textContent = 'Active';
54
- stimulusStatus.className = 'badge badge--success';
55
- } else {
56
- stimulusStatus.textContent = 'Inactive';
57
- stimulusStatus.className = 'badge badge--error';
58
- }
59
- }
60
- }
61
-
62
- function setupAjaxButton() {
63
- const ajaxButton = document.getElementById('ajax-test-btn');
64
- const ajaxResult = document.getElementById('ajax-result');
65
-
66
- if (ajaxButton && ajaxResult) {
67
- ajaxButton.addEventListener('click', function() {
68
- // Update UI to show loading state
69
- ajaxButton.disabled = true;
70
- ajaxButton.textContent = 'Loading...';
71
- ajaxResult.innerHTML = '<span class="text-subtle">Making AJAX request...</span>';
72
-
73
- // Make AJAX request to the JSON endpoint
74
- fetch('/rails_pulse/csp_test.json', {
75
- method: 'GET',
76
- headers: {
77
- 'Accept': 'application/json',
78
- 'Content-Type': 'application/json'
79
- },
80
- credentials: 'same-origin'
81
- })
82
- .then(response => {
83
- if (!response.ok) {
84
- throw new Error('Network response was not ok');
85
- }
86
- return response.json();
87
- })
88
- .then(data => {
89
- // Success - display the success message
90
- ajaxResult.innerHTML = '<span class="text-success">AJAX request completed successfully</span>';
91
- ajaxButton.textContent = 'Test AJAX Loading';
92
- ajaxButton.disabled = false;
93
- })
94
- .catch(error => {
95
- // Error handling
96
- console.error('AJAX request failed:', error);
97
- ajaxResult.innerHTML = '<span class="text-error">AJAX request failed: ' + error.message + '</span>';
98
- ajaxButton.textContent = 'Test AJAX Loading';
99
- ajaxButton.disabled = false;
100
- });
101
- });
102
- }
103
- }
104
-
105
- function checkCspViolations() {
106
- const violationCount = document.getElementById('violation-count');
107
-
108
- if (violationCount) {
109
- // Start with 0 violations and mark as success immediately
110
- let violations = 0;
111
- violationCount.className = 'badge badge--success';
112
-
113
- // Listen for CSP violations
114
- document.addEventListener('securitypolicyviolation', function() {
115
- violations++;
116
- violationCount.textContent = violations.toString();
117
- violationCount.className = 'badge badge--error';
118
- });
119
- }
120
- }
@@ -1,13 +0,0 @@
1
- {
2
- "version": 3,
3
- "file": "rails-pulse-icons.js",
4
- "sourceRoot": "",
5
- "sources": [
6
- "rails-pulse-icons.js"
7
- ],
8
- "names": [],
9
- "mappings": "",
10
- "sourcesContent": [
11
- "// Rails Pulse Icons Bundle - Auto-generated\n// Contains 37 SVG icons for Rails Pulse\n\n(function() {\n 'use strict';\n\n // Icon data\n const icons = {\n \"menu\": \"<path d=\\\"M4 5h16\\\" /><path d=\\\"M4 12h16\\\" /><path d=\\\"M4 19h16\\\" />\",\n \"sun\": \"<circle cx=\\\"12\\\" cy=\\\"12\\\" r=\\\"4\\\" /><path d=\\\"M12 2v2\\\" /><path d=\\\"M12 20v2\\\" /><path d=\\\"m4.93 4.93 1.41 1.41\\\" /><path d=\\\"m17.66 17.66 1.41 1.41\\\" /><path d=\\\"M2 12h2\\\" /><path d=\\\"M20 12h2\\\" /><path d=\\\"m6.34 17.66-1.41 1.41\\\" /><path d=\\\"m19.07 4.93-1.41 1.41\\\" />\",\n \"moon\": \"<path d=\\\"M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401\\\" />\",\n \"chevron-right\": \"<path d=\\\"m9 18 6-6-6-6\\\" />\",\n \"chevron-left\": \"<path d=\\\"m15 18-6-6 6-6\\\" />\",\n \"chevron-down\": \"<path d=\\\"m6 9 6 6 6-6\\\" />\",\n \"chevron-up\": \"<path d=\\\"m18 15-6-6-6 6\\\" />\",\n \"chevrons-left\": \"<path d=\\\"m11 17-5-5 5-5\\\" /><path d=\\\"m18 17-5-5 5-5\\\" />\",\n \"chevrons-right\": \"<path d=\\\"m6 17 5-5-5-5\\\" /><path d=\\\"m13 17 5-5-5-5\\\" />\",\n \"loader-circle\": \"<path d=\\\"M12 2v4\\\" /><path d=\\\"m16.2 7.8 2.9-2.9\\\" /><path d=\\\"M18 12h4\\\" /><path d=\\\"m16.2 16.2 2.9 2.9\\\" /><path d=\\\"M12 18v4\\\" /><path d=\\\"m4.9 19.1 2.9-2.9\\\" /><path d=\\\"M2 12h4\\\" /><path d=\\\"m4.9 4.9 2.9 2.9\\\" />\",\n \"search\": \"<path d=\\\"m21 21-4.34-4.34\\\" /><circle cx=\\\"11\\\" cy=\\\"11\\\" r=\\\"8\\\" />\",\n \"list-filter\": \"<path d=\\\"M2 5h20\\\" /><path d=\\\"M6 12h12\\\" /><path d=\\\"M9 19h6\\\" />\",\n \"list-filter-plus\": \"<path d=\\\"M12 5H2\\\" /><path d=\\\"M6 12h12\\\" /><path d=\\\"M9 19h6\\\" /><path d=\\\"M16 5h6\\\" /><path d=\\\"M19 8V2\\\" />\",\n \"x\": \"<path d=\\\"M18 6 6 18\\\" /><path d=\\\"m6 6 12 12\\\" />\",\n \"x-circle\": \"<circle cx=\\\"12\\\" cy=\\\"12\\\" r=\\\"10\\\" /><path d=\\\"m15 9-6 6\\\" /><path d=\\\"m9 9 6 6\\\" />\",\n \"check\": \"<path d=\\\"M20 6 9 17l-5-5\\\" />\",\n \"alert-circle\": \"<circle cx=\\\"12\\\" cy=\\\"12\\\" r=\\\"10\\\" /><line x1=\\\"12\\\" x2=\\\"12\\\" y1=\\\"8\\\" y2=\\\"12\\\" /><line x1=\\\"12\\\" x2=\\\"12.01\\\" y1=\\\"16\\\" y2=\\\"16\\\" />\",\n \"alert-triangle\": \"<path d=\\\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\\\" /><path d=\\\"M12 9v4\\\" /><path d=\\\"M12 17h.01\\\" />\",\n \"info\": \"<circle cx=\\\"12\\\" cy=\\\"12\\\" r=\\\"10\\\" /><path d=\\\"M12 16v-4\\\" /><path d=\\\"M12 8h.01\\\" />\",\n \"external-link\": \"<path d=\\\"M15 3h6v6\\\" /><path d=\\\"M10 14 21 3\\\" /><path d=\\\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\\\" />\",\n \"download\": \"<path d=\\\"M12 15V3\\\" /><path d=\\\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\\\" /><path d=\\\"m7 10 5 5 5-5\\\" />\",\n \"refresh-cw\": \"<path d=\\\"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8\\\" /><path d=\\\"M21 3v5h-5\\\" /><path d=\\\"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16\\\" /><path d=\\\"M8 16H3v5\\\" />\",\n \"clock\": \"<path d=\\\"M12 6v6l4 2\\\" /><circle cx=\\\"12\\\" cy=\\\"12\\\" r=\\\"10\\\" />\",\n \"database\": \"<ellipse cx=\\\"12\\\" cy=\\\"5\\\" rx=\\\"9\\\" ry=\\\"3\\\" /><path d=\\\"M3 5V19A9 3 0 0 0 21 19V5\\\" /><path d=\\\"M3 12A9 3 0 0 0 21 12\\\" />\",\n \"server\": \"<rect width=\\\"20\\\" height=\\\"8\\\" x=\\\"2\\\" y=\\\"2\\\" rx=\\\"2\\\" ry=\\\"2\\\" /><rect width=\\\"20\\\" height=\\\"8\\\" x=\\\"2\\\" y=\\\"14\\\" rx=\\\"2\\\" ry=\\\"2\\\" /><line x1=\\\"6\\\" x2=\\\"6.01\\\" y1=\\\"6\\\" y2=\\\"6\\\" /><line x1=\\\"6\\\" x2=\\\"6.01\\\" y1=\\\"18\\\" y2=\\\"18\\\" />\",\n \"activity\": \"<path d=\\\"M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2\\\" />\",\n \"layout-dashboard\": \"<rect width=\\\"7\\\" height=\\\"9\\\" x=\\\"3\\\" y=\\\"3\\\" rx=\\\"1\\\" /><rect width=\\\"7\\\" height=\\\"5\\\" x=\\\"14\\\" y=\\\"3\\\" rx=\\\"1\\\" /><rect width=\\\"7\\\" height=\\\"9\\\" x=\\\"14\\\" y=\\\"12\\\" rx=\\\"1\\\" /><rect width=\\\"7\\\" height=\\\"5\\\" x=\\\"3\\\" y=\\\"16\\\" rx=\\\"1\\\" />\",\n \"audio-lines\": \"<path d=\\\"M2 10v3\\\" /><path d=\\\"M6 6v11\\\" /><path d=\\\"M10 3v18\\\" /><path d=\\\"M14 8v7\\\" /><path d=\\\"M18 5v13\\\" /><path d=\\\"M22 10v3\\\" />\",\n \"message-circle-question\": \"<path d=\\\"M2.992 16.342a2 2 0 0 1 .094 1.167l-1.065 3.29a1 1 0 0 0 1.236 1.168l3.413-.998a2 2 0 0 1 1.099.092 10 10 0 1 0-4.777-4.719\\\" /><path d=\\\"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3\\\" /><path d=\\\"M12 17h.01\\\" />\",\n \"route\": \"<circle cx=\\\"6\\\" cy=\\\"19\\\" r=\\\"3\\\" /><path d=\\\"M9 19h8.5a3.5 3.5 0 0 0 0-7h-11a3.5 3.5 0 0 1 0-7H15\\\" /><circle cx=\\\"18\\\" cy=\\\"5\\\" r=\\\"3\\\" />\",\n \"trending-up\": \"<path d=\\\"M16 7h6v6\\\" /><path d=\\\"m22 7-8.5 8.5-5-5L2 17\\\" />\",\n \"trending-down\": \"<path d=\\\"M16 17h6v-6\\\" /><path d=\\\"m22 17-8.5-8.5-5 5L2 7\\\" />\",\n \"move-right\": \"<path d=\\\"M18 8L22 12L18 16\\\" /><path d=\\\"M2 12H22\\\" />\",\n \"eye\": \"<path d=\\\"M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0\\\" /><circle cx=\\\"12\\\" cy=\\\"12\\\" r=\\\"3\\\" />\",\n \"zap\": \"<path d=\\\"M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z\\\" />\",\n \"shield-check\": \"<path d=\\\"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z\\\" /><path d=\\\"m9 12 2 2 4-4\\\" />\",\n \"bell\": \"<path d=\\\"M10.268 21a2 2 0 0 0 3.464 0\\\" /><path d=\\\"M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326\\\" />\"\n};\n\n // Global icon registry\n window.RailsPulseIcons = {\n icons: icons,\n\n // Get icon SVG content\n get: function(name) {\n return icons[name] || null;\n },\n\n // Check if icon exists\n has: function(name) {\n return name in icons;\n },\n\n // Get all icon names\n list: function() {\n return Object.keys(icons);\n },\n\n // Render icon to element (CSP-safe)\n render: function(name, element, options = {}) {\n const svgContent = this.get(name);\n if (!svgContent || !element) return false;\n\n // Create SVG element\n const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n svg.setAttribute('width', options.width || '24');\n svg.setAttribute('height', options.height || '24');\n svg.setAttribute('viewBox', '0 0 24 24');\n svg.setAttribute('fill', 'none');\n svg.setAttribute('stroke', 'currentColor');\n svg.setAttribute('stroke-width', '2');\n svg.setAttribute('stroke-linecap', 'round');\n svg.setAttribute('stroke-linejoin', 'round');\n\n // Add icon content\n svg.innerHTML = svgContent;\n\n // Replace element content\n element.innerHTML = '';\n element.appendChild(svg);\n\n return true;\n }\n };\n})();\n"
12
- ]
13
- }