solid_errors 0.4.2 → 0.5.0

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: 502b309733d074ca7a0d47c9207964de7316ec9b0fdb39530d987e4d8698aea7
4
- data.tar.gz: 1a81591573e559628e99360fffe6d2f727f519a68c6254339b089cf9f6b9da12
3
+ metadata.gz: ef3e4cca2bd412b918d7b7c36b3e754d79fefbc06e754a54fd58d5b04ef02a79
4
+ data.tar.gz: 1ca69a12aa28386778c66d7cd9114c06d20fbce1f846bf78391cfcad6796ff63
5
5
  SHA512:
6
- metadata.gz: 12642107e9c31caa1819026ae43d992ceae2449d07655ef3fff6569a258b18272c2c94098a1b0dc6028e8d71bb652a86a6a2030ce1b38afea90cc55e7d87735b
7
- data.tar.gz: ddd1e53133b7c2a7e04fd8a1fa53072d00838bfe901e58236b23870cc520551b431933eed72a1d07b4dcf6745addb481df1637486540d8b5201e784d2b41412a
6
+ metadata.gz: 1d5313d9fd88ce1d75bbd1faf09bd47bca8caaafd61ea7930f982e02b117957b11b077406c5c8109531d7d718a37ee344b136f9fbf483fe371271951ee137b55
7
+ data.tar.gz: cd5a876a317307109b4660e39b11be2e80b6fa2b7a5a33db00c3edac84bcf27d0a3dc777a2a3f49837411e4a3168483f2c57656bc18e6d24903d5106400a697c
data/README.md CHANGED
@@ -27,7 +27,7 @@
27
27
 
28
28
  Solid Errors is a DB-based, app-internal exception tracker for Rails applications, designed with simplicity and performance in mind. It uses the new [Rails error reporting API](https://guides.rubyonrails.org/error_reporting.html) to store uncaught exceptions in the database, and provides a simple UI for viewing and managing exceptions.
29
29
 
30
- > [!WARNING]
30
+ > [!WARNING]
31
31
  > The current point release of Rails (7.1.3.2) has a bug which severely limits the utility of Solid Errors. Exceptions raised during a web request *are not* reported to Rails' error reporter. There is a fix in the `main` branch, but it has not been released in a new point release. As such, Solid Errors is **not** production-ready unless you are running Rails from the `main` branch or until a new point version is released and you upgrade.
32
32
  > The original bug report can be found [here](https://github.com/rails/rails/issues/51002) and the pull request making the fix is [here](https://github.com/rails/rails/pull/51050). I will try to backport the fix into the gem directly, but I haven't quite figured it out yet.
33
33
 
@@ -69,6 +69,54 @@ Please consult the [official guides](https://guides.rubyonrails.org/error_report
69
69
 
70
70
  There are intentionally few features; you can view and resolve errors. That’s it. The goal is to provide a simple, lightweight, and performant solution for tracking exceptions in your Rails application. If you need more features, you should probably use a 3rd party service like [Honeybadger](https://www.honeybadger.io/), whose MIT-licensed [Ruby agent gem](https://github.com/honeybadger-io/honeybadger-ruby) provided a couple of critical pieces of code for this project.
71
71
 
72
+ ### Manually reporting an Error
73
+
74
+ Errors can be added to Solid Errors via the [Rails error reporter](https://guides.rubyonrails.org/error_reporting.html).
75
+
76
+ There are [three ways](https://guides.rubyonrails.org/error_reporting.html#using-the-error-reporter) you can use the error reporter:
77
+
78
+ `Rails.error.handle` will report any error raised within the block. It will then swallow the error, and the rest of your code outside the block will continue as normal.
79
+
80
+ ```ruby
81
+ result = Rails.error.handle do
82
+ 1 + '1' # raises TypeError
83
+ end
84
+ result # => nil
85
+ 1 + 1 # This will be executed
86
+ ```
87
+
88
+ `Rails.error.record` will report errors to all registered subscribers and then re-raise the error, meaning that the rest of your code won't execute.
89
+
90
+ ```ruby
91
+ Rails.error.record do
92
+ 1 + '1' # raises TypeError
93
+ end
94
+ 1 + 1 # This won't be executed
95
+ ```
96
+
97
+ You can also manually report errors by calling `Rails.error.report`:
98
+
99
+ ```ruby
100
+ begin
101
+ # code
102
+ rescue StandardError => e
103
+ Rails.error.report(e)
104
+ end
105
+ ```
106
+
107
+ All 3 reporting APIs (`#handle`, `#record`, and `#report`) support the following options, which are then passed along to all registered subscribers:
108
+
109
+ * `handled`: a Boolean to indicate if the error was handled. This is set to `true` by default. `#record` sets this to `false`.
110
+ * `severity`: a Symbol describing the severity of the error. Expected values are: `:error`, `:warning`, and `:info`. `#handle` sets this to `:warning`, while `#record` sets it to `:error`.
111
+ * `context`: a Hash to provide more context about the error, like request or user details
112
+ * `source`: a String about the source of the error. The default source is `"application"`. Errors reported by internal libraries may set other sources; the Redis cache library may use "redis_cache_store.active_support", for instance. Your subscriber can use the source to ignore errors you aren't interested in.
113
+
114
+ ```ruby
115
+ Rails.error.handle(context: { user_id: user.id }, severity: :info) do
116
+ # ...
117
+ end
118
+ ```
119
+
72
120
  ### Configuration
73
121
 
74
122
  You can configure Solid Errors via the Rails configuration object, under the `solid_errors` key. Currently, 6 configuration options are available:
@@ -132,7 +180,7 @@ Solid Errors _can_ send email notifications whenever an error occurs, if your ap
132
180
  There are two ways to configure email notifications. First, you can use environment variables:
133
181
 
134
182
  ```ruby
135
- ENV["SOLIDERRORS_SEND_EMAILS"] = true # defaults to true
183
+ ENV["SOLIDERRORS_SEND_EMAILS"] = true # defaults to false
136
184
  ENV["SOLIDERRORS_EMAIL_FROM"] = "errors@myapp.com" # defaults to "solid_errors@noreply.com"
137
185
  ENV["SOLIDERRORS_EMAIL_TO"] = "devs@myapp.com" # no default, must be set
138
186
  ```
@@ -2,14 +2,16 @@ module SolidErrors
2
2
  class ErrorsController < ApplicationController
3
3
  around_action :force_english_locale!
4
4
 
5
- before_action :set_error, only: %i[show update]
5
+ before_action :set_error, only: %i[show update destroy]
6
+
7
+ helper_method :error_scope
6
8
 
7
9
  # GET /errors
8
10
  def index
9
11
  errors_table = Error.arel_table
10
12
  occurrences_table = Occurrence.arel_table
11
-
12
- @errors = Error.unresolved
13
+ query_scope = error_scope.resolved? ? Error.resolved : Error.unresolved
14
+ @errors = query_scope
13
15
  .joins(:occurrences)
14
16
  .select(errors_table[Arel.star],
15
17
  occurrences_table[:created_at].maximum.as("recent_occurrence"),
@@ -21,7 +23,7 @@ module SolidErrors
21
23
  # GET /errors/1
22
24
  def show
23
25
  @page = Page.new(@error.occurrences, params)
24
- @occurrences = @error.occurrences.offset(@page.offset).limit(@page.items)
26
+ @occurrences = @error.occurrences.offset(@page.offset).limit(@page.items).order(created_at: :desc)
25
27
  end
26
28
 
27
29
  # PATCH/PUT /errors/1
@@ -30,6 +32,16 @@ module SolidErrors
30
32
  redirect_to errors_path, notice: "Error marked as resolved."
31
33
  end
32
34
 
35
+ # DELETE /errors/1
36
+ def destroy
37
+ if @error.resolved?
38
+ @error.destroy
39
+ redirect_to errors_path(scope: :resolved), notice: "Error deleted."
40
+ else
41
+ redirect_to error_path(@error), alert: "You must resolve the error before deleting it."
42
+ end
43
+ end
44
+
33
45
  private
34
46
 
35
47
  # Only allow a list of trusted parameters through.
@@ -44,5 +56,9 @@ module SolidErrors
44
56
  def force_english_locale!(&action)
45
57
  I18n.with_locale(:en, &action)
46
58
  end
59
+
60
+ def error_scope
61
+ ActiveSupport::StringInquirer.new(params[:scope] || "unresolved")
62
+ end
47
63
  end
48
64
  end
@@ -6,7 +6,7 @@ module SolidErrors
6
6
  @error = occurrence.error
7
7
 
8
8
  mail(
9
- subject: "#{@error.emoji} #{@error.exception_class}",
9
+ subject: "#{@error.severity_emoji} #{@error.exception_class}",
10
10
  from: SolidErrors.email_from,
11
11
  to: SolidErrors.email_to
12
12
  )
@@ -12,6 +12,14 @@ module SolidErrors
12
12
  warning: "bg-yellow-100 text-yellow-800",
13
13
  info: "bg-blue-100 text-blue-800"
14
14
  }
15
+ STATUS_TO_EMOJI = {
16
+ resolved: "✅",
17
+ unresolved: "⏳"
18
+ }
19
+ STATUS_TO_BADGE_CLASSES = {
20
+ resolved: "bg-green-100 text-green-800",
21
+ unresolved: "bg-violet-100 text-violet-800"
22
+ }
15
23
 
16
24
  has_many :occurrences, class_name: "SolidErrors::Occurrence", dependent: :destroy
17
25
 
@@ -22,12 +30,28 @@ module SolidErrors
22
30
  scope :resolved, -> { where.not(resolved_at: nil) }
23
31
  scope :unresolved, -> { where(resolved_at: nil) }
24
32
 
25
- def emoji
33
+ def severity_emoji
26
34
  SEVERITY_TO_EMOJI[severity.to_sym]
27
35
  end
28
36
 
29
- def badge_classes
37
+ def severity_badge_classes
30
38
  "px-2 inline-flex text-sm font-semibold rounded-md #{SEVERITY_TO_BADGE_CLASSES[severity.to_sym]}"
31
39
  end
40
+
41
+ def status
42
+ resolved? ? :resolved : :unresolved
43
+ end
44
+
45
+ def status_emoji
46
+ STATUS_TO_EMOJI[status]
47
+ end
48
+
49
+ def status_badge_classes
50
+ "px-2 inline-flex text-sm font-semibold rounded-md #{STATUS_TO_BADGE_CLASSES[status]}"
51
+ end
52
+
53
+ def resolved?
54
+ resolved_at.present?
55
+ end
32
56
  end
33
57
  end
@@ -617,6 +617,10 @@
617
617
  margin-bottom: 0.75rem
618
618
  }
619
619
 
620
+ .mb-6{
621
+ margin-bottom: 1.5rem
622
+ }
623
+
620
624
  .ml-6{
621
625
  margin-left: 1.5rem
622
626
  }
@@ -629,6 +633,10 @@
629
633
  margin-top: 1rem
630
634
  }
631
635
 
636
+ .-mb-px {
637
+ margin-bottom: -1px;
638
+ }
639
+
632
640
  .inline-block{
633
641
  display: inline-block
634
642
  }
@@ -743,6 +751,12 @@
743
751
  margin-bottom: calc(1.5rem * var(--tw-space-y-reverse))
744
752
  }
745
753
 
754
+ .space-x-8 > :not([hidden]) ~ :not([hidden]) {
755
+ --tw-space-x-reverse: 0;
756
+ margin-right: calc(2rem * var(--tw-space-x-reverse));
757
+ margin-left: calc(2rem * calc(1 - var(--tw-space-x-reverse)));
758
+ }
759
+
746
760
  .divide-y > :not([hidden]) ~ :not([hidden]){
747
761
  --tw-divide-y-reverse: 0;
748
762
  border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse)));
@@ -770,6 +784,10 @@
770
784
  border-radius: 0.25rem
771
785
  }
772
786
 
787
+ .rounded-md{
788
+ border-radius: 0.375rem
789
+ }
790
+
773
791
  .rounded-lg{
774
792
  border-radius: 0.5rem
775
793
  }
@@ -787,6 +805,10 @@
787
805
  border-bottom-width: 1px
788
806
  }
789
807
 
808
+ .border-b-2 {
809
+ border-bottom-width: 2px;
810
+ }
811
+
790
812
  .border-black{
791
813
  --tw-border-opacity: 1;
792
814
  border-color: rgb(0 0 0 / var(--tw-border-opacity))
@@ -802,11 +824,24 @@
802
824
  border-color: rgb(209 213 219 / var(--tw-border-opacity))
803
825
  }
804
826
 
827
+ .border-red-500{
828
+ --tw-border-opacity: 1;
829
+ border-color: rgb(239 68 68 / var(--tw-border-opacity))
830
+ }
831
+
832
+ .border-transparent {
833
+ border-color: transparent;
834
+ }
835
+
805
836
  .bg-gray-100{
806
837
  --tw-bg-opacity: 1;
807
838
  background-color: rgb(243 244 246 / var(--tw-bg-opacity))
808
839
  }
809
840
 
841
+ .bg-gray-600\/50{
842
+ background-color: rgb(75 85 99 / 0.5);
843
+ }
844
+
810
845
  .bg-green-50{
811
846
  --tw-bg-opacity: 1;
812
847
  background-color: rgb(240 253 244 / var(--tw-bg-opacity))
@@ -844,6 +879,11 @@
844
879
  padding-right: 0px
845
880
  }
846
881
 
882
+ .px-1 {
883
+ padding-left: 0.25rem;
884
+ padding-right: 0.25rem;
885
+ }
886
+
847
887
  .px-2{
848
888
  padding-left: 0.5rem;
849
889
  padding-right: 0.5rem
@@ -912,10 +952,6 @@
912
952
  padding-top: 1.75rem
913
953
  }
914
954
 
915
- .rounded-md{
916
- border-radius: 0.375rem
917
- }
918
-
919
955
  .text-left{
920
956
  text-align: left
921
957
  }
@@ -927,7 +963,7 @@
927
963
  .text-right{
928
964
  text-align: right
929
965
  }
930
-
966
+
931
967
  .text-black{
932
968
  --tw-text-opacity: 1;
933
969
  color: rgb(0 0 0 / var(--tw-text-opacity))
@@ -983,6 +1019,16 @@
983
1019
  background-color: rgb(254 249 195 / var(--tw-bg-opacity))
984
1020
  }
985
1021
 
1022
+ .bg-green-100{
1023
+ --tw-bg-opacity: 1;
1024
+ background-color: rgb(220 252 231 / var(--tw-bg-opacity))
1025
+ }
1026
+
1027
+ .bg-violet-100{
1028
+ --tw-bg-opacity: 1;
1029
+ background-color: rgb(237 233 254 / var(--tw-bg-opacity))
1030
+ }
1031
+
986
1032
  .text-blue-400{
987
1033
  --tw-text-opacity: 1;
988
1034
  color: rgb(96 165 250 / var(--tw-text-opacity))
@@ -1033,6 +1079,16 @@
1033
1079
  color: rgb(133 77 14 / var(--tw-text-opacity))
1034
1080
  }
1035
1081
 
1082
+ .text-green-800{
1083
+ --tw-text-opacity: 1;
1084
+ color: rgb(22 101 52 / var(--tw-text-opacity))
1085
+ }
1086
+
1087
+ .text-violet-800{
1088
+ --tw-text-opacity: 1;
1089
+ color: rgb(91 33 182 / var(--tw-text-opacity))
1090
+ }
1091
+
1036
1092
  .text-white{
1037
1093
  --tw-text-opacity: 1;
1038
1094
  color: rgb(255 255 255 / var(--tw-text-opacity))
@@ -1042,6 +1098,14 @@
1042
1098
  text-decoration-line: underline
1043
1099
  }
1044
1100
 
1101
+ .uppercase{
1102
+ text-transform: uppercase
1103
+ }
1104
+
1105
+ .whitespace-pre-wrap{
1106
+ white-space: pre-wrap
1107
+ }
1108
+
1045
1109
  .transition-opacity{
1046
1110
  transition-property: opacity;
1047
1111
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
@@ -1078,6 +1142,11 @@
1078
1142
  --tw-ring-color: rgb(229 231 235 / var(--tw-ring-opacity))
1079
1143
  }
1080
1144
 
1145
+ .hover\:ring-red-200:hover{
1146
+ --tw-ring-opacity: 1;
1147
+ --tw-ring-color: rgb(254 202 202 / var(--tw-ring-opacity))
1148
+ }
1149
+
1081
1150
  .hover\:bg-black:hover{
1082
1151
  --tw-bg-opacity: 1;
1083
1152
  background-color: rgb(0 0 0 / var(--tw-bg-opacity))
@@ -1088,6 +1157,16 @@
1088
1157
  color: rgb(255 255 255 / var(--tw-text-opacity))
1089
1158
  }
1090
1159
 
