rails_event_viewer 0.3.1 → 0.4.1

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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +28 -0
  3. data/README.md +7 -0
  4. data/app/assets/stylesheets/rails_event_viewer/application.css +1 -1
  5. data/app/controllers/rails_event_viewer/application_controller.rb +1 -11
  6. data/app/controllers/rails_event_viewer/events_controller.rb +6 -6
  7. data/app/helpers/rails_event_viewer/application_helper.rb +21 -75
  8. data/app/models/rails_event_viewer/entry.rb +0 -26
  9. data/app/models/rails_event_viewer/page.rb +9 -0
  10. data/app/views/layouts/rails_event_viewer/application.html.erb +3 -4
  11. data/app/views/rails_event_viewer/analytics/overview.html.erb +11 -9
  12. data/app/views/rails_event_viewer/dashboard/index.html.erb +13 -13
  13. data/app/views/rails_event_viewer/event_types/index.html.erb +6 -6
  14. data/app/views/rails_event_viewer/event_types/show.html.erb +14 -14
  15. data/app/views/rails_event_viewer/events/_event_row.html.erb +8 -8
  16. data/app/views/rails_event_viewer/events/_filters_sidebar.html.erb +16 -14
  17. data/app/views/rails_event_viewer/events/index.html.erb +6 -6
  18. data/app/views/rails_event_viewer/events/show.html.erb +22 -22
  19. data/app/views/rails_event_viewer/groups/index.html.erb +7 -7
  20. data/app/views/rails_event_viewer/groups/show.html.erb +11 -11
  21. data/app/views/rails_event_viewer/shared/_navigation.html.erb +8 -14
  22. data/app/views/rails_event_viewer/shared/_pagination.html.erb +10 -10
  23. data/app/views/rails_event_viewer/shared/_stat_card.html.erb +5 -5
  24. data/db/migrate/20261002121337_create_rails_event_viewer_entries.rb +0 -1
  25. data/lib/generators/rails_event_viewer/install/templates/create_rails_event_viewer_entries.rb.erb +0 -1
  26. data/lib/generators/rails_event_viewer/install/templates/initializer.rb.erb +4 -0
  27. data/lib/rails_event_viewer/adapter.rb +0 -8
  28. data/lib/rails_event_viewer/adapters/active_record.rb +10 -44
  29. data/lib/rails_event_viewer/adapters/concerns/in_memory_filtering.rb +0 -7
  30. data/lib/rails_event_viewer/adapters/memory.rb +0 -4
  31. data/lib/rails_event_viewer/adapters/null.rb +0 -8
  32. data/lib/rails_event_viewer/adapters/redis.rb +3 -17
  33. data/lib/rails_event_viewer/flusher.rb +5 -5
  34. data/lib/rails_event_viewer/logging.rb +1 -11
  35. data/lib/rails_event_viewer/version.rb +1 -1
  36. data/lib/rails_event_viewer.rb +6 -5
  37. metadata +7 -2
  38. data/app/assets/stylesheets/rails_event_viewer/tailwind.css +0 -29
@@ -4,8 +4,8 @@
4
4
  <!-- Header -->
5
5
  <div class="flex items-center justify-between">
6
6
  <div class="flex items-center space-x-4">
7
- <%= link_to rails_event_viewer.event_types_path, class: "text-gray-400 hover:text-gray-600" do %>
8
- <svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
7
+ <%= link_to rails_event_viewer.event_types_path, class: "text-gray-500 hover:text-gray-700", aria: { label: "Back to event types" } do %>
8
+ <svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
9
9
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
10
10
  </svg>
11
11
  <% end %>
@@ -38,7 +38,7 @@
38
38
  <!-- Events list -->
39
39
  <div class="bg-white shadow rounded-lg overflow-hidden">
40
40
  <div class="px-6 py-4 border-b border-gray-200">
41
- <h3 class="text-lg font-medium text-gray-900">Events</h3>
41
+ <h2 class="text-lg font-medium text-gray-900">Events</h2>
42
42
  </div>
43
43
 
44
44
  <% if @events.any? %>
@@ -46,17 +46,17 @@
46
46
  <table class="min-w-full divide-y divide-gray-200">
47
47
  <thead class="bg-gray-50">
48
48
  <tr>
49
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Payload</th>
50
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Tags</th>
51
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Time</th>
52
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Source</th>
49
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Payload</th>
50
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Tags</th>
51
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Time</th>
52
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Source</th>
53
53
  </tr>
54
54
  </thead>
55
55
  <tbody class="bg-white divide-y divide-gray-200">
56
56
  <% @events.each do |event| %>
57
- <tr class="hover:bg-gray-50 cursor-pointer" data-event-viewer-href="<%= rails_event_viewer.event_path(event_id(event)) %>">
57
+ <tr class="hover:bg-gray-50 cursor-pointer" data-event-viewer-href="<%= rails_event_viewer.event_path(event[:id]) %>">
58
58
  <td class="px-6 py-4">
59
- <%= link_to rails_event_viewer.event_path(event_id(event)) do %>
59
+ <%= link_to rails_event_viewer.event_path(event[:id]) do %>
60
60
  <code class="text-xs bg-gray-100 px-2 py-1 rounded"><%= truncate_json(event_payload(event), length: 80) %></code>
61
61
  <% end %>
62
62
  </td>
@@ -74,18 +74,18 @@
74
74
  <% end %>
75
75
  </div>
76
76
  <% else %>
77
- <span class="text-gray-400 text-sm">-</span>
77
+ <span class="text-gray-500 text-sm">-</span>
78
78
  <% end %>
79
79
  </td>
80
80
  <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
81
- <%= time_ago_with_title(event_occurred_at(event)) %>
81
+ <%= time_ago_with_title(event[:occurred_at]) %>
82
82
  </td>
83
83
  <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
84
- <% filepath = event_source_file(event) %>
84
+ <% filepath = event[:source_file] %>
85
85
  <% if filepath.present? %>
86
- <code class="text-xs"><%= event_short_filepath(event) %>:<%= event_source_line(event) %></code>
86
+ <code class="text-xs"><%= event_short_filepath(event) %>:<%= event[:source_line] %></code>
87
87
  <% else %>
88
- <span class="text-gray-400">-</span>
88
+ <span class="text-gray-500">-</span>
89
89
  <% end %>
90
90
  </td>
91
91
  </tr>
@@ -1,8 +1,8 @@
1
- <tr class="hover:bg-gray-50 cursor-pointer" data-event-viewer-href="<%= rails_event_viewer.event_path(event_id(event)) %>">
1
+ <tr class="hover:bg-gray-50 cursor-pointer" data-event-viewer-href="<%= rails_event_viewer.event_path(event[:id]) %>">
2
2
  <td class="px-6 py-4">
3
3
  <div class="flex flex-col max-w-md">
4
- <%= link_to event_name(event), rails_event_viewer.event_path(event_id(event)),
5
- title: event_name(event),
4
+ <%= link_to event[:name], rails_event_viewer.event_path(event[:id]),
5
+ title: event[:name],
6
6
  class: "inline-block max-w-full truncate px-2.5 py-0.5 rounded-full text-xs font-medium bg-indigo-100 text-indigo-800 w-fit" %>
7
7
  <div class="text-sm text-gray-500 mt-1 truncate">
8
8
  <code class="text-xs"><%= truncate_json(event_payload(event), length: 50) %></code>
@@ -23,20 +23,20 @@
23
23
  <% end %>
24
24
  </div>
25
25
  <% else %>
26
- <span class="text-gray-400 text-sm">-</span>
26
+ <span class="text-gray-500 text-sm">-</span>
27
27
  <% end %>
28
28
  </td>
29
29
  <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
30
- <%= time_ago_with_title(event_occurred_at(event)) %>
30
+ <%= time_ago_with_title(event[:occurred_at]) %>
31
31
  </td>
32
32
  <td class="px-6 py-4 text-sm text-gray-500">
33
- <% filepath = event_source_file(event) %>
33
+ <% filepath = event[:source_file] %>
34
34
  <% if filepath.present? %>
35
35
  <code class="text-xs bg-gray-100 px-2 py-1 rounded block truncate max-w-xs" title="<%= filepath %>">
36
- <%= truncate(event_short_filepath(event), length: 30) %>:<%= event_source_line(event) %>
36
+ <%= truncate(event_short_filepath(event), length: 30) %>:<%= event[:source_line] %>
37
37
  </code>
38
38
  <% else %>
39
- <span class="text-gray-400">-</span>
39
+ <span class="text-gray-500">-</span>
40
40
  <% end %>
41
41
  </td>
42
42
  </tr>
@@ -1,10 +1,9 @@
1
1
  <div class="bg-white rounded-lg shadow p-5 space-y-5">
2
- <h3 class="font-medium text-gray-900">Filters</h3>
2
+ <h2 class="font-medium text-gray-900">Filters</h2>
3
3
 
4
4
  <%= form_with url: rails_event_viewer.events_path, method: :get, class: "space-y-5" do |f| %>
5
5
  <%= f.hidden_field :q, value: @query if @query %>
6
6
 
7
- <!-- Event name filter -->
8
7
  <div>
9
8
  <label for="name" class="block text-sm font-medium text-gray-700 mb-2">Event Name</label>
10
9
  <%= f.select :name,
@@ -13,48 +12,51 @@
13
12
  class: "block w-full rounded-md border border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 py-2 px-3" %>
14
13
  </div>
15
14
 
16
- <!-- Date range -->
17
- <div>
18
- <label class="block text-sm font-medium text-gray-700 mb-2">Date Range</label>
15
+ <fieldset>
16
+ <legend class="block text-sm font-medium text-gray-700 mb-2">Date Range</legend>
19
17
  <div class="space-y-2">
20
18
  <%= f.date_field :start_date,
21
19
  value: @start_date,
22
20
  placeholder: "From",
21
+ aria: { label: "From date" },
23
22
  class: "block w-full rounded-md border border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 py-2 px-3" %>
24
23
  <%= f.date_field :end_date,
25
24
  value: @end_date,
26
25
  placeholder: "To",
26
+ aria: { label: "To date" },
27
27
  class: "block w-full rounded-md border border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 py-2 px-3" %>
28
28
  </div>
29
- </div>
29
+ </fieldset>
30
30
 
31
- <!-- Tag filter -->
32
- <div>
33
- <label class="block text-sm font-medium text-gray-700 mb-1">Tag</label>
31
+ <fieldset>
32
+ <legend class="block text-sm font-medium text-gray-700 mb-1">Tag</legend>
34
33
  <p class="text-xs text-gray-500 mb-2">Filter by event tags (e.g., env, user_id)</p>
35
34
  <%= f.text_field :tag_key,
36
35
  value: params[:tag_key],
37
36
  placeholder: "e.g., environment",
37
+ aria: { label: "Tag key" },
38
38
  class: "block w-full rounded-md border border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 py-2 px-3 mb-2" %>
39
39
  <%= f.text_field :tag_value,
40
40
  value: params[:tag_value],
41
41
  placeholder: "e.g., production",
42
+ aria: { label: "Tag value" },
42
43
  class: "block w-full rounded-md border border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 py-2 px-3" %>
43
- </div>
44
+ </fieldset>
44
45
 
45
- <!-- Context filter -->
46
- <div>
47
- <label class="block text-sm font-medium text-gray-700 mb-1">Context</label>
46
+ <fieldset>
47
+ <legend class="block text-sm font-medium text-gray-700 mb-1">Context</legend>
48
48
  <p class="text-xs text-gray-500 mb-2">Filter by request context (e.g., request_id)</p>
49
49
  <%= f.text_field :context_key,
50
50
  value: params[:context_key],
51
51
  placeholder: "e.g., request_id",
52
+ aria: { label: "Context key" },
52
53
  class: "block w-full rounded-md border border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 py-2 px-3 mb-2" %>
53
54
  <%= f.text_field :context_value,
54
55
  value: params[:context_value],
55
56
  placeholder: "e.g., abc-123",
57
+ aria: { label: "Context value" },
56
58
  class: "block w-full rounded-md border border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 py-2 px-3" %>
57
- </div>
59
+ </fieldset>
58
60
 
59
61
  <div class="flex space-x-3 pt-3">
60
62
  <%= f.submit "Apply",
@@ -29,10 +29,10 @@
29
29
  <table class="w-full divide-y divide-gray-200 table-fixed">
30
30
  <thead class="bg-gray-50">
31
31
  <tr>
32
- <th class="w-2/5 px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Event</th>
33
- <th class="w-1/5 px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Tags</th>
34
- <th class="w-1/5 px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Time</th>
35
- <th class="w-1/5 px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Source</th>
32
+ <th scope="col" class="w-2/5 px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Event</th>
33
+ <th scope="col" class="w-1/5 px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Tags</th>
34
+ <th scope="col" class="w-1/5 px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Time</th>
35
+ <th scope="col" class="w-1/5 px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Source</th>
36
36
  </tr>
37
37
  </thead>
38
38
  <tbody class="bg-white divide-y divide-gray-200">
@@ -46,10 +46,10 @@
46
46
  <%= render "rails_event_viewer/shared/pagination", pagination: @pagination %>
47
47
  <% else %>
48
48
  <div class="px-6 py-12 text-center text-gray-500">
49
- <svg class="mx-auto h-12 w-12 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
49
+ <svg aria-hidden="true" class="mx-auto h-12 w-12 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
50
50
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
51
51
  </svg>
52
- <h3 class="mt-2 text-sm font-medium text-gray-900">No events found</h3>
52
+ <h2 class="mt-2 text-sm font-medium text-gray-900">No events found</h2>
53
53
  <p class="mt-1 text-sm text-gray-500">
54
54
  <% if @filtered %>
55
55
  Try adjusting your filters or search query.
@@ -1,16 +1,16 @@
1
- <% content_for(:title, "#{event_name(@event)} - Rails Event Viewer") %>
1
+ <% content_for(:title, "#{@event[:name]} - Rails Event Viewer") %>
2
2
 
3
3
  <div class="space-y-6">
4
4
  <!-- Header -->
5
5
  <div class="flex items-center space-x-4">
6
- <%= link_to rails_event_viewer.events_path, class: "text-gray-400 hover:text-gray-600", aria: { label: "Back to events" } do %>
7
- <svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
6
+ <%= link_to rails_event_viewer.events_path, class: "text-gray-500 hover:text-gray-700", aria: { label: "Back to events" } do %>
7
+ <svg aria-hidden="true" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
8
8
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
9
9
  </svg>
10
10
  <% end %>
11
11
  <div class="min-w-0">
12
- <h1 class="text-2xl font-bold text-gray-900 break-words"><%= event_name(@event) %></h1>
13
- <p class="text-sm text-gray-500">Event ID: <%= event_id(@event) %></p>
12
+ <h1 class="text-2xl font-bold text-gray-900 break-words"><%= @event[:name] %></h1>
13
+ <p class="text-sm text-gray-500">Event ID: <%= @event[:id] %></p>
14
14
  </div>
15
15
  </div>
16
16
 
@@ -20,7 +20,7 @@
20
20
  <!-- Payload -->
21
21
  <div class="bg-white rounded-lg shadow">
22
22
  <div class="px-6 py-4 border-b border-gray-200 flex justify-between items-center">
23
- <h3 class="text-lg font-medium text-gray-900">Payload</h3>
23
+ <h2 class="text-lg font-medium text-gray-900">Payload</h2>
24
24
  <button type="button"
25
25
  data-event-viewer-copy="<%= JSON.generate(event_payload(@event)) %>"
26
26
  class="text-indigo-600 hover:text-indigo-500 text-sm font-medium">
@@ -34,7 +34,7 @@
34
34
  <%= json_tree(payload) %>
35
35
  </div>
36
36
  <% else %>
37
- <span class="text-gray-400">Empty payload</span>
37
+ <span class="text-gray-500">Empty payload</span>
38
38
  <% end %>
39
39
  </div>
40
40
  </div>
@@ -44,7 +44,7 @@
44
44
  <% if tags.present? %>
45
45
  <div class="bg-white rounded-lg shadow">
46
46
  <div class="px-6 py-4 border-b border-gray-200">
47
- <h3 class="text-lg font-medium text-gray-900">Tags</h3>
47
+ <h2 class="text-lg font-medium text-gray-900">Tags</h2>
48
48
  </div>
49
49
  <div class="p-6">
50
50
  <div class="font-mono text-sm break-words">
@@ -59,7 +59,7 @@
59
59
  <% if context.present? %>
60
60
  <div class="bg-white rounded-lg shadow">
61
61
  <div class="px-6 py-4 border-b border-gray-200">
62
- <h3 class="text-lg font-medium text-gray-900">Context</h3>
62
+ <h2 class="text-lg font-medium text-gray-900">Context</h2>
63
63
  </div>
64
64
  <div class="p-6">
65
65
  <div class="font-mono text-sm break-words">
@@ -75,7 +75,7 @@
75
75
  <!-- Metadata -->
76
76
  <div class="bg-white rounded-lg shadow">
77
77
  <div class="px-6 py-4 border-b border-gray-200">
