rails_error_dashboard 0.8.3 → 0.8.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 270ac48ebee51c2f68cab29abdbf1169b7db7d7b860bf1fc5a43883960cdc0c6
4
- data.tar.gz: 6def5b5a2bbcabffd1116f13607771f6923823dc65eec803e028ba911af85ec9
3
+ metadata.gz: ba282b251af897146a14dce9cbd14aae0032428b96bb8d274d7400db3b1386cd
4
+ data.tar.gz: 4d4de4a7d143fe4233ea283766f452018f0a057652620077579686c6a10b1cbe
5
5
  SHA512:
6
- metadata.gz: fd6984fc8ccb2a68f9543786ffd6157d1a975ed5d446a13e38b3a38b42cc93047117918186b7f3936c2ddc3a53c3609db63073abad5f25d02edba4961e7b1f30
7
- data.tar.gz: 55ba8d78b0d06176ac80e63919cd29a6ca94423d8880712c8fb82979a17741b5881878ef2351efd89c468fbb3d03c6411c82c5c4668a687f4f441b512c169814
6
+ metadata.gz: e794d0737d5c8381a8a127ff30ebea8023fbf3e9b73f089d2cde9832617f953a6a589481a954dad41e1a18c85400e36e3a04a8a3bac35eaedc35aa53cf3a3d87
7
+ data.tar.gz: b9cff40ccba8d4459e0fe829dbf43fd054c66ff3f2a28a15d0be334e84fe757fc02c1d34e326ab1956a5d6074474113951e42bfdd9f9ef43705a0cfae46c0165
@@ -12,6 +12,16 @@ module RailsErrorDashboard
12
12
 
13
13
  protect_from_forgery with: :exception
14
14
 
15
+ # Render pagination in the dashboard's own locale, not the host app's.
16
+ #
17
+ # Pagy stores its locale in Thread.current[:pagy_locale] and never resets it
18
+ # (pagy 43.6.1, modules/i18n/i18n.rb:24-31 — the "for the duration of a single
19
+ # request" comment is aspirational; nothing in the gem enforces it). A host app
20
+ # that sets a per-request locale leaves that value on the Puma thread, so a
21
+ # dashboard request landing on a recycled thread inherits whatever language the
22
+ # host last used — Russian on one refresh, Portuguese on the next (issue #148).
23
+ around_action :with_dashboard_locale
24
+
15
25
  # CRITICAL: Ensure dashboard errors never break the app
16
26
  # Catch all exceptions and render user-friendly error page
17
27
  # NOTE: rescue_from is checked in reverse declaration order (last = highest priority).
@@ -60,6 +70,49 @@ module RailsErrorDashboard
60
70
 
61
71
  private
62
72
 
73
+ # Set Pagy's locale for this request and restore whatever was there before.
74
+ #
75
+ # Two details are load-bearing:
76
+ #
77
+ # 1. The previous value is read from Thread.current directly, NOT from
78
+ # Pagy::I18n.locale. The getter coerces nil to "en", so restoring through
79
+ # it would stamp "en" onto a thread that started clean — making the
80
+ # dashboard a source of the very leak it is fixing.
81
+ # 2. around_action + ensure, not before_action. A before_action would strand
82
+ # the dashboard's locale on the thread for the host app's next request.
83
+ # The ensure also covers the rescue_from handlers above, which still
84
+ # render through the view layer.
85
+ def with_dashboard_locale
86
+ previous = Thread.current[:pagy_locale]
87
+ Pagy::I18n.locale = dashboard_pagy_locale
88
+ yield
89
+ ensure
90
+ Thread.current[:pagy_locale] = previous
91
+ end
92
+
93
+ def dashboard_pagy_locale
94
+ configured = RailsErrorDashboard.configuration.dashboard_locale.to_s.strip
95
+ return "en" if configured.empty?
96
+
97
+ self.class.resolved_pagy_locales[configured] ||= resolve_pagy_locale(configured)
98
+ rescue StandardError
99
+ "en"
100
+ end
101
+
102
+ # Pagy looks its dictionary up by exact filename AND by an exact top-level
103
+ # key inside that YAML, so "EN" finds en.yml but then reads a nil dictionary
104
+ # and raises mid-render. Match the shipped filenames case-insensitively and
105
+ # fall back to English for anything Pagy cannot serve.
106
+ def resolve_pagy_locale(configured)
107
+ available = Pagy::I18n.pathnames.flat_map { |dir| Dir.glob(dir.join("*.yml")) }
108
+ .map { |path| File.basename(path, ".yml") }
109
+ available.find { |locale| locale.casecmp?(configured) } || "en"
110
+ end
111
+
112
+ def self.resolved_pagy_locales
113
+ @resolved_pagy_locales ||= {}
114
+ end
115
+
63
116
  def render_dashboard_error(icon:, title:, message:, detail: nil, icon_style: nil, status: :internal_server_error)
64
117
  set_common_view_variables
65
118
  error_html = <<~ERB
@@ -490,6 +490,10 @@ module RailsErrorDashboard
490
490
  return
491
491
  end
492
492
 
493
+ # Distinguishes "gem not installed" from "installed but no rules matched"
494
+ # in the empty state — both otherwise render an identical blank page.
495
+ @rack_attack_missing = !defined?(::Rack::Attack)
496
+
493
497
  days = days_param(default: 30)