1160
+ .hover\:text-gray-700:hover {
1161
+ --tw-text-opacity: 1;
1162
+ color: rgb(55 65 81 / var(--tw-text-opacity));
1163
+ }
1164
+
1165
+ .hover\:border-gray-300:hover {
1166
+ --tw-border-opacity: 1;
1167
+ border-color: rgb(209 213 219 / var(--tw-border-opacity));
1168
+ }
1169
+
1091
1170
  @media (min-width: 640px){
1092
1171
  .sm\:mx-0{
1093
1172
  margin-left: 0px;
@@ -1,6 +1,6 @@
1
1
  <html>
2
2
  <head>
3
- <title>Solid Errors | <%= @error.emoji %> <%= @error.exception_class %></title>
3
+ <title>Solid Errors | <%= @error.severity_emoji %> <%= @error.exception_class %></title>
4
4
  <%= render "layouts/solid_errors/style" %>
5
5
  </head>
6
6
  <body>
@@ -1,16 +1,13 @@
1
1
  <div class="inline-flex items-center justify-start flex-wrap gap-3 whitespace-nowrap">
2
- <%= link_to errors_path, class: "inline-flex items-center justify-center gap-2 font-medium cursor-pointer border rounded-lg py-3 px-5 bg-gray-100 text-initial border-gray-300 hover:ring-gray-200 hover:ring-8" do %>
2
+ <%= link_to errors_path(scope: error.resolved? ? :resolved : :unresolved), class: "inline-flex items-center justify-center gap-2 font-medium cursor-pointer border rounded-lg py-3 px-5 bg-gray-100 text-initial border-gray-300 hover:ring-gray-200 hover:ring-8" do %>
3
3
  <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-left" viewBox="0 0 16 16">
4
4
  <path fill-rule="evenodd" d="M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8"/>
5
5
  </svg>
6
6
  <span>Back to errors</span>
7
7
  <% end %>
8
-
9
- <%= button_to error_path(error), method: :patch, class: "inline-flex items-center justify-center gap-2 font-medium cursor-pointer border rounded-lg py-3 px-5 bg-transparent text-blue-500 border-blue-500 hover:ring-blue-200 hover:ring-8", params: { error: { resolved_at: Time.now } } do %>
10
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-check2-circle" viewBox="0 0 16 16">
11
- <path d="M2.5 8a5.5 5.5 0 0 1 8.25-4.764.5.5 0 0 0 .5-.866A6.5 6.5 0 1 0 14.5 8a.5.5 0 0 0-1 0 5.5 5.5 0 1 1-11 0"/>
12
- <path d="M15.354 3.354a.5.5 0 0 0-.708-.708L8 9.293 5.354 6.646a.5.5 0 1 0-.708.708l3 3a.5.5 0 0 0 .708 0z"/>
13
- </svg>
14
- <span>Resolve Error<span class="sr-only"> #<%= error.id %></span></span>
8
+ <% if error.resolved? %>
9
+ <%= render 'solid_errors/errors/delete_button', error: error %>
10
+ <% else %>
11
+ <%= render 'solid_errors/errors/resolve_button', error: error %>
15
12
  <% end %>
16
13
  </div>
@@ -0,0 +1,7 @@
1
+ <%# locals: (error:) -%>
2
+ <%= button_to error_path(error), method: :delete, class: "inline-flex items-center justify-center gap-2 font-medium cursor-pointer border rounded-lg py-3 px-5 bg-transparent text-red-500 border-red-500 hover:ring-red-200 hover:ring-8" do %>
3
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" class="bi bi-trash3" fill="currentColor" viewBox="0 0 16 16">
4
+ <path d="M6.5 1h3a.5.5 0 0 1 .5.5v1H6v-1a.5.5 0 0 1 .5-.5M11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3A1.5 1.5 0 0 0 5 1.5v1H1.5a.5.5 0 0 0 0 1h.538l.853 10.66A2 2 0 0 0 4.885 16h6.23a2 2 0 0 0 1.994-1.84l.853-10.66h.538a.5.5 0 0 0 0-1zm1.958 1-.846 10.58a1 1 0 0 1-.997.92h-6.23a1 1 0 0 1-.997-.92L3.042 3.5zm-7.487 1a.5.5 0 0 1 .528.47l.5 8.5a.5.5 0 0 1-.998.06L5 5.03a.5.5 0 0 1 .47-.53Zm5.058 0a.5.5 0 0 1 .47.53l-.5 8.5a.5.5 0 1 1-.998-.06l.5-8.5a.5.5 0 0 1 .528-.47M8 4.5a.5.5 0 0 1 .5.5v8.5a.5.5 0 0 1-1 0V5a.5.5 0 0 1 .5-.5"/>
5
+ </svg>
6
+ <span>Delete <span class="sr-only">, Error #<%= error.id %></span></span>
7
+ <% end %>
@@ -3,7 +3,7 @@
3
3
  <%= tag.section id: dom_id(error), class: "space-y-6" do %>
4
4
  <div class="flex justify-between items-center">
5
5
  <%= tag.h1 class: "font-bold flex items-center text-2xl gap-2" do %>
6
- <%= error.emoji %>
6
+ <%= error.severity_emoji %>
7
7
  <code><%= error.exception_class %></code>
8
8
  from
9
9
  <em><code><%= error.source %></code></em>
@@ -14,9 +14,31 @@
14
14
  </small>
15
15
  </div>
16
16
 
17
- <pre class=""><%= error.message %></pre>
17
+ <pre class="whitespace-pre-wrap"><%= error.message %></pre>
18
18
 
19
19
  <dl class="flex-1 grid grid-cols-2 gap-x-4">
20
+ <div class="flex items-center justify-between flex-wrap gap-x-2">
21
+ <dt class="font-bold">
22
+ <%= SolidErrors::Error.human_attribute_name(:severity) %>
23
+ </dt>
24
+ <dd class="inline-flex items-center gap-1">
25
+ <%= error.severity_emoji %>
26
+ <span class="<%= error.severity_badge_classes %>">
27
+ <%= error.severity %>
28
+ </span>
29
+ </dd>
30
+ </div>
31
+ <div class="flex items-center justify-between flex-wrap gap-x-2">
32
+ <dt class="font-bold">
33
+ <%= SolidErrors::Error.human_attribute_name(:status) %>
34
+ </dt>
35
+ <dd class="inline-flex items-center gap-1">
36
+ <%= error.status_emoji %>
37
+ <span class="<%= error.status_badge_classes %>">
38
+ <%= error.status %>
39
+ </span>
40
+ </dd>
41
+ </div>
20
42
  <div class="flex items-center justify-between flex-wrap gap-x-2">
21
43
  <dt class="font-bold">
22
44
  <%= SolidErrors::Error.human_attribute_name(:first_seen) %>
@@ -41,14 +63,6 @@
41
63
  </abbr>
42
64
  </dd>
43
65
  </div>
44
- <div class="flex items-center justify-between flex-wrap gap-x-2">
45
- <dt class="font-bold">
46
- <%= SolidErrors::Error.human_attribute_name(:occurrences) %>
47
- </dt>
48
- <dd class="inline-flex items-center gap-1">
49
- <%= error.occurrences.size %>
50
- </dd>
51
- </div>
52
66
  <div class="flex items-center justify-between flex-wrap gap-x-2">
53
67
  <dt class="font-bold">
54
68
  <%= SolidErrors::Error.human_attribute_name(:exception_class) %>
@@ -57,17 +71,6 @@
57
71
  <code><%= error.exception_class %></code>
58
72
  </dd>
59
73
  </div>
60
- <div class="flex items-center justify-between flex-wrap gap-x-2">
61
- <dt class="font-bold">
62
- <%= SolidErrors::Error.human_attribute_name(:severity) %>
63
- </dt>
64
- <dd class="inline-flex items-center gap-1">
65
- <%= error.emoji %>
66
- <span class="<%= error.badge_classes %>">
67
- <%= error.severity %>
68
- </span>
69
- </dd>
70
- </div>
71
74
  <div class="flex items-center justify-between flex-wrap gap-x-2">
72
75
  <dt class="font-bold">
73
76
  <%= SolidErrors::Error.human_attribute_name(:source) %>
@@ -0,0 +1,8 @@
1
+ <%# locals: (error:) -%>
2
+ <%= button_to error_path(error), method: :patch, class: "inline-flex items-center justify-center gap-2 font-medium cursor-pointer border rounded-lg py-3 px-5 bg-transparent text-blue-500 border-blue-500 hover:ring-blue-200 hover:ring-8", params: { error: { resolved_at: Time.now } } do %>
3
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-check2-circle" viewBox="0 0 16 16">
4
+ <path d="M2.5 8a5.5 5.5 0 0 1 8.25-4.764.5.5 0 0 0 .5-.866A6.5 6.5 0 1 0 14.5 8a.5.5 0 0 0-1 0 5.5 5.5 0 1 1-11 0"/>
5
+ <path d="M15.354 3.354a.5.5 0 0 0-.708-.708L8 9.293 5.354 6.646a.5.5 0 1 0-.708.708l3 3a.5.5 0 0 0 .708 0z"/>
6
+ </svg>
7
+ <span>Resolve <span class="sr-only">, Error #<%= error.id %></span></span>
8
+ <% end %>
@@ -1,7 +1,8 @@
1
+ <%# locals: (error:) -%>
1
2
  <tr class="even:bg-gray-50 align-top">
2
3
  <td scope="col" class="whitespace-wrap py-4 pl-4 pr-3 font-medium text-gray-900 sm:pl-3">
3
4
  <div>
4
- <%= error.emoji %>
5
+ <%= error.severity_emoji %>
5
6
  <%= link_to error_path(error), class: "text-blue-400 underline inline-flex items-baseline gap-1" do %>
6
7
  <strong><code><%= error.exception_class %></code></strong>
7
8
  <% end %>
@@ -20,12 +21,10 @@
20
21
  </abbr>
21
22
  </td>
22
23
  <td class="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-3">
23
- <%= button_to error_path(error), method: :patch, class: "inline-flex items-center justify-center gap-2 font-medium cursor-pointer border rounded-lg py-3 px-5 bg-transparent text-blue-500 border-blue-500 hover:ring-blue-200 hover:ring-8", params: { error: { resolved_at: Time.now } } do %>
24
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-check2-circle" viewBox="0 0 16 16">
25
- <path d="M2.5 8a5.5 5.5 0 0 1 8.25-4.764.5.5 0 0 0 .5-.866A6.5 6.5 0 1 0 14.5 8a.5.5 0 0 0-1 0 5.5 5.5 0 1 1-11 0"/>
26
- <path d="M15.354 3.354a.5.5 0 0 0-.708-.708L8 9.293 5.354 6.646a.5.5 0 1 0-.708.708l3 3a.5.5 0 0 0 .708 0z"/>
27
- </svg>
28
- <span>Resolve<span class="sr-only">, Error #<%= error.id %></span></span>
24
+ <% if error.resolved? %>
25
+ <%= render 'solid_errors/errors/delete_button', error: error %>
26
+ <% else %>
27
+ <%= render 'solid_errors/errors/resolve_button', error: error %>
29
28
  <% end %>
30
29
  </td>
31
30
  </tr>
@@ -1,3 +1,25 @@
1
+ <div class="mb-6 border-b border-gray-300 flex justify-between items-baseline">
2
+ <h1 class="font-bold flex items-center text-2xl gap-2">
3
+ Errors
4
+ </h1>
5
+ <nav class="-mb-px flex space-x-8" aria-label="Tabs">
6
+ <%= link_to errors_path(scope: :unresolved), class: class_names(
7
+ "inline-flex items-center border-b-2 px-1 py-4 text-sm font-medium",
8
+ "border-blue-500 text-blue-500" => !error_scope.resolved?,
9
+ "border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700" => error_scope.resolved?) do %>
10
+ <span class="mr-2"><%= SolidErrors::Error::STATUS_TO_EMOJI[:unresolved] %></span>
11
+ <span>Unresolved</span>
12
+ <% end %>
13
+ <%= link_to errors_path(scope: :resolved), class: class_names(
14
+ "inline-flex items-center border-b-2 px-1 py-4 text-sm font-medium",
15
+ "border-blue-500 text-blue-500" => error_scope.resolved?,
16
+ "border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700" => !error_scope.resolved?) do %>
17
+ <span class="mr-2"><%= SolidErrors::Error::STATUS_TO_EMOJI[:resolved] %></span>
18
+ <span>Resolved</span>
19
+ <% end %>
20
+ </nav>
21
+ </div>
22
+
1
23
  <table class="min-w-full divide-y divide-gray-300">
2
24
  <thead>
3
25
  <tr>
@@ -49,7 +49,8 @@
49
49
 
50
50
  <div class="min-w-full">
51
51
  <% if occurrences.any? %>
52
- <%= render occurrences %>
52
+ <%= render partial: "solid_errors/occurrences/occurrence",
53
+ collection: occurrences, as: :occurrence %>
53
54
  <% else %>
54
55
  <div class="flex items-center justify-center gap-2">
55
56
  <%= bootstrap_svg "list-ul" %>
@@ -33,11 +33,11 @@
33
33
  <span class="text-gray-500">in</span>
34
34
  <code class="text-green-500 font-medium"><%= line.filtered_method %></code>
35
35
  <% else %>
36
- <span class="text-gray-500"><%= line.unparsed_line %>
36
+ <span class="text-gray-500"><%= line.unparsed_line %></span>
37
37
  <% end %>
38
38
  </summary>
39
- <div><pre class="flex overflow-auto rounded-b-lg bg-slate-800 p-4 text-sm leading-normal text-white sm:rounded-t-lg"><code class="flex flex-col min-h-full min-w-content px-0"><% line.source.each do |n, code| %>
40
- <div class="line"><span class="mr-2 text-right select-none text-gray-600"><%= n %></span><span><%= code %></span></div>
39
+ <div><pre class="flex overflow-auto rounded-b-lg bg-slate-800 p-4 text-sm leading-normal text-white sm:rounded-t-lg"><code class="flex flex-1 flex-col min-h-full min-w-content px-0"><% line.source.each do |n, code| %>
40
+ <div class="line <%= n == line.filtered_number.to_i ? 'bg-gray-600/50' : '' %>"><span class="mr-2 text-right select-none text-gray-600"><%= n %></span><span><%= code %></span></div>
41
41
  <% end %></code></pre></div>
42
42
  <% end %>
43
43
  <% end %>
data/config/routes.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  SolidErrors::Engine.routes.draw do
2
2
  get "/" => "errors#index", :as => :root
3
3
 
4
- resources :errors, only: [:index, :show, :update], path: ""
4
+ resources :errors, only: [:index, :show, :update, :destroy], path: ""
5
5
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolidErrors
4
- VERSION = "0.4.2"
4
+ VERSION = "0.5.0"
5
5
  end
data/lib/solid_errors.rb CHANGED
@@ -27,7 +27,7 @@ module SolidErrors
27
27
  end
28
28
 
29
29
  def send_emails?
30
- @send_emails ||= ENV["SOLIDERRORS_SEND_EMAILS"] || @@send_emails || true
30
+ @send_emails ||= ENV["SOLIDERRORS_SEND_EMAILS"] || @@send_emails || false
31
31
  end
32
32
 
33
33
  def email_from
metadata CHANGED
@@ -1,97 +1,97 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solid_errors
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen Margheim
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-04-10 00:00:00.000000000 Z
11
+ date: 2024-08-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionmailer
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '7.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '7.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: actionpack
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '7.0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '7.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: actionview
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '7.0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '7.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: activerecord
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '7.0'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '7.0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: activesupport
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - "~>"
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
75
  version: '7.0'
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - "~>"
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '7.0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: railties
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - "~>"
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
89
  version: '7.0'
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - "~>"
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '7.0'
97
97
  - !ruby/object:Gem::Dependency
@@ -130,7 +130,9 @@ files:
130
130
  - app/views/solid_errors/error_mailer/error_occurred.html.erb
131
131
  - app/views/solid_errors/error_mailer/error_occurred.text.erb
132
132
  - app/views/solid_errors/errors/_actions.html.erb
133
+ - app/views/solid_errors/errors/_delete_button.html.erb
133
134
  - app/views/solid_errors/errors/_error.html.erb
135
+ - app/views/solid_errors/errors/_resolve_button.html.erb
134
136
  - app/views/solid_errors/errors/_row.html.erb
135
137
  - app/views/solid_errors/errors/index.html.erb
136
138
  - app/views/solid_errors/errors/show.html.erb
@@ -167,7 +169,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
167
169
  - !ruby/object:Gem::Version
168
170
  version: '0'
169
171
  requirements: []
170
- rubygems_version: 3.5.1
172
+ rubygems_version: 3.5.17
171
173
  signing_key:
172
174
  specification_version: 4
173
175
  summary: Database-backed Rails error subscriber