78
- <h3 class="text-lg font-medium text-gray-900">Metadata</h3>
78
+ <h2 class="text-lg font-medium text-gray-900">Metadata</h2>
79
79
  </div>
80
80
  <dl class="divide-y divide-gray-200">
81
81
  <div class="px-6 py-4">
@@ -92,15 +92,15 @@
92
92
  </dd>
93
93
  </div>
94
94
  <% end %>
95
- <% filepath = event_source_file(@event) %>
95
+ <% filepath = @event[:source_file] %>
96
96
  <% if filepath.present? %>
97
97
  <div class="px-6 py-4">
98
98
  <dt class="text-sm font-medium text-gray-500">Source Location</dt>
99
99
  <dd class="mt-1 text-sm text-gray-900">
100
100
  <code class="bg-gray-100 px-2 py-1 rounded text-xs break-all">
101
- <%= filepath %>:<%= event_source_line(@event) %>
101
+ <%= filepath %>:<%= @event[:source_line] %>
102
102
  </code>
103
- <% label = event_source_label(@event) %>
103
+ <% label = @event[:source_label] %>
104
104
  <% if label.present? %>
105
105
  <div class="mt-1 text-gray-600 text-xs"><%= label %></div>
106
106
  <% end %>
@@ -114,18 +114,18 @@
114
114
  <% if @related_events.any? %>
115
115
  <div class="bg-white rounded-lg shadow">
116
116
  <div class="px-6 py-4 border-b border-gray-200">
117
- <h3 class="text-lg font-medium text-gray-900">Related Events</h3>
117
+ <h2 class="text-lg font-medium text-gray-900">Related Events</h2>
118
118
  <p class="text-xs text-gray-500">Same request context</p>
119
119
  </div>
120
120
  <ul class="divide-y divide-gray-200">
121
121
  <% @related_events.each do |related| %>
122
122
  <li class="px-6 py-3 hover:bg-gray-50">
123
- <%= link_to rails_event_viewer.event_path(event_id(related)), class: "block" do %>
123
+ <%= link_to rails_event_viewer.event_path(related[:id]), class: "block" do %>
124
124
  <div class="text-sm font-medium text-indigo-600 hover:text-indigo-500">
125
- <%= event_name(related) %>
125
+ <%= related[:name] %>
126
126
  </div>
127
127
  <div class="text-xs text-gray-500">
128
- <%= time_ago_with_title(event_occurred_at(related)) %>
128
+ <%= time_ago_with_title(related[:occurred_at]) %>
129
129
  </div>
130
130
  <% end %>
131
131
  </li>
@@ -137,16 +137,16 @@
137
137
  <!-- Quick Links -->
138
138
  <div class="bg-white rounded-lg shadow">
139
139
  <div class="px-6 py-4 border-b border-gray-200">
140
- <h3 class="text-lg font-medium text-gray-900">Quick Links</h3>
140
+ <h2 class="text-lg font-medium text-gray-900">Quick Links</h2>
141
141
  </div>
142
142
  <div class="p-4 space-y-2">
143
- <%= link_to rails_event_viewer.events_path(name: event_name(@event)),
143
+ <%= link_to rails_event_viewer.events_path(name: @event[:name]),
144
144
  class: "block text-sm text-indigo-600 hover:text-indigo-500" do %>
145
- View all "<%= event_name(@event) %>" events
145
+ View all "<%= @event[:name] %>" events
146
146
  <% end %>
147
- <%= link_to rails_event_viewer.event_type_path(name: event_name(@event)),
147
+ <%= link_to rails_event_viewer.event_type_path(name: @event[:name]),
148
148
  class: "block text-sm text-indigo-600 hover:text-indigo-500" do %>
149
- View "<%= event_name(@event) %>" event type
149
+ View "<%= @event[:name] %>" event type
150
150
  <% end %>
151
151
  </div>
152
152
  </div>
@@ -40,7 +40,7 @@
40
40
  <path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd" />
41
41
  </svg>
42
42
  <div class="ml-3">
43
- <h3 class="text-sm font-medium text-yellow-800">No group keys configured</h3>
43
+ <h2 class="text-sm font-medium text-yellow-800">No group keys configured</h2>
44
44
  <p class="mt-1 text-sm text-yellow-700">
45
45
  Configure group keys in your initializer:
46
46
  <code class="bg-yellow-100 px-1 rounded">config.group_keys = [:request_id, :order_id]</code>