494
498
  @days = days
495
499
  result = Queries::RackAttackSummary.call(days, application_id: @current_application_id)
@@ -22,11 +22,21 @@
22
22
 
23
23
  <% if @unique_rules == 0 %>
24
24
  <div class="red-empty-state">
25
- <i class="bi bi-shield-check display-1 text-success mb-3"></i>
26
- <div class="red-empty-state-title">No Rate Limit Events Found</div>
27
- <p class="text-muted">
28
- No Rack Attack throttle, blocklist, or track events were recorded over the last <%= @days %> days.
29
- </p>
25
+ <% if @rack_attack_missing %>
26
+ <i class="bi bi-exclamation-triangle display-1 text-warning mb-3"></i>
27
+ <div class="red-empty-state-title">Rack Attack Is Not Installed</div>
28
+ <p class="text-muted">
29
+ Tracking is enabled, but the <code>rack-attack</code> gem is not loaded in this
30
+ application — so no events can be recorded. Add it to your Gemfile and configure
31
+ at least one rule, then events will appear here.
32
+ </p>
33
+ <% else %>
34
+ <i class="bi bi-shield-check display-1 text-success mb-3"></i>
35
+ <div class="red-empty-state-title">No Rate Limit Events Found</div>
36
+ <p class="text-muted">
37
+ No Rack Attack throttle, blocklist, or track events were recorded over the last <%= @days %> days.
38
+ </p>
39
+ <% end %>
30
40
  <div class="card mx-auto" style="max-width: 500px;">
31
41
  <div class="card-body text-start">
32
42
  <h6>How Rack Attack tracking works:</h6>
@@ -144,7 +144,7 @@
144
144
  icon: "bi-broadcast",
145
145
  color: "info",
146
146
  settings: {
147
- enable_rack_attack_tracking: { label: "Rack Attack Tracking", description: "Track throttle/blocklist events as breadcrumbs", type: :boolean },
147
+ enable_rack_attack_tracking: { label: "Rack Attack Tracking", description: "Record throttle/blocklist events to their own table", type: :boolean },
148
148
  enable_actioncable_tracking: { label: "ActionCable Tracking", description: "Track WebSocket channel events as breadcrumbs", type: :boolean },
149
149
  enable_activestorage_tracking: { label: "ActiveStorage Tracking", description: "Track uploads/downloads/deletes as breadcrumbs", type: :boolean }
150
150
  }
@@ -222,6 +222,11 @@ module RailsErrorDashboard
222
222
  # Dashboard UI appearance
223
223
  attr_accessor :accent_color # :crimson (default), :ruby, :ember, :violet
224
224
 
225
+ # Locale the dashboard renders in, independent of the host app's locale.
226
+ # Currently applies to Pagy pagination labels — the rest of the dashboard
227
+ # UI is not yet translated (default: "en").
228
+ attr_accessor :dashboard_locale
229
+
225
230
  # LLM-powered AI help (disabled unless provider and API key are configured)
226
231
  attr_accessor :llm_provider # :openai or :anthropic
227
232
  attr_accessor :llm_api_key # String or lambda/proc
@@ -433,6 +438,7 @@ module RailsErrorDashboard
433
438
 
434
439
  # Dashboard UI
435
440
  @accent_color = :crimson # :crimson, :ruby, :ember, :violet
441
+ @dashboard_locale = "en" # Pagy pagination labels; rest of the UI is English-only
436
442
 
437
443
  # LLM-powered AI help defaults - OFF until provider and API key are configured
438
444
  @llm_provider = ENV["RED_LLM_PROVIDER"]&.to_sym
@@ -590,6 +596,16 @@ module RailsErrorDashboard
590
596
  if rack_attack_flush_interval && rack_attack_flush_interval < 1
591
597
  errors << "rack_attack_flush_interval must be at least 1 (got: #{rack_attack_flush_interval})"
592
598
  end
599
+
600
+ # Warn rather than auto-disable: validation may run before the host's
601
+ # Rack::Attack initializer has loaded, so a missing constant here does
602
+ # not prove it will still be missing at after_initialize (when the
603
+ # subscriber actually registers). Auto-disabling would break that case.
604
+ unless defined?(::Rack::Attack)
605
+ warnings << "enable_rack_attack_tracking is enabled but the rack-attack gem " \
606
+ "does not appear to be loaded. No events will be recorded until " \
607
+ "Rack::Attack is installed and configured."
608
+ end
593
609
  end
594
610
 
595
611
  # Validate actioncable tracking requires breadcrumbs
@@ -1,3 +1,3 @@
1
1
  module RailsErrorDashboard
2
- VERSION = "0.8.3"
2
+ VERSION = "0.8.4"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_error_dashboard
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.3
4
+ version: 0.8.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anjan Jagirdar
@@ -530,7 +530,7 @@ metadata:
530
530
  funding_uri: https://github.com/sponsors/AnjanJ
531
531
  post_install_message: |
532
532
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
533
- RED (Rails Error Dashboard) v0.8.3
533
+ RED (Rails Error Dashboard) v0.8.4
534
534
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
535
535
 
536
536
  First install: