Skip to content

Commit 1d9a397

Browse files
authored
feat: add DeveloperWarningComponent for development/test environment warnings (#4383)
* feat: add DeveloperWarningComponent for development/test environment warnings Introduced a new DeveloperWarningComponent to display warnings when fields are declared directly inside a panel without a card wrapper. This component is rendered conditionally in development and test environments, providing helpful guidance to developers. Updated panel_component to utilize this new component and added corresponding tests for its functionality. * lint * fix code classes * comment docs for now * comment docs url
1 parent 796fd29 commit 1d9a397

6 files changed

Lines changed: 110 additions & 0 deletions

File tree

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<div
2+
class="<%= classes %>"
3+
data-tippy="tooltip"
4+
title="This warning is present only on development"
5+
>
6+
<div class="flex items-center min-h-6">
7+
<%= helpers.svg icon, class: "h-6 text-orange-600 dark:text-orange-300" %>
8+
</div>
9+
10+
<div class="flex-1 text-sm leading-5 font-semibold space-y-3">
11+
<div>
12+
<%= sanitize @message.to_s, sanitize_options %>
13+
</div>
14+
</div>
15+
</div>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# frozen_string_literal: true
2+
3+
class Avo::DeveloperWarningComponent < Avo::BaseComponent
4+
include Avo::ApplicationHelper
5+
6+
prop :message, kind: :positional
7+
8+
def render?
9+
Rails.env.development? || Rails.env.test?
10+
end
11+
12+
def classes
13+
"w-full flex items-start gap-3 rounded-lg border border-orange-600/40 bg-orange-50 px-4 py-3 text-orange-950 dark:border-orange-500/30 dark:bg-orange-950/30 dark:text-orange-50"
14+
end
15+
16+
def icon
17+
"tabler/filled/alert-triangle"
18+
end
19+
20+
def sanitize_options
21+
{
22+
tags: %w[a code br],
23+
attributes: %w[href target rel class]
24+
}
25+
end
26+
end

app/components/avo/items/panel_component.html.erb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
<%= render ui.panel(title: @item.title, description: @item.description, index: @index) do |panel| %>
22
<% panel.with_body do %>
3+
<% if fields_outside_card? %>
4+
<%= render Avo::DeveloperWarningComponent.new(card_background_warning_message) %>
5+
<% end %>
36
<%= render Avo::Items::VisibleItemsComponent.new resource: @resource, item: @item, view: @view, form: @form, parent_component: @parent_component, reflection: @reflection %>
47
<% end %>
58

app/components/avo/items/panel_component.rb

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,37 @@ class Avo::Items::PanelComponent < Avo::ResourceComponent
2121
:can_see_the_destroy_button?,
2222
:can_see_the_save_button?,
2323
to: :@parent_component
24+
25+
# Warn in development/test when a developer declares fields directly inside a `panel`
26+
# without wrapping them in a `card do ... end` block.
27+
#
28+
# This matters because cards are the thing that provides the consistent background/spacing.
29+
def fields_outside_card?
30+
return false unless Rails.env.development? || Rails.env.test?
31+
return false unless @item.respond_to?(:visible_items)
32+
return false if @item.respond_to?(:dev_warnings?) && !@item.dev_warnings?
33+
34+
@item.visible_items.any? do |item|
35+
# Direct field under the panel will render without card background.
36+
if item.is_field?
37+
true
38+
# Row is rendered directly by the panel too; it can contain fields rendered without card background.
39+
elsif item.is_row?
40+
item.visible_items.any?(&:is_field?)
41+
else
42+
false
43+
end
44+
end
45+
end
46+
47+
def card_background_warning_message
48+
# Keep the message deterministic for specs.
49+
# docs_url = "https://docs.avohq.io/4.0/resource-cards.html"
50+
docs_message = ""
51+
# docs_message = "See the <a href=\"#{docs_url}\" target=\"_blank\" rel=\"noopener\" class=\"underline underline-offset-2\">resource cards</a> docs."
52+
code_classes = "inline-flex items-center align-middle rounded bg-orange-500/10 px-1 py-px font-mono text-[0.85em] font-semibold leading-none text-orange-950 dark:bg-orange-500/15 dark:text-orange-50"
53+
disable_snippet = "<code class=\"#{code_classes}\">panel dev_warnings: false do ... end</code>"
54+
55+
"Some fields are declared directly inside a <code class=\"#{code_classes}\">panel</code> without a <code class=\"#{code_classes}\">card do ... end</code> wrapper. Wrap them in a <code class=\"#{code_classes}\">card</code> to get the expected card background and spacing. If this is intentional and you want to avoid this warning please use #{disable_snippet}. #{docs_message}"
56+
end
2457
end

lib/avo/resources/items/item_group.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ def initialize(title: nil, description: nil, view: nil, **args)
2323
post_initialize if respond_to?(:post_initialize)
2424
end
2525

26+
def dev_warnings?
27+
@args.fetch(:dev_warnings, true) != false
28+
end
29+
2630
class Builder
2731
include Avo::Concerns::BorrowItemsHolder
2832

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
require "rails_helper"
2+
3+
RSpec.describe Avo::DeveloperWarningComponent, type: :component do
4+
let(:message) { "Hello <a href='https://example.com'>link</a>" }
5+
6+
it "renders in test environment" do
7+
result = render_inline(described_class.new(message))
8+
9+
expect(result).to have_css('[data-tippy="tooltip"]')
10+
expect(result).to have_text("Hello link")
11+
end
12+
13+
it "renders in development environment" do
14+
allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new("development"))
15+
16+
result = render_inline(described_class.new(message))
17+
18+
expect(result).to have_css('[data-tippy="tooltip"]')
19+
expect(result).to have_text("Hello link")
20+
end
21+
22+
it "does not render in production environment" do
23+
allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new("production"))
24+
25+
result = render_inline(described_class.new(message))
26+
27+
expect(result.to_html.strip).to eq("")
28+
end
29+
end

0 commit comments

Comments
 (0)