@@ -53,13 +53,13 @@
53
53
  <table class="min-w-full divide-y divide-gray-200">
54
54
  <thead class="bg-gray-50">
55
55
  <tr>
56
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
56
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
57
57
  <%= @selected_key.to_s.titleize %>
58
58
  </th>
59
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Events</th>
60
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">First Event</th>
61
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Last Event</th>
62
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Duration</th>
59
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Events</th>
60
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">First Event</th>
61
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Last Event</th>
62
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Duration</th>
63
63
  </tr>
64
64
  </thead>
65
65
  <tbody class="bg-white divide-y divide-gray-200">
@@ -106,7 +106,7 @@
106
106
  <svg class="mx-auto h-12 w-12 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
107
107
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
108
108
  </svg>
109
- <h3 class="mt-2 text-sm font-medium text-gray-900">No groups found</h3>
109
+ <h2 class="mt-2 text-sm font-medium text-gray-900">No groups found</h2>
110
110
  <p class="mt-1 text-sm text-gray-500">
111
111
  No events with <code class="bg-gray-100 px-1 rounded"><%= @selected_key %></code> in their <%= @source %> data.
112
112
  </p>
@@ -4,7 +4,7 @@
4
4
  <!-- Header -->
5
5
  <div class="flex items-center justify-between">
6
6
  <div class="flex items-center space-x-4">
7
- <%= link_to rails_event_viewer.groups_path(key: @key, source: @source), class: "text-gray-400 hover:text-gray-600", aria: { label: "Back to groups" } do %>
7
+ <%= link_to rails_event_viewer.groups_path(key: @key, source: @source), class: "text-gray-500 hover:text-gray-700", aria: { label: "Back to groups" } do %>
8
8
  <svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
9
9
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
10
10
  </svg>
@@ -37,7 +37,7 @@
37
37
  <!-- Timeline -->
38
38
  <div class="bg-white shadow rounded-lg overflow-hidden">
39
39
  <div class="px-6 py-4 border-b border-gray-200">
40
- <h3 class="text-lg font-medium text-gray-900">Event Timeline</h3>
40
+ <h2 class="text-lg font-medium text-gray-900">Event Timeline</h2>
41
41
  <% if @first_event_at && @last_event_at %>
42
42
  <p class="text-sm text-gray-500">
43
43
  <%= @first_event_at.strftime("%Y-%m-%d %H:%M:%S") %> to <%= @last_event_at.strftime("%Y-%m-%d %H:%M:%S") %>
@@ -51,13 +51,13 @@
51
51
 
52
52
  <div class="divide-y divide-gray-100">
53
53
  <% @events.each_with_index do |event, index| %>
54
- <a href="<%= rails_event_viewer.event_path(event_id(event)) %>" class="relative pl-16 pr-6 py-4 hover:bg-gray-50 block">
54
+ <a href="<%= rails_event_viewer.event_path(event[:id]) %>" class="relative pl-16 pr-6 py-4 hover:bg-gray-50 block">
55
55
  <div class="absolute left-10 top-6 w-4 h-4 rounded-full border-2 border-indigo-500 bg-white"></div>
56
56
 
57
- <% if @first_event_at && event_occurred_at(event) %>
58
- <% offset = event_occurred_at(event) - @first_event_at %>
57
+ <% if @first_event_at && event[:occurred_at] %>
58
+ <% offset = event[:occurred_at] - @first_event_at %>
59
59
  <div class="absolute left-0 top-4 w-9 text-right">
60
- <span class="text-xs text-gray-400" title="<%= format_duration(offset) %> from start">
60
+ <span class="text-xs text-gray-500" title="<%= format_duration(offset) %> from start">
61
61
  <% if offset < 0.001 %>
62
62
  0
63
63
  <% elsif offset < 1 %>
@@ -75,7 +75,7 @@
75
75
  <div class="flex-1 min-w-0">
76
76
  <!-- Event name badge -->
77
77
  <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-indigo-100 text-indigo-800">
78
- <%= event_name(event) %>
78
+ <%= event[:name] %>
79
79
  </span>
80
80
 
81
81
  <!-- Payload preview -->
@@ -106,11 +106,11 @@
106
106
 
107
107
  <div class="ml-4 flex-shrink-0 text-right">
108
108
  <p class="text-sm text-gray-500">
