Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: display backtrace on unrelated form errors #2905

Merged
merged 12 commits into from
Jun 28, 2024
2 changes: 1 addition & 1 deletion app/components/avo/alert_component.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
data-alert-dismiss-after-value="<%= Avo.configuration.alert_dismiss_time %>"
data-alert-remove-delay-value="0"
class="<%= classes %>"
>
>
<div class="px-2">
<div class="flex h-full">
<div class="flex items-center min-h-full">
Expand Down
2 changes: 1 addition & 1 deletion app/components/avo/alert_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def initialize(type, message)
end

def icon
return "heroicons/solid/x-circle" if is_error?
return "heroicons/solid/exclamation-circle" if is_error?
return "heroicons/solid/exclamation" if is_warning?
return "heroicons/solid/exclamation-circle" if is_info?
return "heroicons/solid/check-circle" if is_success?
Expand Down
26 changes: 26 additions & 0 deletions app/components/avo/backtrace_alert_component.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<div data-controller="alert"
data-alert-dismiss-after-value="<%= Avo.configuration.alert_dismiss_time %>"
data-alert-remove-delay-value="0"
class="w-full shadow-lg px-4 py-3 rounded relative border text-white pointer-events-auto bg-red-400 border-red-600"
>
<div class="px-2">
<div class="flex h-full">
<div class="flex items-center min-h-full">
<%= helpers.svg "heroicons/solid/exclamation-circle", class: "h-6" %>
</div>
<div class="ml-3 w-0 flex-1 pt-0.5">
<p class="text-sm leading-5 font-semibold">
<strong>Backtrace:</strong>
<pre class='overflow-y-scroll max-h-64 whitespace-pre-wrap text-xs'><%= @backtrace.join("\n") %></pre>
</p>
</div>
<div class="ml-4 flex-shrink-0 flex items-center">
<button data-action="alert#close" class="inline-flex text-white focus:outline-none focus:text-gray-300 transition ease-in-out duration-150">
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"/>
</svg>
</button>
</div>
</div>
</div>
</div>
13 changes: 13 additions & 0 deletions app/components/avo/backtrace_alert_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# frozen_string_literal: true

class Avo::BacktraceAlertComponent < ViewComponent::Base
include Avo::ApplicationHelper

def initialize(backtrace: nil)
@backtrace = backtrace
end

def render?
@backtrace.present?
end
end
1 change: 1 addition & 0 deletions app/controllers/avo/base_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ def perform_action_and_record_errors(&block)
# Example: When you save a license that should create a user for it and creating that user throws and error.
# Example: When you Try to delete a record and has a foreign key constraint.
exception_message = exception.message
@backtrace = exception.backtrace
end

# Add the errors from the record
Expand Down
20 changes: 1 addition & 19 deletions app/views/avo/base/create_fail_action.turbo_stream.erb
Original file line number Diff line number Diff line change
@@ -1,21 +1,3 @@
<%= turbo_stream.replace(frame_id(@resource), template: "avo/base/new") %>

<%= turbo_stream.append "alerts" do %>
<%= render Avo::FlashAlertsComponent.new flashes: flash %>
<% end %>

<% if @errors.any? %>
<%= turbo_stream.append("alerts") do %>
<% @errors.each do |message| %>
<%= render Avo::AlertComponent.new :error, message %>
<% end %>
<% end %>
<% end %>

<% if @record.errors.any? %>
<%= turbo_stream.append("alerts") do %>
<% @record.errors.full_messages.each do |message| %>
<%= render Avo::AlertComponent.new :error, message %>
<% end %>
<% end %>
<% end %>
<%= render partial: "avo/partials/all_alerts" %>
20 changes: 1 addition & 19 deletions app/views/avo/base/update_fail_action.turbo_stream.erb
Original file line number Diff line number Diff line change
@@ -1,21 +1,3 @@
<%= turbo_stream.replace(frame_id(@resource), template: "avo/base/edit") %>

<%= turbo_stream.append "alerts" do %>
<%= render Avo::FlashAlertsComponent.new flashes: flash %>
<% end %>

<% if @errors.any? %>
<%= turbo_stream.append("alerts") do %>
<% @errors.each do |message| %>
<%= render Avo::AlertComponent.new :error, message %>
<% end %>
<% end %>
<% end %>

<% if @record.errors.any? %>
<%= turbo_stream.append("alerts") do %>
<% @record.errors.full_messages.each do |message| %>
<%= render Avo::AlertComponent.new :error, message %>
<% end %>
<% end %>
<% end %>
<%= render partial: "avo/partials/all_alerts" %>
8 changes: 1 addition & 7 deletions app/views/avo/partials/_alerts.html.erb
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
<%= turbo_frame_tag :alerts, class: "fixed inset-0 bottom-0 flex flex-col space-y-4 items-end justify-right px-4 py-6 sm:p-6 justify-end z-[100] pointer-events-none" do %>
<%= render Avo::FlashAlertsComponent.new flashes: flash %>
<% # In case we have other general error messages %>
<% if @errors.present? %>
<% @errors.each do |message| %>
<%= render Avo::AlertComponent.new :error, message %>
<% end %>
<% end %>
<%= render partial: "avo/partials/all_alerts" %>
<% end %>
28 changes: 28 additions & 0 deletions app/views/avo/partials/_all_alerts.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<%= turbo_stream.append "alerts" do %>
<%= render Avo::FlashAlertsComponent.new flashes: flash %>
<% end %>

