rails_pulse 0.1.2 → 0.1.4

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 (101) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +66 -20
  3. data/Rakefile +169 -86
  4. data/app/assets/images/rails_pulse/dashboard.png +0 -0
  5. data/app/assets/images/rails_pulse/request.png +0 -0
  6. data/app/assets/stylesheets/rails_pulse/application.css +28 -5
  7. data/app/assets/stylesheets/rails_pulse/components/badge.css +13 -0
  8. data/app/assets/stylesheets/rails_pulse/components/base.css +12 -2
  9. data/app/assets/stylesheets/rails_pulse/components/collapsible.css +30 -0
  10. data/app/assets/stylesheets/rails_pulse/components/popover.css +0 -1
  11. data/app/assets/stylesheets/rails_pulse/components/row.css +55 -3
  12. data/app/assets/stylesheets/rails_pulse/components/sidebar_menu.css +23 -0
  13. data/app/controllers/concerns/zoom_range_concern.rb +31 -0
  14. data/app/controllers/rails_pulse/application_controller.rb +5 -1
  15. data/app/controllers/rails_pulse/queries_controller.rb +49 -10
  16. data/app/controllers/rails_pulse/requests_controller.rb +46 -20
  17. data/app/controllers/rails_pulse/routes_controller.rb +40 -1
  18. data/app/helpers/rails_pulse/breadcrumbs_helper.rb +1 -1
  19. data/app/helpers/rails_pulse/chart_helper.rb +16 -8
  20. data/app/helpers/rails_pulse/formatting_helper.rb +21 -2
  21. data/app/javascript/rails_pulse/application.js +34 -3
  22. data/app/javascript/rails_pulse/controllers/collapsible_controller.js +32 -0
  23. data/app/javascript/rails_pulse/controllers/color_scheme_controller.js +2 -1
  24. data/app/javascript/rails_pulse/controllers/expandable_rows_controller.js +58 -0
  25. data/app/javascript/rails_pulse/controllers/index_controller.js +249 -11
  26. data/app/javascript/rails_pulse/controllers/popover_controller.js +28 -4
  27. data/app/javascript/rails_pulse/controllers/table_sort_controller.js +14 -0
  28. data/app/models/rails_pulse/dashboard/tables/slow_queries.rb +1 -1
  29. data/app/models/rails_pulse/dashboard/tables/slow_routes.rb +1 -1
  30. data/app/models/rails_pulse/queries/cards/average_query_times.rb +20 -20
  31. data/app/models/rails_pulse/queries/cards/execution_rate.rb +58 -14
  32. data/app/models/rails_pulse/queries/cards/percentile_query_times.rb +14 -9
  33. data/app/models/rails_pulse/queries/charts/average_query_times.rb +3 -7
  34. data/app/models/rails_pulse/query.rb +46 -0
  35. data/app/models/rails_pulse/request.rb +1 -1
  36. data/app/models/rails_pulse/requests/charts/average_response_times.rb +2 -2
  37. data/app/models/rails_pulse/requests/tables/index.rb +77 -0
  38. data/app/models/rails_pulse/routes/cards/average_response_times.rb +18 -20
  39. data/app/models/rails_pulse/routes/cards/error_rate_per_route.rb +14 -9
  40. data/app/models/rails_pulse/routes/cards/percentile_response_times.rb +14 -9
  41. data/app/models/rails_pulse/routes/cards/request_count_totals.rb +29 -13
  42. data/app/models/rails_pulse/routes/tables/index.rb +4 -2
  43. data/app/models/rails_pulse/summary.rb +7 -7
  44. data/app/services/rails_pulse/analysis/backtrace_analyzer.rb +256 -0
  45. data/app/services/rails_pulse/analysis/base_analyzer.rb +67 -0
  46. data/app/services/rails_pulse/analysis/explain_plan_analyzer.rb +206 -0
  47. data/app/services/rails_pulse/analysis/index_recommendation_engine.rb +326 -0
  48. data/app/services/rails_pulse/analysis/n_plus_one_detector.rb +241 -0
  49. data/app/services/rails_pulse/analysis/query_characteristics_analyzer.rb +154 -0
  50. data/app/services/rails_pulse/analysis/suggestion_generator.rb +217 -0
  51. data/app/services/rails_pulse/query_analysis_service.rb +125 -0
  52. data/app/views/layouts/rails_pulse/_sidebar_menu.html.erb +0 -1
  53. data/app/views/layouts/rails_pulse/application.html.erb +0 -2
  54. data/app/views/rails_pulse/components/_breadcrumbs.html.erb +1 -1
  55. data/app/views/rails_pulse/components/_code_panel.html.erb +17 -3
  56. data/app/views/rails_pulse/components/_empty_state.html.erb +1 -1
  57. data/app/views/rails_pulse/components/_metric_card.html.erb +28 -5
  58. data/app/views/rails_pulse/components/_operation_details_popover.html.erb +1 -1
  59. data/app/views/rails_pulse/components/_panel.html.erb +1 -1
  60. data/app/views/rails_pulse/components/_sparkline_stats.html.erb +5 -7
  61. data/app/views/rails_pulse/components/_table_head.html.erb +6 -1
  62. data/app/views/rails_pulse/dashboard/index.html.erb +2 -2
  63. data/app/views/rails_pulse/operations/show.html.erb +17 -15
  64. data/app/views/rails_pulse/queries/_analysis_error.html.erb +15 -0
  65. data/app/views/rails_pulse/queries/_analysis_prompt.html.erb +27 -0
  66. data/app/views/rails_pulse/queries/_analysis_results.html.erb +117 -0
  67. data/app/views/rails_pulse/queries/_analysis_section.html.erb +39 -0
  68. data/app/views/rails_pulse/queries/_show_table.html.erb +34 -6
  69. data/app/views/rails_pulse/queries/_table.html.erb +4 -8
  70. data/app/views/rails_pulse/queries/index.html.erb +48 -51
  71. data/app/views/rails_pulse/queries/show.html.erb +56 -52
  72. data/app/views/rails_pulse/requests/_operations.html.erb +30 -43
  73. data/app/views/rails_pulse/requests/_table.html.erb +31 -18
  74. data/app/views/rails_pulse/requests/index.html.erb +55 -50
  75. data/app/views/rails_pulse/requests/show.html.erb +0 -2
  76. data/app/views/rails_pulse/routes/_requests_table.html.erb +39 -0
  77. data/app/views/rails_pulse/routes/_table.html.erb +4 -10
  78. data/app/views/rails_pulse/routes/index.html.erb +49 -52
  79. data/app/views/rails_pulse/routes/show.html.erb +6 -8
  80. data/config/initializers/rails_charts_csp_patch.rb +32 -40
  81. data/config/routes.rb +5 -1
  82. data/db/migrate/20250930105043_install_rails_pulse_tables.rb +23 -0
  83. data/db/rails_pulse_schema.rb +10 -1
  84. data/lib/generators/rails_pulse/convert_to_migrations_generator.rb +81 -0
  85. data/lib/generators/rails_pulse/install_generator.rb +75 -18
  86. data/lib/generators/rails_pulse/templates/db/rails_pulse_schema.rb +72 -2
  87. data/lib/generators/rails_pulse/templates/migrations/install_rails_pulse_tables.rb +23 -0
  88. data/lib/generators/rails_pulse/templates/migrations/upgrade_rails_pulse_tables.rb +19 -0
  89. data/lib/generators/rails_pulse/upgrade_generator.rb +226 -0
  90. data/lib/rails_pulse/engine.rb +21 -0
  91. data/lib/rails_pulse/version.rb +1 -1
  92. data/lib/tasks/rails_pulse.rake +27 -8
  93. data/public/rails-pulse-assets/rails-pulse.css +1 -1
  94. data/public/rails-pulse-assets/rails-pulse.css.map +1 -1
  95. data/public/rails-pulse-assets/rails-pulse.js +53 -53
  96. data/public/rails-pulse-assets/rails-pulse.js.map +4 -4
  97. metadata +25 -6
  98. data/app/assets/images/rails_pulse/rails-pulse-logo.png +0 -0
  99. data/app/assets/images/rails_pulse/routes.png +0 -0
  100. data/app/javascript/rails_pulse/controllers/expandable_row_controller.js +0 -67
  101. data/db/migrate/20241222000001_create_rails_pulse_summaries.rb +0 -54
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_pulse
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rails Pulse
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-09-09 00:00:00.000000000 Z
10
+ date: 2025-10-13 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rails
@@ -173,9 +173,7 @@ files:
173
173
  - Rakefile
