Skip to content

Commit

Permalink
enhancement: lazy_load on tabs (#3630)
Browse files Browse the repository at this point in the history
* enhancement: lazy_load on tabs

* lint

* dont lazy load when on form

* rm duplicated panel

* comment lazy load tab

* test

* lint
  • Loading branch information
Paul-Bob authored Feb 4, 2025
1 parent 6373da3 commit 24649f4
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 4 deletions.
5 changes: 5 additions & 0 deletions app/components/avo/tab_content_component.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<div class="space-y-12">
<% @tab.visible_items.each do |item| %>
<%= render Avo::Items::SwitcherComponent.new item: item, **@kwargs %>
<% end %>
</div>
6 changes: 6 additions & 0 deletions app/components/avo/tab_content_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# frozen_string_literal: true

class Avo::TabContentComponent < Avo::BaseComponent
prop :tab
prop :kwargs, kind: :**
end
14 changes: 10 additions & 4 deletions app/components/avo/tab_group_component.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,17 @@
<div class="border rounded-lg p-2 -mx-2 -my-2 lg:p-4 lg:-mx-4 lg:-my-3 space-y-4">
<%= render Avo::TabSwitcherComponent.new resource: resource, current_tab: visible_tabs.first, group: group, active_tab_name: tab.name, view: view %>
<% if !tab.is_empty? %>
<div class="space-y-12">
<% tab.visible_items.each do |item| %>
<%= render Avo::Items::SwitcherComponent.new resource: resource, item: item, index: index, form: form, view: @view %>
<% if tab.lazy_load && view.display? %>
<%= turbo_frame_tag tab.turbo_frame_id(parent: @group), **frame_args(tab) do %>
<% if is_not_loaded?(tab) %>
<%= render Avo::LoadingComponent.new(title: tab.name) %>
<% else %>
<%= render Avo::TabContentComponent.new tab:, resource:, index:, form:, view:%>
<% end %>
<% end %>
</div>
<% else %>
<%= render Avo::TabContentComponent.new tab:, resource:, index:, form:, view:%>
<% end %>
<% end %>
</div>
<% end %>
Expand Down
24 changes: 24 additions & 0 deletions app/components/avo/tab_group_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,30 @@ def render?
tabs_have_content? && visible_tabs.present?
end

def frame_args(tab)
args = {
target: :_top,
class: "block"
}

if is_not_loaded?(tab)
args[:loading] = :lazy
args[:src] = helpers.resource_path(
resource: @resource,
record: @resource.record,
keep_query_params: true,
active_tab_name: tab.name,
tab_turbo_frame: tab.turbo_frame_id(parent: @group)
)
end

args
end

def is_not_loaded?(tab)
params[:tab_turbo_frame] != tab.turbo_frame_id(parent: @group)
end

def tabs_have_content?
visible_tabs.present?
end
Expand Down
2 changes: 2 additions & 0 deletions lib/avo/resources/items/tab.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class Avo::Resources::Items::Tab
delegate :items, :add_item, to: :items_holder

attr_accessor :description
attr_reader :lazy_load

def initialize(name: nil, description: nil, view: nil, **args)
@name = name
Expand All @@ -18,6 +19,7 @@ def initialize(name: nil, description: nil, view: nil, **args)
@view = Avo::ViewInquirer.new view
@args = args
@visible = args[:visible]
@lazy_load = args[:lazy_load]

post_initialize if respond_to?(:post_initialize)
end
Expand Down
81 changes: 81 additions & 0 deletions spec/dummy/app/avo/resources/person.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,86 @@ def fields
as: :has_many,
hide_search_input: true,
description: "Default behaviour with link_to_child_resource disabled"

tabs do
tab "Employment" do
panel do
field :job_title, as: :heading do
"Software Engineer"
end

row do
field :company, stacked: true do
"TechCorp Inc."
end
field :department, stacked: true do
"Research & Development"
end
end

field :years_of_experience do
"7 Years"
end

sidebar do
field :employee_id do
"EMP123456"
end
field :supervisor do
"Jane Smith"
end
end
end
end

tab "Address", lazy_load: true do
panel do
field :address, as: :heading
row do
field :street_address, stacked: true do
"1234 Elm Street"
end
field :city, stacked: true do
"Los Angeles"
end
end

field :state do
"California"
end

sidebar do
field :phone_number do
"+1 (555) 123-4567"
end
field :zip_code do
"90001"
end
end
end
end

tab "Preferences" do
panel do
field :preferred_language do
"English"
end

field :theme_mode do
"Dark Mode"
end

field :notification_preference do
"Email & SMS"
end

sidebar do
field :timezone do
"Pacific Time (PST)"
end
end
end
end
end
end
end
49 changes: 49 additions & 0 deletions spec/system/avo/tabs_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -230,4 +230,53 @@

Avo.configuration.persistence = {driver: nil}
end

let!(:person) { create :person }

it "lazy_load" do
visit avo.resources_person_path(person)

scroll_to first_tab_group

# Find visible information from first default tab
field_wrapper = find('div[data-field-id="company"]')
label = field_wrapper.find('div[data-slot="label"]')
value = field_wrapper.find('div[data-slot="value"]')
expect(label.text.strip).to eq("COMPANY")
expect(value.text.strip).to eq("TechCorp Inc.")

# Expect text from preferences and employment tabs (not lazy loaded) to be visible
within(:css, '.block.hidden[data-tabs-target="tabPanel"][data-tab-id="Preferences"]', visible: :all) do
# Find the field wrapper for "Notification preference"
field_wrapper = find('div[data-field-id="notification_preference"]', visible: :all)

# Locate the label and value within the wrapper
label = field_wrapper.find('div[data-slot="label"]', visible: :all)
value = field_wrapper.find('div[data-slot="value"]', visible: :all)

expect(label.text(:all).strip).to eq("Notification preference")
expect(value.text(:all).strip).to eq("Email & SMS")
end

# Expect not to find field from lazy loaded tab
within(:css, '.block.hidden[data-tabs-target="tabPanel"][data-tab-id="Address"]', visible: :all) do
expect(page).not_to have_selector('div[data-field-id="phone_number"]', visible: :all)
end

find('a[data-selected="false"][data-tabs-tab-name-param="Address"]').click
wait_for_loaded

# Find the phone number from lazy loaded tab after clicking on it
within(:css, '.block[data-tabs-target="tabPanel"][data-tab-id="Address"]', visible: :all) do
# Find the field wrapper for "Phone number"
field_wrapper = find('div[data-field-id="phone_number"]', visible: :all)

# Locate the label and value within the wrapper
label = field_wrapper.find('div[data-slot="label"]', visible: :all)
value = field_wrapper.find('div[data-slot="value"]', visible: :all)

expect(label.text(:all).strip).to eq("Phone number")
expect(value.text(:all).strip).to eq("+1 (555) 123-4567")
end
end
end

0 comments on commit 24649f4

Please sign in to comment.