<%# Print out stack traces if we have any %>
<% if @record&.errors&.any? %>
<%= turbo_stream.append("alerts") do %>
<% @record.errors.full_messages.each do |message| %>
<%= render Avo::AlertComponent.new :error, message %>
<% end %>
<% end %>
<% end %>

<%# In case we have other general error messages %>
<% if @errors&.any? %>
<%= turbo_stream.append("alerts") do %>
<% @errors.each do |message| %>
<%= render Avo::AlertComponent.new :error, message %>
<% end %>
<% end %>
<% end %>

<%# In case we have a backtrace from an error %>
<% if @backtrace&.present? && Avo::Current.user_is_developer? %>
<%= turbo_stream.append("alerts") do %>
<%= render Avo::BacktraceAlertComponent.new backtrace: @backtrace %>
<% end %>
<% end %>
4 changes: 4 additions & 0 deletions lib/avo/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ class Configuration
attr_accessor :default_url_options
attr_accessor :click_row_to_view_record
attr_accessor :alert_dismiss_time
attr_accessor :is_admin_method
attr_accessor :is_developer_method
attr_accessor :search_results_count

def initialize
Expand Down Expand Up @@ -110,6 +112,8 @@ def initialize
@pagination = {}
@click_row_to_view_record = false
@alert_dismiss_time = 5000
@is_admin_method = :is_admin?
@is_developer_method = :is_developer?
@search_results_count = 8
end

Expand Down
12 changes: 12 additions & 0 deletions lib/avo/current.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,16 @@ def params
def request
view_context&.request || ActionDispatch::Request.empty
end

def user_is_admin?
return false unless user && user.respond_to?(Avo.configuration.is_admin_method)
adrianthedev marked this conversation as resolved.
Show resolved Hide resolved

user.send(Avo.configuration.is_admin_method)
end

def user_is_developer?
return false unless user && user.respond_to?(Avo.configuration.is_developer_method)
adrianthedev marked this conversation as resolved.
Show resolved Hide resolved

user.send(Avo.configuration.is_developer_method)
end
end
2 changes: 2 additions & 0 deletions lib/generators/avo/templates/initializer/avo.tt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ Avo.configure do |config|

## == Authentication ==
# config.current_user_method = {}
# config.is_admin_method = :is_admin
# config.is_developer_method = :is_developer
# config.authenticate_with do
# end

Expand Down
6 changes: 6 additions & 0 deletions spec/dummy/app/models/course.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ class Course < ApplicationRecord

validates :name, presence: true

# Used to test the backtrace alert
after_save do
raise "raised" if ENV['TEST_BACKTRACE_ALERT'] == "1"
adrianthedev marked this conversation as resolved.
Show resolved Hide resolved
# raise "raised"
end

def has_skills
true
end
Expand Down
4 changes: 4 additions & 0 deletions spec/dummy/app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,8 @@ def self.ransackable_attributes(auth_object = nil)
def accounts
[OpenStruct.new(id: 1, name: "Foo"), OpenStruct.new(id: 2, name: "Bar")]
end

def is_developer?
true
end
end
2 changes: 2 additions & 0 deletions spec/dummy/config/initializers/avo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

## == App context ==
config.current_user_method = :current_user
# config.is_admin_method = :is_admin?
# config.is_developer_method = :is_developer?
config.model_resource_mapping = {
User: "User"
}
Expand Down
19 changes: 19 additions & 0 deletions spec/system/avo/alert_backtrace_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
require 'rails_helper'
adrianthedev marked this conversation as resolved.
Show resolved Hide resolved
adrianthedev marked this conversation as resolved.
Show resolved Hide resolved

RSpec.describe "Alert Backtrace", type: :system do
before do
ENV['TEST_BACKTRACE_ALERT'] = '1'
adrianthedev marked this conversation as resolved.
Show resolved Hide resolved
adrianthedev marked this conversation as resolved.
Show resolved Hide resolved
adrianthedev marked this conversation as resolved.
Show resolved Hide resolved
adrianthedev marked this conversation as resolved.
Show resolved Hide resolved
end

it "responds with a backtrace alert" do
visit "/admin/resources/courses/new"

fill_in "Name", with: "Test"

save

expect(page).to have_text "raised"
expect(page).to have_text "Backtrace:"
expect(page).to have_text "/dummy/app/models/course.rb:25:in `block in <class:Course>'"
end
end
Loading