174
174
  - app/assets/images/rails_pulse/dashboard.png
175
175
  - app/assets/images/rails_pulse/menu.svg
176
- - app/assets/images/rails_pulse/rails-pulse-logo.png
177
176
  - app/assets/images/rails_pulse/request.png
178
- - app/assets/images/rails_pulse/routes.png
179
177
  - app/assets/stylesheets/rails_pulse/application.css
180
178
  - app/assets/stylesheets/rails_pulse/components/alert.css
181
179
  - app/assets/stylesheets/rails_pulse/components/badge.css
@@ -184,6 +182,7 @@ files:
184
182
  - app/assets/stylesheets/rails_pulse/components/button.css
185
183
  - app/assets/stylesheets/rails_pulse/components/card.css
186
184
  - app/assets/stylesheets/rails_pulse/components/chart.css
185
+ - app/assets/stylesheets/rails_pulse/components/collapsible.css
187
186
  - app/assets/stylesheets/rails_pulse/components/csp_safe_positioning.css
188
187
  - app/assets/stylesheets/rails_pulse/components/descriptive_list.css
189
188
  - app/assets/stylesheets/rails_pulse/components/dialog.css
@@ -218,16 +217,18 @@ files:
218
217
  - app/helpers/rails_pulse/status_helper.rb
