Created
January 12, 2021 11:08
-
-
Save pythonandchips/c4aac663145324b9755c24f2b6ef383c to your computer and use it in GitHub Desktop.
View component data table
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="data-table"> | |
<%= form_with url: search_path, method: :get do |f| %> | |
<div class="data-table_controls"> | |
<div class="data-table_length"> | |
<%= f.label "page_size" do %> | |
Show | |
<%= f.select "page_size", options_for_select([10, 25, 50, 100], @collection.per_page) %> | |
entries | |
<% end %> | |
</div> | |
<div class="data-table_search"> | |
<%= f.label "search", "Search:" %> | |
<div class="input-group"> | |
<%= f.text_field "search", value: params.fetch(:search, ""), type: "search" %> | |
<%= f.submit "Go", class: "btn btn-primary" %> | |
</div> | |
</div> | |
</div> | |
<div class="data-table_controls"> | |
<div class="data-table_filter"> | |
<%= f.hidden_field "filter", value: params.fetch(:filter, "all") %> | |
<% @filters.each do |key, text| %> | |
<%= link_to text, filter_link(key), class: filter_class(key) %> | |
<% end %> | |
</div> | |
</div> | |
<% end %> | |
<table class="data-table_content"> | |
<thead> | |
<tr> | |
<% @columns.each do |column, config| %> | |
<th class="<%= ordering_class(column, config) %> "> | |
<% if config[:sort] %> | |
<%= link_to column.to_s.titleize, sort_link(column, config) %> | |
<% else %> | |
<span><%= column.to_s.titleize %></span> | |
<% end %> | |
</th> | |
<% end %> | |
<% if show_links? %> | |
<th> </th> | |
<% end %> | |
</tr> | |
</thead> | |
<tbody> | |
<% @collection.each do |item| %> | |
<tr> | |
<% @columns.each do |column, config| %> | |
<td><%= display_value(item, column, config) %></td> | |
<% end %> | |
<% if show_links? %> | |
<td> | |
<% @links.each do |name, format| %> | |
<%= link_to name.to_s.titleize, format.call(item) %> | |
<% end %> | |
</td> | |
<% end %> | |
</tr> | |
<% end %> | |
</tbody> | |
</table> | |
<div class="data-table_footer"> | |
<div class="data-table_summary"> | |
<span>Showing <%= start_number %> to <%= end_number %> of <%= @collection.count %> entries</span> | |
</div> | |
<%= render(UI::Paging, collection: @collection, class_name: ["data-table_paging"]) %> | |
</div> | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
require "uri_address" | |
module UI | |
class DataTable < ActionView::Component::Base | |
def initialize( | |
columns:, | |
collection:, | |
sorting:, | |
filters:, | |
links: | |
) | |
@columns = columns | |
@collection = collection | |
@sorting = sorting | |
@links = links | |
@filters = filters | |
end | |
def display_value(item, column, config) | |
v = item.send(column) | |
formatting = config.fetch(:format, proc { |value| value }) | |
formatting.call(v) | |
end | |
def show_links? | |
@links.length.present? | |
end | |
def start_number | |
[((@collection.current_page - 1) * @collection.per_page) + 1, @collection.count].min | |
end | |
def end_number | |
page_end = (start_number + @collection.per_page) - 1 | |
[page_end, @collection.count].min | |
end | |
def ordering_class(column, config) | |
return "" unless config[:sort] | |
order_field = @collection.order_values.first.expr.name | |
order_direction = @collection.order_values.first.direction | |
classes = ["data-table_sorting"] | |
classes << order_direction.to_s if order_field.to_s == column.to_s | |
classes.join(" ") | |
end | |
def sort_link(column, _config) | |
uri = UriAddress.new(request_url) | |
uri.query_param("order", column) | |
uri.query_param("direction", sort_direction(column)) | |
uri.to_s | |
end | |
def search_path | |
uri = UriAddress.new(request_url) | |
uri.query_param("filter", params.fetch(:filter, "all")) | |
uri.query_param("order", order_field) | |
uri.query_param("direction", order_direction) | |
uri.remove_query_param("page_no") | |
uri.to_s | |
end | |
def filter_link(key) | |
uri = UriAddress.new(request_url) | |
uri.query_param("filter", key) | |
uri.to_s | |
end | |
def filter_class(key) | |
classes = ["btn"] | |
classes << if key.to_s == params.fetch(:filter, "all") | |
"btn-primary" | |
else | |
"btn-outline" | |
end | |
classes.join(" ") | |
end | |
def sort_direction(column) | |
if column.to_s == order_field | |
order_direction.to_s == "desc" ? "asc" : "desc" | |
else | |
"desc" | |
end | |
end | |
def order_field | |
@collection.order_values.first.expr.name | |
end | |
def order_direction | |
@collection.order_values.first.direction | |
end | |
def request_url | |
@request_url ||= request.url | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.data-table { | |
display: block; | |
width: 100%; | |
overflow-x: auto; | |
&_controls { | |
display: flex; | |
align-items: center; | |
} | |
&_search { | |
display: flex; | |
label { | |
margin: auto; | |
} | |
} | |
&_filter { | |
display: flex; | |
align-items: flex-end; | |
width: 100%; | |
justify-content: flex-end; | |
margin-top: 10px; | |
} | |
&_length { | |
flex: 1 0; | |
} | |
&_content { | |
width: 100%; | |
border: 1px solid #e6e6f2; | |
margin-top: 6px; | |
margin-bottom: 6px; | |
max-width: none; | |
border-collapse: separate; | |
border-spacing: 0; | |
tbody { | |
tr:nth-child(odd) { | |
background-color: rgba(230, 230, 242, .5); | |
} | |
} | |
th { | |
text-align: left; | |
font-weight: normal; | |
border: 1px solid #e6e6f2; | |
vertical-align: middle; | |
border-bottom: 2px solid #e6e6f2; | |
color: #3d405c; | |
font-family: 'Circular Std Medium'; | |
a, span { | |
padding: 10px; | |
display: block; | |
position: relative; | |
} | |
} | |
td { | |
padding: 10px; | |
vertical-align: middle; | |
border: 1px solid #e6e6f2; | |
font-weight: normal; | |
} | |
} | |
&_sorting { | |
cursor: pointer; | |
position: relative; | |
&::before { | |
position: absolute; | |
bottom: 0.7em; | |
display: block; | |
opacity: 0.3; | |
right: 1em; | |
content: "\2191"; | |
} | |
&::after { | |
position: absolute; | |
bottom: 0.7em; | |
display: block; | |
opacity: 0.3; | |
right: 0.5em; | |
content: "\2193"; | |
} | |
&.asc { | |
&::before { | |
opacity: 1; | |
} | |
} | |
&.desc { | |
&::after { | |
opacity: 1; | |
} | |
} | |
} | |
&_footer { | |
display: flex; | |
} | |
&_summary { | |
flex: 1 0; | |
padding-top: 0.85em; | |
white-space: nowrap; | |
} | |
&_paging { | |
margin: 0; | |
white-space: nowrap; | |
text-align: right; | |
display: flex; | |
padding-left: 0; | |
list-style: none; | |
border-radius: .25rem; | |
margin: 2px 0; | |
white-space: nowrap; | |
justify-content: flex-end; | |
li { | |
a, span { | |
position: relative; | |
display: block; | |
padding: .5rem .75rem; | |
margin-right: 5px; | |
border: 1px solid #e6e6f2; | |
border-radius: 3px; | |
line-height: 1; | |
} | |
a.active, a:hover { | |
color: #fff; | |
background-color: #5969ff; | |
border-color: #5969ff; | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<%= render(UI::Card, container_class: "alert-list") do %> | |
<%= | |
render( | |
UI::DataTable, | |
columns: { | |
timestamp: { | |
sort: true, | |
format: proc { |value| value.strftime("%Y-%m-%d %H:%M:%S") } | |
}, | |
current_state: { | |
sort: true, | |
format: proc { |value| value.titleize } | |
}, | |
name: { sort: true }, | |
description: {} | |
}, | |
filters: { | |
all: "All", | |
received: "Received", | |
awaiting_acknowledgement: "Awaiting Acknowledgement", | |
acknowledged: "Acknowledged", | |
resolved: "Resolved" | |
}, | |
links: { | |
view: proc { |item| alerting_alert_path(item) } | |
}, | |
collection: @alerts, | |
sorting: { field: :timestamp, direction: :asc }, | |
) | |
%> | |
<% end %> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<% return if @total_pages == 1 %> | |
<ul class="<%= @class_name.join(" ") %>"> | |
<% if previous_page %> | |
<li> | |
<%= link_to "Previous", paging_link(previous_page) %> | |
</li> | |
<% end %> | |
<% if more_pages_before %> | |
<li><span>...</span></li> | |
<% end %> | |
<% (paging_start..paging_end).each do |page| %> | |
<li> | |
<%= link_to page, paging_link(page), class: "#{ 'active' if page == current_page }" %> | |
</li> | |
<% end %> | |
<% if more_pages_after %> | |
<li><span>...</span></li> | |
<% end %> | |
<% if next_page %> | |
<li> | |
<%= link_to "Next", paging_link(next_page) %> | |
</li> | |
<% end %> | |
</ul> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
require "uri_address" | |
module UI | |
class Paging < ActionView::Component::Base | |
attr_reader :current_page, :total_entries, :page_size, :previous_page, :next_page, :total_pages | |
def initialize(collection:, class_name: [], request_url: nil) | |
@current_page = collection.current_page.to_i | |
@page_size = collection.per_page | |
@total_pages = collection.total_pages | |
@total_entries = collection.count | |
@previous_page = collection.previous_page | |
@next_page = collection.next_page | |
@class_name = class_name | |
@request_url = request_url | |
end | |
def paging_start | |
return 1 if current_page < 4 | |
[(current_page - 2), (@total_pages - 5)].min | |
end | |
def paging_end | |
return @total_pages if @total_pages < 5 | |
return 5 if current_page <= 3 | |
end_no = current_page + 2 | |
return @total_pages if end_no > @total_pages | |
end_no | |
end | |
def more_pages_before | |
paging_start != 1 | |
end | |
def more_pages_after | |
@total_pages != paging_end | |
end | |
def paging_link(page_no) | |
uri = UriAddress.new(request_url) | |
uri.query_param("page_no", page_no) | |
uri.to_s | |
end | |
def request_url | |
@request_url ||= request.url | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment