Skip to content

Commit

Permalink
Refactor ui/table to use the internal objects instead of proxy ivars
Browse files Browse the repository at this point in the history
  • Loading branch information
elia committed Nov 24, 2023
1 parent 669ea89 commit 2e35075
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 63 deletions.
59 changes: 29 additions & 30 deletions admin/app/components/solidus_admin/ui/table/component.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<div role="search">
<%= render component("ui/table/toolbar").new("data-#{stimulus_id}-target": "searchToolbar", hidden: initial_mode != "search") do %>
<%= form_with(
url: @search_url,
url: @search.url,
method: :get,
html: {
id: search_form_id,
Expand All @@ -25,13 +25,13 @@
"data-action": "input->#{stimulus_id}#search change->#{stimulus_id}#search",
},
) do |form| %>
<%= hidden_field_tag scope_param_name, current_scope_name %>
<%= hidden_field_tag @search.scope_param_name, @search.current_scope.name if @search.scopes.present? %>
<%= render component('ui/forms/search_field').new(
name: "#{@search_param}[#{@search_key}]",
value: params.dig(@search_param, @search_key),
placeholder: t('.search_placeholder', resources: resource_plural_name),
name: @search.searchbar_param_name,
value: @search.value[@search.searchbar_key],
placeholder: t('.search_placeholder', resources: @data.plural_name),
"aria-label": t('.search_placeholder', resources: @data.plural_name),
"data-#{stimulus_id}-target": "searchField",
"aria-label": t('.search_placeholder', resources: resource_plural_name),
"data-turbo-permanent": "true",
id: "#{stimulus_id}-search-field-#{@id}",
) %>
Expand All @@ -46,27 +46,26 @@
</div>
<% end %>
<% if @filters.any? %>
<% if @search.filters.any? %>
<%= render component("ui/table/toolbar").new("data-#{stimulus_id}-target": "filterToolbar", hidden: initial_mode != "search") do %>
<% @filters.each_with_index do |filter, index| %>
<% @search.filters.each_with_index do |filter, index| %>
<%= render_ransack_filter_dropdown(filter, index) %>
<% end %>
<% end %>
<% end %>
<%= render component("ui/table/toolbar").new("data-#{stimulus_id}-target": "scopesToolbar", hidden: initial_mode != "scopes") do %>
<div class="flex-grow">
<%= form_with(url: @search_url, method: :get) do %>
<% @scopes.each do |scope| %>
<%= form_with(url: @search.url, method: :get) do %>
<% @search.scopes.each do |scope| %>
<%= render component("ui/tab").new(
tag: :button,
type: :submit,
text: scope.label,
current: current_scope_name == scope.name.to_s,
name: scope_param_name,
current: scope == @search.current_scope,
name: @search.scope_param_name,
value: scope.name,
) %>
<%#= render component("ui/tab").new(text: scope.label, current: current, href: scope.path) %>
<% end %>
<% end %>
</div>
Expand All @@ -82,15 +81,15 @@

<%= render component("ui/table/toolbar").new("data-#{stimulus_id}-target": "batchToolbar", role: "toolbar", "aria-label": t(".batch_actions"), hidden: true) do %>
<%= form_tag '', id: batch_actions_form_id %>
<% @batch_actions.each do |batch_action| %>
<% @data.batch_actions.each do |batch_action| %>
<%= render_batch_action_button(batch_action) %>
<% end %>
<% end %>
<%= turbo_frame_tag table_frame_id, target: "_top" do %>
<table class="table-fixed w-full border-collapse">
<colgroup>
<% @columns.each do |column| %>
<% @data.columns.each do |column| %>
<col <%= tag.attributes(**column.col) if column.col %>">
<% end %>
</colgroup>
Expand All @@ -100,13 +99,13 @@
data-<%= stimulus_id %>-target="defaultHeader"
>
<tr>
<% @columns.each do |column| %>
<% @data.columns.each do |column| %>
<%= render_header_cell(column.header) %>
<% end %>
</tr>
</thead>

<% if @batch_actions %>
<% if @data.batch_actions %>
<thead
data-<%= stimulus_id %>-target="batchHeader"
class="bg-white color-black text-xs leading-none text-left"
Expand All @@ -117,46 +116,46 @@
<%= render_header_cell(content_tag(:div, safe_join([
content_tag(:span, "0", "data-#{stimulus_id}-target": "selectedRowsCount"),
" #{t('.rows_selected')}.",
])), colspan: @columns.count - 1) %>
])), colspan: @data.columns.count - 1) %>
</tr>
</thead>
<% end %>

<tbody class="bg-white text-3.5 line-[150%] text-black">
<% @rows.each do |row| %>
<% @data.rows.each do |row| %>
<tr
class="border-b border-gray-100 last:border-0 hover:bg-gray-50 cursor-pointer <%= 'bg-gray-15 text-gray-700' if @row_fade&.call(row) %>"
<% if @row_url %>
class="border-b border-gray-100 last:border-0 hover:bg-gray-50 cursor-pointer <%= 'bg-gray-15 text-gray-700' if @data.fade&.call(row) %>"
<% if @data.url %>
data-action="click-><%= stimulus_id %>#rowClicked"
data-<%= stimulus_id %>-url-param="<%= @row_url.call(row) %>"
data-<%= stimulus_id %>-url-param="<%= @data.url.call(row) %>"
<% end %>
>
<% @columns.each do |column| %>
<% @data.columns.each do |column| %>
<%= render_data_cell(column, row) %>
<% end %>
</tr>
<% end %>
<% if @rows.empty? && @model_class %>
<% if @data.rows.empty? && @data.plural_name %>
<tr>
<td
colspan="<%= @columns.size %>"
colspan="<%= @data.columns.size %>"
class="text-center py-4 text-3.5 line-[150%] text-black bg-white rounded-b-lg"
>
<%= t('.no_resources_found', resources: resource_plural_name) %>
<%= t('.no_resources_found', resources: @data.plural_name) %>
</td>
</tr>
<% end %>
</tbody>

<% if @prev_page_link || @next_page_link %>
<% if @data.prev || @data.next %>
<tfoot>
<tr>
<td colspan="<%= @columns.size %>" class="py-4 bg-white rounded-b-lg border-t border-gray-100">
<td colspan="<%= @data.columns.size %>" class="py-4 bg-white rounded-b-lg border-t border-gray-100">
<div class="flex justify-center">
<%= render component('ui/table/pagination').new(
prev_link: @prev_page_link,
next_link: @next_page_link
prev_link: @data.prev,
next_link: @data.next
) %>
</div>
</td>
Expand Down
79 changes: 46 additions & 33 deletions admin/app/components/solidus_admin/ui/table/component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,36 +7,53 @@ class SolidusAdmin::UI::Table::Component < SolidusAdmin::BaseComponent
Scope = Struct.new(:name, :label, :default, keyword_init: true)
private_constant :BatchAction, :Column, :Filter, :Scope

Data = Struct.new(:rows, :class, :url, :prev, :next, :columns, :fade, :batch_actions, keyword_init: true) # rubocop:disable Lint/StructNewOverride
Search = Struct.new(:name, :value, :url, :searchbar_key, :filters, :scopes, keyword_init: true)
class Data < Struct.new(:rows, :class, :url, :prev, :next, :columns, :fade, :batch_actions, keyword_init: true) # rubocop:disable Lint/StructNewOverride
def initialize(**args)
super

self.columns = columns.map { |column| Column.new(wrap: false, **column) }
self.batch_actions = batch_actions.to_a.map { |action| BatchAction.new(**action) }
end

def plural_name
self[:class].model_name.human.pluralize if self[:class]
end
end

class Search < Struct.new(:name, :value, :url, :searchbar_key, :filters, :scopes, keyword_init: true)
def initialize(**args)
super

self.filters = filters.to_a.map { |filter| Filter.new(**filter) }
self.scopes = scopes.to_a.map { |scope| Scope.new(**scope) }
end

def current_scope
scopes.find { |scope| scope.name.to_s == value[:scope].presence } || default_scope
end

def default_scope
scopes.find(&:default)
end

def scope_param_name
"#{name}[scope]"
end

def searchbar_param_name
"#{name}[#{searchbar_key}]"
end

def value
super || {}
end
end

def initialize(id:, data:, search: nil)
@id = id
@data = Data.new(**data)
@data.columns.unshift selectable_column if @data.batch_actions.present?
@search = Search.new(**search)

# Data
@columns = @data.columns.map { Column.new(wrap: true, **_1) }
@columns.unshift selectable_column if @data.batch_actions.present?
@batch_actions = @data.batch_actions&.map { BatchAction.new(**_1) }
@model_class = data[:class]
@rows = @data.rows
@row_fade = @data.fade
@row_url = @data.url
@prev_page_link = @data.prev
@next_page_link = @data.next

# Search
@filters = @search.filters.map { Filter.new(**_1) }
@scopes = @search.scopes.map { Scope.new(**_1) }
@search_param = @search.name
@search_params = @search.value
@search_key = @search.searchbar_key
@search_url = @search.url
end

def resource_plural_name
@model_class.model_name.human.pluralize
end

def selectable_column
Expand Down Expand Up @@ -95,7 +112,7 @@ def render_batch_action_button(batch_action)
def render_ransack_filter_dropdown(filter, index)
render component("ui/table/ransack_filter").new(
presentation: filter.presentation,
search_param: @search_param,
search_param: @search.name,
combinator: filter.combinator,
attribute: filter.attribute,
predicate: filter.predicate,
Expand All @@ -107,7 +124,7 @@ def render_ransack_filter_dropdown(filter, index)

def render_header_cell(cell, **attrs)
cell = cell.call if cell.respond_to?(:call)
cell = @model_class.human_attribute_name(cell) if cell.is_a?(Symbol)
cell = @data[:class].human_attribute_name(cell) if cell.is_a?(Symbol)
cell = cell.render_in(self) if cell.respond_to?(:render_in)

content_tag(:th, cell, class: %{
Expand Down Expand Up @@ -135,14 +152,10 @@ def render_data_cell(column, data)
end

def current_scope_name
@current_scope_name ||= params.dig(@search_param, :scope).presence || @scopes.find(&:default)&.name&.to_s
end

def scope_param_name
@scope_param_name ||= "#{@search_param}[scope]"
@search.current_scope.name
end

def initial_mode
@initial_mode ||= params.dig(@search_param, @search_key) ? "search" : "scopes"
@initial_mode ||= @search.value[@search.searchbar_key] ? "search" : "scopes"
end
end

0 comments on commit 2e35075

Please sign in to comment.