219
218
  - app/helpers/rails_pulse/table_helper.rb
220
219
  - app/javascript/rails_pulse/application.js
220
+ - app/javascript/rails_pulse/controllers/collapsible_controller.js
221
221
  - app/javascript/rails_pulse/controllers/color_scheme_controller.js
222
222
  - app/javascript/rails_pulse/controllers/context_menu_controller.js
223
223
  - app/javascript/rails_pulse/controllers/dialog_controller.js
224
- - app/javascript/rails_pulse/controllers/expandable_row_controller.js
224
+ - app/javascript/rails_pulse/controllers/expandable_rows_controller.js
225
225
  - app/javascript/rails_pulse/controllers/form_controller.js
226
226
  - app/javascript/rails_pulse/controllers/icon_controller.js
227
227
  - app/javascript/rails_pulse/controllers/index_controller.js
228
228
  - app/javascript/rails_pulse/controllers/menu_controller.js
229
229
  - app/javascript/rails_pulse/controllers/pagination_controller.js
230
230
  - app/javascript/rails_pulse/controllers/popover_controller.js
231
+ - app/javascript/rails_pulse/controllers/table_sort_controller.js
231
232
  - app/javascript/rails_pulse/controllers/timezone_controller.js
232
233
  - app/javascript/rails_pulse/theme.js
233
234
  - app/jobs/rails_pulse/application_job.rb
@@ -250,6 +251,7 @@ files:
250
251
  - app/models/rails_pulse/request.rb
251
252
  - app/models/rails_pulse/requests/charts/average_response_times.rb
252
253
  - app/models/rails_pulse/requests/charts/operations_chart.rb
254
+ - app/models/rails_pulse/requests/tables/index.rb
253
255
  - app/models/rails_pulse/route.rb
254
256
  - app/models/rails_pulse/routes/cards/average_response_times.rb
255
257
  - app/models/rails_pulse/routes/cards/error_rate_per_route.rb
@@ -258,6 +260,14 @@ files:
258
260
  - app/models/rails_pulse/routes/charts/average_response_times.rb