109
- <%= time_ago_with_title(event_occurred_at(event)) %>
109
+ <%= time_ago_with_title(event[:occurred_at]) %>
110
110
  </p>
111
- <% if event_source_file(event).present? %>
112
- <p class="text-xs text-gray-400 mt-1">
113
- <%= event_short_filepath(event) %>:<%= event_source_line(event) %>
111
+ <% if event[:source_file].present? %>
112
+ <p class="text-xs text-gray-500 mt-1">
113
+ <%= event_short_filepath(event) %>:<%= event[:source_line] %>
114
114
  </p>
115
115
  <% end %>
116
116
  </div>
@@ -8,39 +8,33 @@
8
8
  <% end %>
9
9
  </div>
10
10
  <div class="ml-10 flex flex-wrap items-baseline space-x-4">
11
- <%= link_to "Dashboard", rails_event_viewer.root_path,
12
- class: nav_link_class("dashboard") %>
13
- <%= link_to "Events", rails_event_viewer.events_path,
14
- class: nav_link_class("events") %>
15
- <%= link_to "Event Types", rails_event_viewer.event_types_path,
16
- class: nav_link_class("event_types") %>
17
- <%= link_to "Groups", rails_event_viewer.groups_path,
18
- class: nav_link_class("groups") %>
11
+ <%= nav_link "Dashboard", rails_event_viewer.root_path, "dashboard" %>
12
+ <%= nav_link "Events", rails_event_viewer.events_path, "events" %>
13
+ <%= nav_link "Event Types", rails_event_viewer.event_types_path, "event_types" %>
14
+ <%= nav_link "Groups", rails_event_viewer.groups_path, "groups" %>
19
15
  <% if analytics_supported? %>
20
- <%= link_to "Analytics", rails_event_viewer.analytics_overview_path,
21
- class: nav_link_class("analytics") %>
16
+ <%= nav_link "Analytics", rails_event_viewer.analytics_overview_path, "analytics" %>
22
17
  <% end %>
23
18
  </div>
24
19
  </div>
25
20
 
26
21
  <div class="flex items-center space-x-4">
27
- <!-- Search -->
28
22
  <%= form_with url: rails_event_viewer.events_path, method: :get, class: "relative" do |f| %>
29
23
  <div class="relative">
30
24
  <div class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
31
- <svg class="h-4 w-4 text-indigo-200" fill="none" viewBox="0 0 24 24" stroke="currentColor">
25
+ <svg class="h-4 w-4 text-indigo-200" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
32
26
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
33
27
  </svg>
34
28
  </div>
35
29
  <%= f.search_field :q,
36
30
  value: params[:q],
37
31
  placeholder: "Search events...",
32
+ aria: { label: "Search events" },
38
33
  class: "w-64 rounded-md bg-indigo-500 py-2 pl-10 pr-3 text-sm text-white placeholder-indigo-200 focus:bg-white focus:text-gray-900 focus:placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-white" %>
39
34
  </div>
40
35
  <% end %>
41
36
 
42
- <!-- Timezone indicator -->
43
- <div class="text-indigo-200 text-sm" title="Current timezone">
37
+ <div class="text-indigo-200 text-sm" title="Times are shown in this time zone">
44
38
  <%= Time.zone.name %>
45
39
  </div>
46
40
  </div>
@@ -15,41 +15,41 @@
15
15
  <nav class="flex items-center space-x-1" aria-label="Pagination">
16
16
  <% if pagination.previous %>
17
17
  <%= link_to page_path(pagination.previous), class: "relative inline-flex items-center px-3 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md hover:bg-gray-50" do %>
18
- <svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
18
+ <svg aria-hidden="true" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
19
19
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
20
20
  </svg>
21
21
  <span class="ml-1">Prev</span>
22
22
  <% end %>
23
23
  <% else %>
24
24
  <span class="relative inline-flex items-center px-3 py-2 text-sm font-medium text-gray-300 bg-white border border-gray-200 rounded-md cursor-not-allowed">
25
- <svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
25
+ <svg aria-hidden="true" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
26
26
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
27
27
  </svg>
28
28
  <span class="ml-1">Prev</span>
29
29
  </span>
30
30
  <% end %>
31
31
 
