rails_pulse 0.4.2 → 0.5.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +58 -1
- data/README.md +15 -4
- data/app/assets/stylesheets/rails_pulse/components/chart.css +11 -0
- data/app/assets/stylesheets/rails_pulse/components/descriptive_list.css +19 -1
- data/app/assets/stylesheets/rails_pulse/components/row.css +3 -17
- data/app/controllers/concerns/chart_table_concern.rb +28 -69
- data/app/controllers/concerns/deployment_markers_concern.rb +3 -1
- data/app/controllers/concerns/metric_card_concern.rb +6 -7
- data/app/controllers/rails_pulse/api/v1/base_controller.rb +133 -0
- data/app/controllers/rails_pulse/api/v1/capabilities_controller.rb +27 -0
- data/app/controllers/rails_pulse/api/v1/coverage_controller.rb +158 -0
- data/app/controllers/rails_pulse/api/v1/deployments_controller.rb +40 -0
- data/app/controllers/rails_pulse/api/v1/exceptions_controller.rb +77 -0
- data/app/controllers/rails_pulse/api/v1/insights_controller.rb +62 -0
- data/app/controllers/rails_pulse/api/v1/job_runs_controller.rb +34 -0
- data/app/controllers/rails_pulse/api/v1/jobs_controller.rb +172 -0
- data/app/controllers/rails_pulse/api/v1/queries_controller.rb +123 -0
- data/app/controllers/rails_pulse/api/v1/requests_controller.rb +74 -0
- data/app/controllers/rails_pulse/api/v1/routes_controller.rb +103 -0
- data/app/controllers/rails_pulse/application_controller.rb +1 -1
- data/app/controllers/rails_pulse/dashboard_controller.rb +25 -21
- data/app/controllers/rails_pulse/deployments_controller.rb +23 -13
- data/app/controllers/rails_pulse/exceptions_controller.rb +10 -12
- data/app/controllers/rails_pulse/jobs_controller.rb +1 -2
- data/app/controllers/rails_pulse/queries_controller.rb +6 -5
- data/app/controllers/rails_pulse/requests_controller.rb +15 -14
- data/app/controllers/rails_pulse/routes_controller.rb +4 -8
- data/app/helpers/rails_pulse/application_helper.rb +15 -0
- data/app/helpers/rails_pulse/chart_helper.rb +9 -2
- data/app/helpers/rails_pulse/formatting_helper.rb +11 -12
- data/app/javascript/rails_pulse/controllers/chart_controller.js +80 -43
- data/app/jobs/rails_pulse/backfill_summaries_job.rb +4 -2
- data/app/jobs/rails_pulse/cloud_health_job.rb +11 -0
- data/app/jobs/rails_pulse/cloud_sync_job.rb +11 -0
- data/app/jobs/rails_pulse/summary_job.rb +13 -0
- data/app/models/concerns/rails_pulse/has_metadata.rb +15 -0
- data/app/models/concerns/rails_pulse/taggable.rb +5 -12
- data/app/models/rails_pulse/cards/base.rb +20 -11
- data/app/models/rails_pulse/charts/base.rb +5 -18
- data/app/models/rails_pulse/charts/percentile_chart_base.rb +3 -5
- data/app/models/rails_pulse/cleanup_run.rb +32 -0
- data/app/models/rails_pulse/cloud/buffered_batch.rb +55 -0
- data/app/models/rails_pulse/cloud/installation.rb +55 -0
- data/app/models/rails_pulse/dashboard/charts/response_time_percentiles.rb +4 -5
- data/app/models/rails_pulse/dashboard/charts/throughput_and_errors.rb +4 -5
- data/app/models/rails_pulse/dashboard/concerns/attention_classification.rb +104 -0
- data/app/models/rails_pulse/dashboard/concerns/time_range_helper.rb +25 -2
- data/app/models/rails_pulse/dashboard/health_summary.rb +38 -13
- data/app/models/rails_pulse/dashboard/needs_attention.rb +31 -98
- data/app/models/rails_pulse/dashboard/storage_pressure.rb +39 -63
- data/app/models/rails_pulse/dashboard/storage_status.rb +130 -39
- data/app/models/rails_pulse/deployment.rb +2 -7
- data/app/models/rails_pulse/event.rb +41 -0
- data/app/models/rails_pulse/exception_occurrence.rb +1 -1
- data/app/models/rails_pulse/exceptions/cards/exception_rate.rb +3 -6
- data/app/models/rails_pulse/exceptions/cards/open_groups.rb +1 -4
- data/app/models/rails_pulse/exceptions/cards/total_occurrences.rb +3 -6
- data/app/models/rails_pulse/exceptions/charts/occurrence_volume.rb +4 -7
- data/app/models/rails_pulse/job_run.rb +1 -1
- data/app/models/rails_pulse/jobs/cards/failure_rate.rb +8 -14
- data/app/models/rails_pulse/jobs/cards/p95_duration.rb +8 -14
- data/app/models/rails_pulse/jobs/cards/total_runs.rb +5 -11
- data/app/models/rails_pulse/jobs/charts/duration.rb +1 -2
- data/app/models/rails_pulse/jobs/charts/execution_volume.rb +1 -1
- data/app/models/rails_pulse/jobs/charts/failure_rate.rb +1 -2
- data/app/models/rails_pulse/like_pattern.rb +35 -0
- data/app/models/rails_pulse/queries/cards/average_query_times.rb +6 -12
- data/app/models/rails_pulse/queries/cards/database_load.rb +0 -9
- data/app/models/rails_pulse/queries/cards/execution_rate.rb +5 -11
- data/app/models/rails_pulse/queries/cards/percentile_query_times.rb +6 -12
- data/app/models/rails_pulse/queries/charts/database_load.rb +5 -8
- data/app/models/rails_pulse/queries/charts/execution_volume.rb +1 -1
- data/app/models/rails_pulse/request.rb +1 -1
- data/app/models/rails_pulse/routes/cards/error_rates.rb +5 -15
- data/app/models/rails_pulse/routes/cards/percentile_response_times.rb +5 -17
- data/app/models/rails_pulse/routes/cards/request_count_totals.rb +5 -17
- data/app/models/rails_pulse/routes/charts/error_rate.rb +1 -1
- data/app/models/rails_pulse/routes/charts/request_volume.rb +1 -1
- data/app/models/rails_pulse/summary.rb +5 -0
- data/app/models/rails_pulse/tables/base.rb +5 -6
- data/app/models/rails_pulse/time_range.rb +309 -0
- data/app/models/rails_pulse/time_window.rb +15 -0
- data/app/models/rails_pulse/writer_heartbeat.rb +90 -0
- data/app/serializers/rails_pulse/api/v1/deployment_serializer.rb +23 -0
- data/app/serializers/rails_pulse/api/v1/exception_group_serializer.rb +23 -0
- data/app/serializers/rails_pulse/api/v1/exception_occurrence_serializer.rb +22 -0
- data/app/serializers/rails_pulse/api/v1/job_run_serializer.rb +28 -0
- data/app/serializers/rails_pulse/api/v1/job_serializer.rb +26 -0
- data/app/serializers/rails_pulse/api/v1/query_serializer.rb +25 -0
- data/app/serializers/rails_pulse/api/v1/request_serializer.rb +22 -0
- data/app/serializers/rails_pulse/api/v1/route_serializer.rb +19 -0
- data/app/services/rails_pulse/cloud/batch.rb +83 -0
- data/app/services/rails_pulse/cloud/client.rb +68 -0
- data/app/services/rails_pulse/cloud/combined_metrics.rb +49 -0
- data/app/services/rails_pulse/cloud/health_item.rb +77 -0
- data/app/services/rails_pulse/cloud/path_prefix.rb +50 -0
- data/app/services/rails_pulse/cloud/preview.rb +83 -0
- data/app/services/rails_pulse/cloud/query_shape.rb +195 -0
- data/app/services/rails_pulse/cloud/record_items.rb +60 -0
- data/app/services/rails_pulse/cloud/route_pattern.rb +111 -0
- data/app/services/rails_pulse/cloud/summary_items.rb +188 -0
- data/app/services/rails_pulse/cloud/sync.rb +275 -0
- data/app/services/rails_pulse/config_recommendations.rb +132 -0
- data/app/services/rails_pulse/deployment_comparison.rb +177 -0
- data/app/services/rails_pulse/exception_capture_service.rb +1 -1
- data/app/services/rails_pulse/operations/change_point.rb +1 -1
- data/app/services/rails_pulse/operations/comparison.rb +1 -1
- data/app/services/rails_pulse/period_insights.rb +131 -0
- data/app/services/rails_pulse/sql_query_normalizer.rb +222 -122
- data/app/services/rails_pulse/summary_service/from_child_periods.rb +161 -0
- data/app/services/rails_pulse/summary_service/from_raw_rows.rb +115 -0
- data/app/services/rails_pulse/summary_service/metrics.rb +38 -0
- data/app/services/rails_pulse/summary_service.rb +121 -133
- data/app/services/rails_pulse/tag_filter_service.rb +5 -5
- data/app/views/layouts/rails_pulse/_time_range_selector.html.erb +4 -1
- data/app/views/rails_pulse/components/_operation_details_popover.html.erb +1 -1
- data/app/views/rails_pulse/components/_table_head.html.erb +2 -2
- data/app/views/rails_pulse/dashboard/_chart_panel.html.erb +6 -1
- data/app/views/rails_pulse/dashboard/_deployments_panel.html.erb +2 -2
- data/app/views/rails_pulse/dashboard/_health_badge.html.erb +29 -20
- data/app/views/rails_pulse/dashboard/_storage_panel.html.erb +13 -3
- data/app/views/rails_pulse/dashboard/index.html.erb +16 -2
- data/app/views/rails_pulse/jobs/_chart_tabs.html.erb +1 -0
- data/app/views/rails_pulse/jobs/index.html.erb +1 -1
- data/app/views/rails_pulse/queries/_chart_tabs.html.erb +1 -0
- data/app/views/rails_pulse/queries/index.html.erb +1 -1
- data/app/views/rails_pulse/queries/show.html.erb +1 -1
- data/app/views/rails_pulse/requests/index.html.erb +1 -1
- data/app/views/rails_pulse/routes/_chart_tabs.html.erb +1 -0
- data/app/views/rails_pulse/routes/index.html.erb +1 -1
- data/app/views/rails_pulse/routes/show.html.erb +1 -1
- data/app/views/rails_pulse/shared/_aggregation_zone_badge.html.erb +4 -0
- data/app/views/rails_pulse/storage/show.html.erb +39 -2
- data/config/routes.rb +23 -0
- data/db/rails_pulse_cloud_schema.rb +58 -0
- data/db/rails_pulse_migrate/20260506000001_create_rails_pulse_exceptions.rb +1 -1
- data/db/rails_pulse_migrate/20260921000001_create_rails_pulse_events.rb +21 -0
- data/db/rails_pulse_schema.rb +20 -2
- data/exe/rails-pulse +7 -0
- data/lib/generators/rails_pulse/base_methods.rb +19 -0
- data/lib/generators/rails_pulse/install_cloud_generator.rb +84 -0
- data/lib/generators/rails_pulse/templates/db/rails_pulse_cloud_schema.rb +58 -0
- data/lib/generators/rails_pulse/templates/db/rails_pulse_schema.rb +20 -2
- data/lib/generators/rails_pulse/templates/migrations/install_rails_pulse_cloud_tables.rb +30 -0
- data/lib/generators/rails_pulse/templates/rails_pulse.rb +71 -19
- data/lib/generators/rails_pulse/upgrade_generator.rb +9 -16
- data/lib/rails_pulse/cleanup_service.rb +37 -20
- data/lib/rails_pulse/cli/agent_files/agents.md +89 -0
- data/lib/rails_pulse/cli/agent_files/claude_skill.md +182 -0
- data/lib/rails_pulse/cli/base_command.rb +37 -0
- data/lib/rails_pulse/cli/client.rb +64 -0
- data/lib/rails_pulse/cli/config.rb +87 -0
- data/lib/rails_pulse/cli/configure.rb +75 -0
- data/lib/rails_pulse/cli/coverage.rb +91 -0
- data/lib/rails_pulse/cli/deployments.rb +54 -0
- data/lib/rails_pulse/cli/exceptions.rb +116 -0
- data/lib/rails_pulse/cli/formatter.rb +31 -0
- data/lib/rails_pulse/cli/insights.rb +70 -0
- data/lib/rails_pulse/cli/install.rb +145 -0
- data/lib/rails_pulse/cli/job_runs.rb +53 -0
- data/lib/rails_pulse/cli/jobs.rb +71 -0
- data/lib/rails_pulse/cli/main.rb +76 -0
- data/lib/rails_pulse/cli/mcp.rb +47 -0
- data/lib/rails_pulse/cli/queries.rb +67 -0
- data/lib/rails_pulse/cli/requests.rb +57 -0
- data/lib/rails_pulse/cli/routes.rb +73 -0
- data/lib/rails_pulse/configuration.rb +100 -2
- data/lib/rails_pulse/current.rb +11 -0
- data/lib/rails_pulse/engine.rb +12 -3
- data/lib/rails_pulse/installers/config_updater.rb +9 -2
- data/lib/rails_pulse/job_run_collector.rb +15 -15
- data/lib/rails_pulse/mcp/server.rb +78 -0
- data/lib/rails_pulse/mcp/tools/coverage.rb +96 -0
- data/lib/rails_pulse/mcp/tools/deployments.rb +117 -0
- data/lib/rails_pulse/mcp/tools/endpoint.rb +167 -0
- data/lib/rails_pulse/mcp/tools/errors.rb +104 -0
- data/lib/rails_pulse/mcp/tools/exception_detail.rb +118 -0
- data/lib/rails_pulse/mcp/tools/exceptions.rb +128 -0
- data/lib/rails_pulse/mcp/tools/helpers.rb +162 -0
- data/lib/rails_pulse/mcp/tools/insights.rb +99 -0
- data/lib/rails_pulse/mcp/tools/jobs.rb +155 -0
- data/lib/rails_pulse/mcp/tools/queries.rb +142 -0
- data/lib/rails_pulse/mcp/tools/routes.rb +108 -0
- data/lib/rails_pulse/mcp/tools/slow_requests.rb +118 -0
- data/lib/rails_pulse/middleware/request_collector.rb +9 -9
- data/lib/rails_pulse/scoped_inflector.rb +35 -0
- data/lib/rails_pulse/statistics.rb +27 -0
- data/lib/rails_pulse/subscribers/exception_subscriber.rb +2 -2
- data/lib/rails_pulse/subscribers/operation_subscriber.rb +15 -29
- data/lib/rails_pulse/tasks/status_reporter.rb +201 -0
- data/lib/rails_pulse/tracker.rb +76 -14
- data/lib/rails_pulse/version.rb +1 -1
- data/lib/rails_pulse.rb +0 -4
- data/lib/tasks/rails_pulse.rake +6 -0
- data/lib/tasks/rails_pulse_tasks.rake +7 -0
- data/public/rails-pulse-assets/rails-pulse.css +1 -1
- data/public/rails-pulse-assets/rails-pulse.js +13 -13
- metadata +123 -24
- data/app/controllers/concerns/page_timings.rb +0 -10
- data/app/controllers/concerns/response_range_concern.rb +0 -45
- data/app/controllers/concerns/time_range_concern.rb +0 -152
- data/app/controllers/concerns/zoom_range_concern.rb +0 -86
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rails_pulse
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0.pre.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Scott Harvey
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-11 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
@@ -16,7 +16,7 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: 7.
|
|
19
|
+
version: 7.2.0
|
|
20
20
|
- - "<"
|
|
21
21
|
- !ruby/object:Gem::Version
|
|
22
22
|
version: 9.0.0
|
|
@@ -26,24 +26,10 @@ dependencies:
|
|
|
26
26
|
requirements:
|
|
27
27
|
- - ">="
|
|
28
28
|
- !ruby/object:Gem::Version
|
|
29
|
-
version: 7.
|
|
29
|
+
version: 7.2.0
|
|
30
30
|
- - "<"
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
32
|
version: 9.0.0
|
|
33
|
-
- !ruby/object:Gem::Dependency
|
|
34
|
-
name: request_store
|
|
35
|
-
requirement: !ruby/object:Gem::Requirement
|
|
36
|
-
requirements:
|
|
37
|
-
- - "~>"
|
|
38
|
-
- !ruby/object:Gem::Version
|
|
39
|
-
version: '1.5'
|
|
40
|
-
type: :runtime
|
|
41
|
-
prerelease: false
|
|
42
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
43
|
-
requirements:
|
|
44
|
-
- - "~>"
|
|
45
|
-
- !ruby/object:Gem::Version
|
|
46
|
-
version: '1.5'
|
|
47
33
|
- !ruby/object:Gem::Dependency
|
|
48
34
|
name: ransack
|
|
49
35
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -64,6 +50,20 @@ dependencies:
|
|
|
64
50
|
- - "<"
|
|
65
51
|
- !ruby/object:Gem::Version
|
|
66
52
|
version: '6'
|
|
53
|
+
- !ruby/object:Gem::Dependency
|
|
54
|
+
name: thor
|
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
|
56
|
+
requirements:
|
|
57
|
+
- - "~>"
|
|
58
|
+
- !ruby/object:Gem::Version
|
|
59
|
+
version: '1.0'
|
|
60
|
+
type: :runtime
|
|
61
|
+
prerelease: false
|
|
62
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
63
|
+
requirements:
|
|
64
|
+
- - "~>"
|
|
65
|
+
- !ruby/object:Gem::Version
|
|
66
|
+
version: '1.0'
|
|
67
67
|
- !ruby/object:Gem::Dependency
|
|
68
68
|
name: sqlite3
|
|
69
69
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -182,6 +182,20 @@ dependencies:
|
|
|
182
182
|
- - ">="
|
|
183
183
|
- !ruby/object:Gem::Version
|
|
184
184
|
version: '0'
|
|
185
|
+
- !ruby/object:Gem::Dependency
|
|
186
|
+
name: mcp
|
|
187
|
+
requirement: !ruby/object:Gem::Requirement
|
|
188
|
+
requirements:
|
|
189
|
+
- - "~>"
|
|
190
|
+
- !ruby/object:Gem::Version
|
|
191
|
+
version: '1.0'
|
|
192
|
+
type: :development
|
|
193
|
+
prerelease: false
|
|
194
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
195
|
+
requirements:
|
|
196
|
+
- - "~>"
|
|
197
|
+
- !ruby/object:Gem::Version
|
|
198
|
+
version: '1.0'
|
|
185
199
|
description: Self-hosted performance monitoring engine for Rails apps. Tracks slow
|
|
186
200
|
requests, N+1 queries, and SQL performance. All data stays in your own database
|
|
187
201
|
— no third-party cloud required.
|
|
@@ -189,6 +203,7 @@ email:
|
|
|
189
203
|
- hey@railspulse.com
|
|
190
204
|
executables:
|
|
191
205
|
- rails_pulse_server
|
|
206
|
+
- rails-pulse
|
|
192
207
|
extensions: []
|
|
193
208
|
extra_rdoc_files: []
|
|
194
209
|
files:
|
|
@@ -231,14 +246,21 @@ files:
|
|
|
231
246
|
- app/controllers/concerns/chart_table_concern.rb
|
|
232
247
|
- app/controllers/concerns/deployment_markers_concern.rb
|
|
233
248
|
- app/controllers/concerns/metric_card_concern.rb
|
|
234
|
-
- app/controllers/concerns/page_timings.rb
|
|
235
249
|
- app/controllers/concerns/pagination_concern.rb
|
|
236
250
|
- app/controllers/concerns/ransack_params_concern.rb
|
|
237
|
-
- app/controllers/concerns/response_range_concern.rb
|
|
238
251
|
- app/controllers/concerns/session_filters_concern.rb
|
|
239
252
|
- app/controllers/concerns/tag_filter_concern.rb
|
|
240
|
-
- app/controllers/
|
|
241
|
-
- app/controllers/
|
|
253
|
+
- app/controllers/rails_pulse/api/v1/base_controller.rb
|
|
254
|
+
- app/controllers/rails_pulse/api/v1/capabilities_controller.rb
|
|
255
|
+
- app/controllers/rails_pulse/api/v1/coverage_controller.rb
|
|
256
|
+
- app/controllers/rails_pulse/api/v1/deployments_controller.rb
|
|
257
|
+
- app/controllers/rails_pulse/api/v1/exceptions_controller.rb
|
|
258
|
+
- app/controllers/rails_pulse/api/v1/insights_controller.rb
|
|
259
|
+
- app/controllers/rails_pulse/api/v1/job_runs_controller.rb
|
|
260
|
+
- app/controllers/rails_pulse/api/v1/jobs_controller.rb
|
|
261
|
+
- app/controllers/rails_pulse/api/v1/queries_controller.rb
|
|
262
|
+
- app/controllers/rails_pulse/api/v1/requests_controller.rb
|
|
263
|
+
- app/controllers/rails_pulse/api/v1/routes_controller.rb
|
|
242
264
|
- app/controllers/rails_pulse/application_controller.rb
|
|
243
265
|
- app/controllers/rails_pulse/assets_controller.rb
|
|
244
266
|
- app/controllers/rails_pulse/csp_test_controller.rb
|
|
@@ -292,7 +314,10 @@ files:
|
|
|
292
314
|
- app/jobs/rails_pulse/application_job.rb
|
|
293
315
|
- app/jobs/rails_pulse/backfill_summaries_job.rb
|
|
294
316
|
- app/jobs/rails_pulse/cleanup_job.rb
|
|
317
|
+
- app/jobs/rails_pulse/cloud_health_job.rb
|
|
318
|
+
- app/jobs/rails_pulse/cloud_sync_job.rb
|
|
295
319
|
- app/jobs/rails_pulse/summary_job.rb
|
|
320
|
+
- app/models/concerns/rails_pulse/has_metadata.rb
|
|
296
321
|
- app/models/concerns/rails_pulse/has_performance_status.rb
|
|
297
322
|
- app/models/concerns/rails_pulse/taggable.rb
|
|
298
323
|
- app/models/rails_pulse/application_record.rb
|
|
@@ -301,8 +326,12 @@ files:
|
|
|
301
326
|
- app/models/rails_pulse/charts/base.rb
|
|
302
327
|
- app/models/rails_pulse/charts/operations_chart.rb
|
|
303
328
|
- app/models/rails_pulse/charts/percentile_chart_base.rb
|
|
329
|
+
- app/models/rails_pulse/cleanup_run.rb
|
|
330
|
+
- app/models/rails_pulse/cloud/buffered_batch.rb
|
|
331
|
+
- app/models/rails_pulse/cloud/installation.rb
|
|
304
332
|
- app/models/rails_pulse/dashboard/charts/response_time_percentiles.rb
|
|
305
333
|
- app/models/rails_pulse/dashboard/charts/throughput_and_errors.rb
|
|
334
|
+
- app/models/rails_pulse/dashboard/concerns/attention_classification.rb
|
|
306
335
|
- app/models/rails_pulse/dashboard/concerns/threshold_constants.rb
|
|
307
336
|
- app/models/rails_pulse/dashboard/concerns/time_range_helper.rb
|
|
308
337
|
- app/models/rails_pulse/dashboard/health_summary.rb
|
|
@@ -310,6 +339,7 @@ files:
|
|
|
310
339
|
- app/models/rails_pulse/dashboard/storage_pressure.rb
|
|
311
340
|
- app/models/rails_pulse/dashboard/storage_status.rb
|
|
312
341
|
- app/models/rails_pulse/deployment.rb
|
|
342
|
+
- app/models/rails_pulse/event.rb
|
|
313
343
|
- app/models/rails_pulse/exception_group.rb
|
|
314
344
|
- app/models/rails_pulse/exception_occurrence.rb
|
|
315
345
|
- app/models/rails_pulse/exceptions/cards/exception_rate.rb
|
|
@@ -326,6 +356,7 @@ files:
|
|
|
326
356
|
- app/models/rails_pulse/jobs/charts/execution_volume.rb
|
|
327
357
|
- app/models/rails_pulse/jobs/charts/failure_rate.rb
|
|
328
358
|
- app/models/rails_pulse/jobs/tables/index.rb
|
|
359
|
+
- app/models/rails_pulse/like_pattern.rb
|
|
329
360
|
- app/models/rails_pulse/operation.rb
|
|
330
361
|
- app/models/rails_pulse/queries/cards/average_query_times.rb
|
|
331
362
|
- app/models/rails_pulse/queries/cards/database_load.rb
|
|
@@ -347,8 +378,18 @@ files:
|
|
|
347
378
|
- app/models/rails_pulse/routes/tables/index.rb
|
|
348
379
|
- app/models/rails_pulse/summary.rb
|
|
349
380
|
- app/models/rails_pulse/tables/base.rb
|
|
381
|
+
- app/models/rails_pulse/time_range.rb
|
|
350
382
|
- app/models/rails_pulse/time_range_preference.rb
|
|
351
383
|
- app/models/rails_pulse/time_window.rb
|
|
384
|
+
- app/models/rails_pulse/writer_heartbeat.rb
|
|
385
|
+
- app/serializers/rails_pulse/api/v1/deployment_serializer.rb
|
|
386
|
+
- app/serializers/rails_pulse/api/v1/exception_group_serializer.rb
|
|
387
|
+
- app/serializers/rails_pulse/api/v1/exception_occurrence_serializer.rb
|
|
388
|
+
- app/serializers/rails_pulse/api/v1/job_run_serializer.rb
|
|
389
|
+
- app/serializers/rails_pulse/api/v1/job_serializer.rb
|
|
390
|
+
- app/serializers/rails_pulse/api/v1/query_serializer.rb
|
|
391
|
+
- app/serializers/rails_pulse/api/v1/request_serializer.rb
|
|
392
|
+
- app/serializers/rails_pulse/api/v1/route_serializer.rb
|
|
352
393
|
- app/services/rails_pulse/analysis/backtrace_analyzer.rb
|
|
353
394
|
- app/services/rails_pulse/analysis/base_analyzer.rb
|
|
354
395
|
- app/services/rails_pulse/analysis/explain_plan_analyzer.rb
|
|
@@ -356,6 +397,19 @@ files:
|
|
|
356
397
|
- app/services/rails_pulse/analysis/n_plus_one_detector.rb
|
|
357
398
|
- app/services/rails_pulse/analysis/query_characteristics_analyzer.rb
|
|
358
399
|
- app/services/rails_pulse/analysis/suggestion_generator.rb
|
|
400
|
+
- app/services/rails_pulse/cloud/batch.rb
|
|
401
|
+
- app/services/rails_pulse/cloud/client.rb
|
|
402
|
+
- app/services/rails_pulse/cloud/combined_metrics.rb
|
|
403
|
+
- app/services/rails_pulse/cloud/health_item.rb
|
|
404
|
+
- app/services/rails_pulse/cloud/path_prefix.rb
|
|
405
|
+
- app/services/rails_pulse/cloud/preview.rb
|
|
406
|
+
- app/services/rails_pulse/cloud/query_shape.rb
|
|
407
|
+
- app/services/rails_pulse/cloud/record_items.rb
|
|
408
|
+
- app/services/rails_pulse/cloud/route_pattern.rb
|
|
409
|
+
- app/services/rails_pulse/cloud/summary_items.rb
|
|
410
|
+
- app/services/rails_pulse/cloud/sync.rb
|
|
411
|
+
- app/services/rails_pulse/config_recommendations.rb
|
|
412
|
+
- app/services/rails_pulse/deployment_comparison.rb
|
|
359
413
|
- app/services/rails_pulse/exception_capture_service.rb
|
|
360
414
|
- app/services/rails_pulse/exception_message_sanitizer.rb
|
|
361
415
|
- app/services/rails_pulse/operation_suggestions.rb
|
|
@@ -365,6 +419,7 @@ files:
|
|
|
365
419
|
- app/services/rails_pulse/operations/metric.rb
|
|
366
420
|
- app/services/rails_pulse/operations/series.rb
|
|
367
421
|
- app/services/rails_pulse/operations/subject.rb
|
|
422
|
+
- app/services/rails_pulse/period_insights.rb
|
|
368
423
|
- app/services/rails_pulse/query_analysis_service.rb
|
|
369
424
|
- app/services/rails_pulse/route_controller_action_backfiller.rb
|
|
370
425
|
- app/services/rails_pulse/route_merger.rb
|
|
@@ -373,6 +428,9 @@ files:
|
|
|
373
428
|
- app/services/rails_pulse/route_recognizer.rb
|
|
374
429
|
- app/services/rails_pulse/sql_query_normalizer.rb
|
|
375
430
|
- app/services/rails_pulse/summary_service.rb
|
|
431
|
+
- app/services/rails_pulse/summary_service/from_child_periods.rb
|
|
432
|
+
- app/services/rails_pulse/summary_service/from_raw_rows.rb
|
|
433
|
+
- app/services/rails_pulse/summary_service/metrics.rb
|
|
376
434
|
- app/services/rails_pulse/tag_filter_service.rb
|
|
377
435
|
- app/views/layouts/rails_pulse/_global_filters.html.erb
|
|
378
436
|
- app/views/layouts/rails_pulse/_menu_items.html.erb
|
|
@@ -455,6 +513,7 @@ files:
|
|
|
455
513
|
- app/views/rails_pulse/routes/_table.html.erb
|
|
456
514
|
- app/views/rails_pulse/routes/index.html.erb
|
|
457
515
|
- app/views/rails_pulse/routes/show.html.erb
|
|
516
|
+
- app/views/rails_pulse/shared/_aggregation_zone_badge.html.erb
|
|
458
517
|
- app/views/rails_pulse/shared/_deployment_markers_toggle.html.erb
|
|
459
518
|
- app/views/rails_pulse/shared/schema_outdated.html.erb
|
|
460
519
|
- app/views/rails_pulse/skeletons/_chart.html.erb
|
|
@@ -465,6 +524,7 @@ files:
|
|
|
465
524
|
- app/views/rails_pulse/tags/_tag_manager.html.erb
|
|
466
525
|
- config/importmap.rb
|
|
467
526
|
- config/routes.rb
|
|
527
|
+
- db/rails_pulse_cloud_schema.rb
|
|
468
528
|
- db/rails_pulse_migrate/20260417000001_add_diagnostic_fields.rb
|
|
469
529
|
- db/rails_pulse_migrate/20260419000001_add_p95_p99_duration_to_rails_pulse_jobs.rb
|
|
470
530
|
- db/rails_pulse_migrate/20260420000001_expand_normalized_query_column.rb
|
|
@@ -477,13 +537,18 @@ files:
|
|
|
477
537
|
- db/rails_pulse_migrate/20260610000002_change_rails_pulse_routes_to_multi_verb_model.rb
|
|
478
538
|
- db/rails_pulse_migrate/20260610000003_add_null_action_unique_index_to_routes.rb
|
|
479
539
|
- db/rails_pulse_migrate/20260823000001_add_location_to_exception_groups.rb
|
|
540
|
+
- db/rails_pulse_migrate/20260921000001_create_rails_pulse_events.rb
|
|
480
541
|
- db/rails_pulse_schema.rb
|
|
542
|
+
- exe/rails-pulse
|
|
481
543
|
- exe/rails_pulse_server
|
|
482
544
|
- lib/generators/rails_pulse/base_methods.rb
|
|
483
545
|
- lib/generators/rails_pulse/convert_to_migrations_generator.rb
|
|
546
|
+
- lib/generators/rails_pulse/install_cloud_generator.rb
|
|
484
547
|
- lib/generators/rails_pulse/install_generator.rb
|
|
485
548
|
- lib/generators/rails_pulse/schema_parser.rb
|
|
549
|
+
- lib/generators/rails_pulse/templates/db/rails_pulse_cloud_schema.rb
|
|
486
550
|
- lib/generators/rails_pulse/templates/db/rails_pulse_schema.rb
|
|
551
|
+
- lib/generators/rails_pulse/templates/migrations/install_rails_pulse_cloud_tables.rb
|
|
487
552
|
- lib/generators/rails_pulse/templates/migrations/install_rails_pulse_tables.rb
|
|
488
553
|
- lib/generators/rails_pulse/templates/migrations/upgrade_rails_pulse_tables.rb
|
|
489
554
|
- lib/generators/rails_pulse/templates/rails_pulse.rb
|
|
@@ -494,12 +559,45 @@ files:
|
|
|
494
559
|
- lib/rails_pulse/adapters/job_wrapper.rb
|
|
495
560
|
- lib/rails_pulse/adapters/sidekiq_middleware.rb
|
|
496
561
|
- lib/rails_pulse/cleanup_service.rb
|
|
562
|
+
- lib/rails_pulse/cli/agent_files/agents.md
|
|
563
|
+
- lib/rails_pulse/cli/agent_files/claude_skill.md
|
|
564
|
+
- lib/rails_pulse/cli/base_command.rb
|
|
565
|
+
- lib/rails_pulse/cli/client.rb
|
|
566
|
+
- lib/rails_pulse/cli/config.rb
|
|
567
|
+
- lib/rails_pulse/cli/configure.rb
|
|
568
|
+
- lib/rails_pulse/cli/coverage.rb
|
|
569
|
+
- lib/rails_pulse/cli/deployments.rb
|
|
570
|
+
- lib/rails_pulse/cli/exceptions.rb
|
|
571
|
+
- lib/rails_pulse/cli/formatter.rb
|
|
572
|
+
- lib/rails_pulse/cli/insights.rb
|
|
573
|
+
- lib/rails_pulse/cli/install.rb
|
|
574
|
+
- lib/rails_pulse/cli/job_runs.rb
|
|
575
|
+
- lib/rails_pulse/cli/jobs.rb
|
|
576
|
+
- lib/rails_pulse/cli/main.rb
|
|
577
|
+
- lib/rails_pulse/cli/mcp.rb
|
|
578
|
+
- lib/rails_pulse/cli/queries.rb
|
|
579
|
+
- lib/rails_pulse/cli/requests.rb
|
|
580
|
+
- lib/rails_pulse/cli/routes.rb
|
|
497
581
|
- lib/rails_pulse/configuration.rb
|
|
582
|
+
- lib/rails_pulse/current.rb
|
|
498
583
|
- lib/rails_pulse/engine.rb
|
|
499
584
|
- lib/rails_pulse/installers/config_installer.rb
|
|
500
585
|
- lib/rails_pulse/installers/config_updater.rb
|
|
501
586
|
- lib/rails_pulse/installers/migration_installer.rb
|
|
502
587
|
- lib/rails_pulse/job_run_collector.rb
|
|
588
|
+
- lib/rails_pulse/mcp/server.rb
|
|
589
|
+
- lib/rails_pulse/mcp/tools/coverage.rb
|
|
590
|
+
- lib/rails_pulse/mcp/tools/deployments.rb
|
|
591
|
+
- lib/rails_pulse/mcp/tools/endpoint.rb
|
|
592
|
+
- lib/rails_pulse/mcp/tools/errors.rb
|
|
593
|
+
- lib/rails_pulse/mcp/tools/exception_detail.rb
|
|
594
|
+
- lib/rails_pulse/mcp/tools/exceptions.rb
|
|
595
|
+
- lib/rails_pulse/mcp/tools/helpers.rb
|
|
596
|
+
- lib/rails_pulse/mcp/tools/insights.rb
|
|
597
|
+
- lib/rails_pulse/mcp/tools/jobs.rb
|
|
598
|
+
- lib/rails_pulse/mcp/tools/queries.rb
|
|
599
|
+
- lib/rails_pulse/mcp/tools/routes.rb
|
|
600
|
+
- lib/rails_pulse/mcp/tools/slow_requests.rb
|
|
503
601
|
- lib/rails_pulse/middleware/asset_server.rb
|
|
504
602
|
- lib/rails_pulse/middleware/request_collector.rb
|
|
505
603
|
- lib/rails_pulse/packaged_assets.rb
|
|
@@ -507,6 +605,7 @@ files:
|
|
|
507
605
|
- lib/rails_pulse/rack_compat.rb
|
|
508
606
|
- lib/rails_pulse/route_indexes.rb
|
|
509
607
|
- lib/rails_pulse/schema_check.rb
|
|
608
|
+
- lib/rails_pulse/scoped_inflector.rb
|
|
510
609
|
- lib/rails_pulse/standalone.rb
|
|
511
610
|
- lib/rails_pulse/statistics.rb
|
|
512
611
|
- lib/rails_pulse/stats/cleanup_stats_reporter.rb
|
|
@@ -551,7 +650,7 @@ metadata:
|
|
|
551
650
|
bug_tracker_uri: https://github.com/railspulse/rails_pulse/issues
|
|
552
651
|
rubygems_mfa_required: 'true'
|
|
553
652
|
post_install_message: |
|
|
554
|
-
Rails Pulse 0.
|
|
653
|
+
Rails Pulse 0.5.0.pre.2 installed.
|
|
555
654
|
|
|
556
655
|
UPGRADING from any 0.3.x? This release changes route identity and DROPS
|
|
557
656
|
rails_pulse_routes.method. Back up your database first, then run:
|
|
@@ -574,7 +673,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
574
673
|
requirements:
|
|
575
674
|
- - ">="
|
|
576
675
|
- !ruby/object:Gem::Version
|
|
577
|
-
version: 3.
|
|
676
|
+
version: 3.2.0
|
|
578
677
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
579
678
|
requirements:
|
|
580
679
|
- - ">="
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
PageTimings = Struct.new(
|
|
4
|
-
:start_time, :end_time,
|
|
5
|
-
:table_start_time, :table_end_time,
|
|
6
|
-
:zoom_start, :zoom_end,
|
|
7
|
-
:time_diff_hours, :start_duration,
|
|
8
|
-
:selected_time_range, :selected_response_range,
|
|
9
|
-
keyword_init: true
|
|
10
|
-
)
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
# ResponseRangeConcern
|
|
2
|
-
#
|
|
3
|
-
# Handles performance threshold filtering (slow, very_slow, critical).
|
|
4
|
-
# Converts symbolic threshold names to numeric values based on resource type.
|
|
5
|
-
# Supports both page-specific duration filters and global performance threshold filters.
|
|
6
|
-
module ResponseRangeConcern
|
|
7
|
-
extend ActiveSupport::Concern
|
|
8
|
-
include RansackParamsConcern
|
|
9
|
-
|
|
10
|
-
def setup_duration_range(type = :route)
|
|
11
|
-
thresholds = RailsPulse.configuration.public_send("#{type}_thresholds")
|
|
12
|
-
|
|
13
|
-
# Check all duration-related parameters
|
|
14
|
-
# avg_duration for Summary, duration for Request/Operation, duration_gteq for direct Ransack filtering
|
|
15
|
-
duration_param = ransack_params[:avg_duration] || ransack_params[:duration] || ransack_params[:duration_gteq]
|
|
16
|
-
|
|
17
|
-
# Priority 1: Page-specific duration filter
|
|
18
|
-
if duration_param.present?
|
|
19
|
-
selected_range = duration_param
|
|
20
|
-
start_duration =
|
|
21
|
-
case duration_param.to_sym
|
|
22
|
-
when :slow then thresholds[:slow]
|
|
23
|
-
when :very_slow then thresholds[:very_slow]
|
|
24
|
-
when :critical then thresholds[:critical]
|
|
25
|
-
else 0
|
|
26
|
-
end
|
|
27
|
-
# Priority 2: Global performance threshold filter
|
|
28
|
-
elsif (global_threshold = session_global_filters["performance_threshold"]).present?
|
|
29
|
-
selected_range = global_threshold.to_sym
|
|
30
|
-
start_duration =
|
|
31
|
-
case global_threshold.to_sym
|
|
32
|
-
when :slow then thresholds[:slow]
|
|
33
|
-
when :very_slow then thresholds[:very_slow]
|
|
34
|
-
when :critical then thresholds[:critical]
|
|
35
|
-
else 0
|
|
36
|
-
end
|
|
37
|
-
# Priority 3: No filter (show all)
|
|
38
|
-
else
|
|
39
|
-
start_duration = 0
|
|
40
|
-
selected_range = :all
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
[ start_duration, selected_range ]
|
|
44
|
-
end
|
|
45
|
-
end
|
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
# TimeRangeConcern
|
|
2
|
-
#
|
|
3
|
-
# Handles time range selection and filtering across all controllers.
|
|
4
|
-
# Supports multiple time range sources with priority order:
|
|
5
|
-
# 1. Page-specific preset/custom range (from dropdown/picker)
|
|
6
|
-
# 2. Chart zoom parameters
|
|
7
|
-
# 3. Time range selector (session)
|
|
8
|
-
# 4. Global filters (session)
|
|
9
|
-
# 5. Default time range
|
|
10
|
-
#
|
|
11
|
-
# Normalizes times to beginning/end of hour or day based on range duration.
|
|
12
|
-
module TimeRangeConcern
|
|
13
|
-
extend ActiveSupport::Concern
|
|
14
|
-
include RansackParamsConcern
|
|
15
|
-
|
|
16
|
-
included do
|
|
17
|
-
# Define the constant in the including class - ordered by most common usage
|
|
18
|
-
const_set(:TIME_RANGE_OPTIONS, [
|
|
19
|
-
[ "Last 24 hours", :last_24_hours ],
|
|
20
|
-
[ "Last 7 days", :last_7_days ],
|
|
21
|
-
[ "Last 14 days", :last_14_days ],
|
|
22
|
-
[ "Last 30 days", :last_30_days ],
|
|
23
|
-
[ "Custom range", :custom ]
|
|
24
|
-
].freeze)
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def default_time_range_key
|
|
28
|
-
:last_24_hours
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def setup_time_range
|
|
32
|
-
default_key = default_time_range_key
|
|
33
|
-
|
|
34
|
-
start_time = case default_key
|
|
35
|
-
when :last_24_hours then 1.day.ago
|
|
36
|
-
when :last_7_days then 1.week.ago
|
|
37
|
-
when :last_14_days then 2.weeks.ago
|
|
38
|
-
when :last_30_days then 1.month.ago
|
|
39
|
-
else 1.day.ago
|
|
40
|
-
end
|
|
41
|
-
end_time = Time.zone.now
|
|
42
|
-
selected_time_range = default_key
|
|
43
|
-
|
|
44
|
-
# Normalized up front so a symbol-keyed hash from a Marshal-backed session
|
|
45
|
-
# store reads the same as the string-keyed one the cookie store produces;
|
|
46
|
-
# anything unrecognized becomes nil and falls through to later priorities.
|
|
47
|
-
session_preference = RailsPulse::TimeRangePreference.normalize(session[:time_range_preference])
|
|
48
|
-
|
|
49
|
-
# Priority 1: Page-specific preset from dropdown (check this first!)
|
|
50
|
-
if ransack_params[:period_start_range].present? && ransack_params[:period_start_range].to_sym != :custom
|
|
51
|
-
# Predefined time range from dropdown
|
|
52
|
-
selected_time_range = ransack_params[:period_start_range]
|
|
53
|
-
|
|
54
|
-
start_time =
|
|
55
|
-
case selected_time_range.to_sym
|
|
56
|
-
when :last_24_hours then 1.day.ago
|
|
57
|
-
when :last_7_days then 1.week.ago
|
|
58
|
-
when :last_14_days then 2.weeks.ago
|
|
59
|
-
when :last_30_days then 1.month.ago
|
|
60
|
-
else 1.day.ago # Default fallback
|
|
61
|
-
end
|
|
62
|
-
# Priority 2: Page-specific custom datetime range from picker (only if period_start_range is :custom)
|
|
63
|
-
elsif ransack_params[:period_start_range].present? && ransack_params[:period_start_range].to_sym == :custom && ransack_params[:custom_date_range].present? && ransack_params[:custom_date_range].include?(" to ")
|
|
64
|
-
# Custom datetime range from custom range picker
|
|
65
|
-
dates = ransack_params[:custom_date_range].split(" to ")
|
|
66
|
-
custom_start = parse_time_param(dates[0].strip)
|
|
67
|
-
custom_end = parse_time_param(dates[1].strip)
|
|
68
|
-
if custom_start && custom_end
|
|
69
|
-
start_time = custom_start
|
|
70
|
-
end_time = custom_end
|
|
71
|
-
selected_time_range = :custom
|
|
72
|
-
end
|
|
73
|
-
# Priority 3: Page-specific filters (chart zoom)
|
|
74
|
-
elsif ransack_params[:occurred_at_gteq].present? && ransack_params[:occurred_at_lt].present?
|
|
75
|
-
# Custom time range from chart zoom
|
|
76
|
-
zoom_start = parse_time_param(ransack_params[:occurred_at_gteq])
|
|
77
|
-
zoom_end = parse_time_param(ransack_params[:occurred_at_lt])
|
|
78
|
-
if zoom_start && zoom_end
|
|
79
|
-
start_time = zoom_start
|
|
80
|
-
end_time = zoom_end
|
|
81
|
-
selected_time_range = :custom
|
|
82
|
-
end
|
|
83
|
-
# Priority 4: Time range selector (from session)
|
|
84
|
-
elsif RailsPulse::TimeRangePreference.custom?(session_preference)
|
|
85
|
-
# Custom range from time range selector
|
|
86
|
-
start_time = parse_time_param(session_preference["start_time"]) || start_time
|
|
87
|
-
end_time = parse_time_param(session_preference["end_time"]) || end_time
|
|
88
|
-
selected_time_range = :custom
|
|
89
|
-
elsif session_preference.is_a?(String) && session_preference.present?
|
|
90
|
-
# Preset from time range selector
|
|
91
|
-
selected_time_range = session_preference.to_sym
|
|
92
|
-
start_time =
|
|
93
|
-
case selected_time_range
|
|
94
|
-
when :last_24_hours then 1.day.ago
|
|
95
|
-
when :last_7_days then 1.week.ago
|
|
96
|
-
when :last_14_days then 2.weeks.ago
|
|
97
|
-
when :last_30_days then 1.month.ago
|
|
98
|
-
else start_time
|
|
99
|
-
end
|
|
100
|
-
# Priority 5: Global filters (from session)
|
|
101
|
-
elsif session_global_filters["start_time"].present? || session_global_filters["end_time"].present?
|
|
102
|
-
start_time = parse_time_param(session_global_filters["start_time"]) || start_time
|
|
103
|
-
end_time = parse_time_param(session_global_filters["end_time"]) || end_time
|
|
104
|
-
selected_time_range = :custom
|
|
105
|
-
end
|
|
106
|
-
# Priority 6: Default time range (already set above)
|
|
107
|
-
|
|
108
|
-
time_diff = (end_time.to_i - start_time.to_i) / 3600.0
|
|
109
|
-
|
|
110
|
-
# in_time_zone before rounding: a parsed custom-range string carries the
|
|
111
|
-
# server OS's local offset, not Time.zone, and beginning_of_day/_hour
|
|
112
|
-
# round in whatever offset the receiver has. Summary data is always
|
|
113
|
-
# bucketed by Time.zone, so without this the boundary can miss every
|
|
114
|
-
# summary row and render charts empty. No-op for already-Time.zone values.
|
|
115
|
-
start_time = start_time.in_time_zone
|
|
116
|
-
end_time = end_time.in_time_zone
|
|
117
|
-
|
|
118
|
-
if time_diff <= 25
|
|
119
|
-
start_time = start_time.beginning_of_hour
|
|
120
|
-
end_time = end_time.end_of_hour
|
|
121
|
-
else
|
|
122
|
-
start_time = start_time.beginning_of_day
|
|
123
|
-
end_time = end_time.end_of_day
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
# Convert selected_time_range to string for backward compatibility with tests
|
|
127
|
-
[ start_time.to_i, end_time.to_i, selected_time_range.to_s, time_diff ]
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
private
|
|
131
|
-
|
|
132
|
-
# Returns nil for anything that does not parse, so a hand-edited or stale
|
|
133
|
-
# value falls back to the default range instead of raising.
|
|
134
|
-
def parse_time_param(param)
|
|
135
|
-
case param
|
|
136
|
-
when Time, DateTime
|
|
137
|
-
param.in_time_zone
|
|
138
|
-
when String
|
|
139
|
-
return nil if param.blank?
|
|
140
|
-
|
|
141
|
-
# Parse as server local time (not UTC, not Time.zone)
|
|
142
|
-
# This ensures flatpickr datetime strings are interpreted in server's timezone
|
|
143
|
-
Time.parse(param).localtime
|
|
144
|
-
when Numeric
|
|
145
|
-
Time.zone.at(param)
|
|
146
|
-
else
|
|
147
|
-
nil
|
|
148
|
-
end
|
|
149
|
-
rescue ArgumentError, TypeError, RangeError
|
|
150
|
-
nil
|
|
151
|
-
end
|
|
152
|
-
end
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
# ZoomRangeConcern
|
|
2
|
-
#
|
|
3
|
-
# Handles chart zoom and column selection for filtering table data.
|
|
4
|
-
# When users zoom into a chart or click a chart column, this concern calculates
|
|
5
|
-
# the appropriate time boundaries for filtering the table while keeping the chart unchanged.
|
|
6
|
-
# Normalizes zoom times to hour/day boundaries based on the overall time range.
|
|
7
|
-
module ZoomRangeConcern
|
|
8
|
-
extend ActiveSupport::Concern
|
|
9
|
-
|
|
10
|
-
def setup_zoom_range(main_start_time, main_end_time)
|
|
11
|
-
# Extract column selection parameter (but don't delete it yet - we need it for the view)
|
|
12
|
-
selected_column_time = params[:selected_column_time]
|
|
13
|
-
|
|
14
|
-
# Extract zoom parameters from params (this removes them from params)
|
|
15
|
-
zoom_start = params.delete(:zoom_start_time)
|
|
16
|
-
zoom_end = params.delete(:zoom_end_time)
|
|
17
|
-
|
|
18
|
-
# Handle column selection with highest precedence for table filtering
|
|
19
|
-
if selected_column_time
|
|
20
|
-
column_start, column_end = normalize_column_time(selected_column_time.to_i, main_start_time, main_end_time)
|
|
21
|
-
table_start_time = column_start
|
|
22
|
-
table_end_time = column_end
|
|
23
|
-
# Don't set zoom times for column selection - let chart show full range
|
|
24
|
-
return [ zoom_start, zoom_end, table_start_time, table_end_time ]
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
# Normalize zoom times to beginning/end of day or hour like we do for main time range
|
|
28
|
-
if zoom_start && zoom_end
|
|
29
|
-
zoom_start, zoom_end = normalize_zoom_times(zoom_start.to_i, zoom_end.to_i)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# Calculate table times - use zoom if present, otherwise fallback to main times
|
|
33
|
-
table_start_time = zoom_start || main_start_time
|
|
34
|
-
table_end_time = zoom_end || main_end_time
|
|
35
|
-
|
|
36
|
-
[ zoom_start, zoom_end, table_start_time, table_end_time ]
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
private
|
|
40
|
-
|
|
41
|
-
def normalize_column_time(column_time, main_start_time, main_end_time)
|
|
42
|
-
# Convert from JavaScript milliseconds to Unix seconds
|
|
43
|
-
# Chart data uses milliseconds (timestamp * 1000), so divide by 1000 to get seconds
|
|
44
|
-
column_time_seconds = column_time / 1000
|
|
45
|
-
|
|
46
|
-
# Determine period type based on main time range (same logic as ChartTableConcern)
|
|
47
|
-
time_diff_hours = (main_end_time - main_start_time) / 3600.0
|
|
48
|
-
|
|
49
|
-
if time_diff_hours <= 25
|
|
50
|
-
# Hourly period - normalize to beginning/end of hour
|
|
51
|
-
column_time_obj = Time.zone&.at(column_time_seconds) || Time.at(column_time_seconds)
|
|
52
|
-
start_time = column_time_obj&.beginning_of_hour || column_time_obj
|
|
53
|
-
end_time = column_time_obj&.end_of_hour || column_time_obj
|
|
54
|
-
else
|
|
55
|
-
# Daily period - normalize to beginning/end of day
|
|
56
|
-
column_time_obj = Time.zone&.at(column_time_seconds) || Time.at(column_time_seconds)
|
|
57
|
-
start_time = column_time_obj&.beginning_of_day || column_time_obj
|
|
58
|
-
end_time = column_time_obj&.end_of_day || column_time_obj
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
[ start_time.to_i, end_time.to_i ]
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def normalize_zoom_times(start_time, end_time)
|
|
65
|
-
# Convert from JavaScript milliseconds to Unix seconds
|
|
66
|
-
# Chart data uses milliseconds (timestamp * 1000), so divide by 1000 to get seconds
|
|
67
|
-
start_time_seconds = start_time / 1000
|
|
68
|
-
end_time_seconds = end_time / 1000
|
|
69
|
-
|
|
70
|
-
time_diff = (end_time_seconds - start_time_seconds) / 3600.0
|
|
71
|
-
|
|
72
|
-
if time_diff <= 25
|
|
73
|
-
start_time_obj = Time.zone&.at(start_time_seconds) || Time.at(start_time_seconds)
|
|
74
|
-
end_time_obj = Time.zone&.at(end_time_seconds) || Time.at(end_time_seconds)
|
|
75
|
-
start_time = start_time_obj&.beginning_of_hour || start_time_obj
|
|
76
|
-
end_time = end_time_obj&.end_of_hour || end_time_obj
|
|
77
|
-
else
|
|
78
|
-
start_time_obj = Time.zone&.at(start_time_seconds) || Time.at(start_time_seconds)
|
|
79
|
-
end_time_obj = Time.zone&.at(end_time_seconds) || Time.at(end_time_seconds)
|
|
80
|
-
start_time = start_time_obj&.beginning_of_day || start_time_obj
|
|
81
|
-
end_time = end_time_obj&.end_of_day || end_time_obj
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
[ start_time.to_i, end_time.to_i ]
|
|
85
|
-
end
|
|
86
|
-
end
|