259
261
  - app/models/rails_pulse/routes/tables/index.rb
260
262
  - app/models/rails_pulse/summary.rb
263
+ - app/services/rails_pulse/analysis/backtrace_analyzer.rb
264
+ - app/services/rails_pulse/analysis/base_analyzer.rb
265
+ - app/services/rails_pulse/analysis/explain_plan_analyzer.rb
266
+ - app/services/rails_pulse/analysis/index_recommendation_engine.rb
267
+ - app/services/rails_pulse/analysis/n_plus_one_detector.rb
268
+ - app/services/rails_pulse/analysis/query_characteristics_analyzer.rb
269
+ - app/services/rails_pulse/analysis/suggestion_generator.rb
270
+ - app/services/rails_pulse/query_analysis_service.rb
261
271
  - app/services/rails_pulse/sql_query_normalizer.rb
262
272
  - app/services/rails_pulse/summary_service.rb
263
273
  - app/views/layouts/rails_pulse/_menu_items.html.erb
@@ -286,6 +296,10 @@ files:
286
296
  - app/views/rails_pulse/operations/_operation_analysis_other.html.erb
287
297
  - app/views/rails_pulse/operations/_operation_analysis_view.html.erb
288
298
  - app/views/rails_pulse/operations/show.html.erb
299
+ - app/views/rails_pulse/queries/_analysis_error.html.erb
300
+ - app/views/rails_pulse/queries/_analysis_prompt.html.erb
301
+ - app/views/rails_pulse/queries/_analysis_results.html.erb
302
+ - app/views/rails_pulse/queries/_analysis_section.html.erb
289
303
  - app/views/rails_pulse/queries/_show_table.html.erb
290
304
  - app/views/rails_pulse/queries/_table.html.erb
291
305
  - app/views/rails_pulse/queries/index.html.erb
@@ -294,6 +308,7 @@ files:
294
308
  - app/views/rails_pulse/requests/_table.html.erb
295
309
  - app/views/rails_pulse/requests/index.html.erb
296
310
  - app/views/rails_pulse/requests/show.html.erb
311
+ - app/views/rails_pulse/routes/_requests_table.html.erb
297
312
  - app/views/rails_pulse/routes/_table.html.erb
298
313
  - app/views/rails_pulse/routes/index.html.erb
299
314
  - app/views/rails_pulse/routes/show.html.erb
@@ -305,11 +320,15 @@ files:
305
320
  - config/initializers/rails_charts_csp_patch.rb
306
321
  - config/initializers/rails_pulse.rb
307
322
  - config/routes.rb
308
- - db/migrate/20241222000001_create_rails_pulse_summaries.rb
323
+ - db/migrate/20250930105043_install_rails_pulse_tables.rb
309
324
  - db/rails_pulse_schema.rb
325
+ - lib/generators/rails_pulse/convert_to_migrations_generator.rb
310
326
  - lib/generators/rails_pulse/install_generator.rb
311
327
  - lib/generators/rails_pulse/templates/db/rails_pulse_schema.rb
328
+ - lib/generators/rails_pulse/templates/migrations/install_rails_pulse_tables.rb
329
+ - lib/generators/rails_pulse/templates/migrations/upgrade_rails_pulse_tables.rb
312
330
  - lib/generators/rails_pulse/templates/rails_pulse.rb
331
+ - lib/generators/rails_pulse/upgrade_generator.rb
313
332
  - lib/rails_pulse.rb
314
333
  - lib/rails_pulse/cleanup_service.rb
315
334
  - lib/rails_pulse/configuration.rb