32
- <% (1..pagination.pages).each do |page_num| %>
33
- <% if page_num == pagination.page %>
34
- <span class="relative inline-flex items-center px-3 py-2 text-sm font-medium text-white bg-indigo-600 border border-indigo-600 rounded-md"><%= page_num %></span>
35
- <% elsif page_num == 1 || page_num == pagination.pages || (page_num >= pagination.page - 2 && page_num <= pagination.page + 2) %>
36
- <%= link_to page_num, page_path(page_num), class: "relative inline-flex items-center px-3 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md hover:bg-gray-50" %>
37
- <% elsif page_num == pagination.page - 3 || page_num == pagination.page + 3 %>
32
+ <% pagination.window.each do |page_num| %>
33
+ <% if page_num == :gap %>
38
34
  <span class="relative inline-flex items-center px-2 py-2 text-sm font-medium text-gray-700">...</span>
35
+ <% elsif page_num == pagination.page %>
36
+ <span class="relative inline-flex items-center px-3 py-2 text-sm font-medium text-white bg-indigo-600 border border-indigo-600 rounded-md" aria-current="page"><%= page_num %></span>
37
+ <% else %>
38
+ <%= link_to page_num, page_path(page_num), class: "relative inline-flex items-center px-3 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md hover:bg-gray-50" %>
39
39
  <% end %>
40
40
  <% end %>
41
41
 
42
42
  <% if pagination.next %>
43
43
  <%= link_to page_path(pagination.next), class: "relative inline-flex items-center px-3 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md hover:bg-gray-50" do %>
44
44
  <span class="mr-1">Next</span>
45
- <svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
45
+ <svg aria-hidden="true" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
46
46
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
47
47
  </svg>
48
48
  <% end %>
49
49
  <% else %>
50
50
  <span class="relative inline-flex items-center px-3 py-2 text-sm font-medium text-gray-300 bg-white border border-gray-200 rounded-md cursor-not-allowed">
51
51
  <span class="mr-1">Next</span>
52
- <svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
52
+ <svg aria-hidden="true" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
53
53
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
54
54
  </svg>
55
55
  </span>
@@ -4,23 +4,23 @@
4
4
  <div class="flex-shrink-0">
5
5
  <% case icon %>
6
6
  <% when "database" %>
7
- <svg class="h-6 w-6 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
7
+ <svg aria-hidden="true" class="h-6 w-6 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
8
8
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4" />
9
9
  </svg>
10
10
  <% when "calendar" %>
11
- <svg class="h-6 w-6 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
11
+ <svg aria-hidden="true" class="h-6 w-6 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
12
12
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
13
13
  </svg>
14
14
  <% when "tag" %>
15
- <svg class="h-6 w-6 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
15
+ <svg aria-hidden="true" class="h-6 w-6 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
16
16
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" />
17
17
  </svg>
18
18
  <% when "clock" %>
19
- <svg class="h-6 w-6 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
19
+ <svg aria-hidden="true" class="h-6 w-6 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
20
20
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
21
21
  </svg>
22
22
  <% else %>
23
- <svg class="h-6 w-6 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
23
+ <svg aria-hidden="true" class="h-6 w-6 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
24
24
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
25
25
  </svg>
26
26
  <% end %>
@@ -18,7 +18,6 @@ class CreateRailsEventViewerEntries < ActiveRecord::Migration[8.1]
18
18
  t.timestamps
19
19
  end
20
20
 
21
- add_index :rails_event_viewer_entries, :name
22
21
  add_index :rails_event_viewer_entries, :occurred_at
23
22
  add_index :rails_event_viewer_entries, [:name, :occurred_at]
24
23
 
@@ -17,7 +17,6 @@ class CreateRailsEventViewerEntries < ActiveRecord::Migration<%= migration_versi
17
17
  t.timestamps
18
18
  end
19
19
 
20
- add_index :rails_event_viewer_entries, :name
21
20
  add_index :rails_event_viewer_entries, :occurred_at
22
21
  add_index :rails_event_viewer_entries, [:name, :occurred_at]
23
22
 
@@ -49,6 +49,10 @@ RailsEventViewer.configure do |config|
49
49
  # Useful for high-volume production environments
50
50
  # config.sample_rate = 1.0
51
51
 
52
+ # With async = false, events are written inside the transaction. By default a failed
53
+ # write aborts it. Set to false to run each write in a savepoint so host's own writes survive.
54
+ # config.transactional = true
55
+
52
56
  # ==========================================================================
53
57
  # General Configuration
54
58
  # ==========================================================================