@@ -1,67 +0,0 @@
1
- import { Controller } from "@hotwired/stimulus"
2
-
3
- export default class extends Controller {
4
- static targets = ["trigger", "details", "chevron"]
5
-
6
- connect() {
7
- // Ensure details row is initially hidden
8
- this.detailsTarget.classList.add("hidden")
9
- this.loaded = false
10
- }
11
-
12
- toggle(event) {
13
- event.preventDefault()
14
- event.stopPropagation()
15
-
16
- const isExpanded = !this.detailsTarget.classList.contains("hidden")
17
- console.log('Toggle clicked, currently expanded:', isExpanded)
18
-
19
- console.log('isExpanded', isExpanded)
20
- if (isExpanded) {
21
- console.log('Collapsing...')
22
- this.collapse()
23
- } else {
24
- console.log('Expanding...')
25
- this.expand()
26
- }
27
- }
28
-
29
- expand() {
30
- // Show details row
31
- this.detailsTarget.classList.remove("hidden")
32
-
33
- // Rotate chevron to point down
34
- this.chevronTarget.style.transform = "rotate(90deg)"
35
-
36
- // Add expanded state class to trigger row
37
- this.triggerTarget.classList.add("expanded")
38
-
39
- // Load content lazily on first expansion
40
- if (!this.loaded) {
41
- this.loadOperationDetails()
42
- this.loaded = true
43
- }
44
- }
45
-
46
- loadOperationDetails() {
47
- // Find the turbo frame and set its src to trigger loading
48
- const turboFrame = this.detailsTarget.querySelector('turbo-frame')
49
- if (turboFrame) {
50
- const operationUrl = turboFrame.dataset.operationUrl
51
- if (operationUrl) {
52
- turboFrame.src = operationUrl
53
- }
54
- }
55
- }
56
-
57
- collapse() {
58
- // Hide details row
59
- this.detailsTarget.classList.add("hidden")
60
-
61
- // Rotate chevron back to point right
62
- this.chevronTarget.style.transform = "rotate(0deg)"
63
-
64
- // Remove expanded state class from trigger row
65
- this.triggerTarget.classList.remove("expanded")
66
- }
67
- }
@@ -1,54 +0,0 @@
1
- class CreateRailsPulseSummaries < ActiveRecord::Migration[7.1]
2
- def change
3
- create_table :rails_pulse_summaries do |t|
4
- # Time fields
5
- t.datetime :period_start, null: false
6
- t.datetime :period_end, null: false
7
- t.string :period_type, null: false # 'hour', 'day', 'week', 'month'
8
-
9
- # Polymorphic association to handle both routes and queries
10
- t.references :summarizable, polymorphic: true, null: false, index: true
11
- # This creates summarizable_type (e.g., 'RailsPulse::Route', 'RailsPulse::Query')
12
- # and summarizable_id (route_id or query_id)
13
-
14
- # Universal metrics
15
- t.integer :count, default: 0, null: false
16
- t.float :avg_duration
17
- t.float :min_duration
18
- t.float :max_duration
19
- t.float :p50_duration
20
- t.float :p95_duration
21
- t.float :p99_duration
22
- t.float :total_duration
23
- t.float :stddev_duration
24
-
25
- # Request/Route specific metrics
26
- t.integer :error_count, default: 0
27
- t.integer :success_count, default: 0
28
- t.integer :status_2xx, default: 0
29
- t.integer :status_3xx, default: 0
30
- t.integer :status_4xx, default: 0
31
- t.integer :status_5xx, default: 0
32
-
33
- t.timestamps
34
-
35
- # Unique constraint and indexes
36
- t.index [ :summarizable_type, :summarizable_id, :period_type, :period_start ],
37
- unique: true,
38
- name: 'idx_pulse_summaries_unique'
39
- t.index [ :period_type, :period_start ]
40
- t.index :created_at
41
- end
42
-
43
- # Add indexes to existing tables for efficient aggregation
44
- add_index :rails_pulse_requests, [ :created_at, :route_id ],
45
- name: 'idx_requests_for_aggregation'
46
- add_index :rails_pulse_requests, :created_at,
47
- name: 'idx_requests_created_at'
48
-
49
- add_index :rails_pulse_operations, [ :created_at, :query_id ],
50
- name: 'idx_operations_for_aggregation'
51
- add_index :rails_pulse_operations, :created_at,
52
- name: 'idx_operations_created_at'
53
- end
54
- end