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

Sortable resources tables #1744

Merged
merged 4 commits into from
Mar 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ gem 'mysql2', '~> 0.5.1' if ENV['DB'] == 'mysql'
gem 'pg', '~> 1.0' if ENV['DB'] == 'postgresql'

group :development, :test do
if ENV['CI']
gem 'sprockets', '< 4.0' # Sprockets 4 has serious issues with libsass on Linux machines
if ENV['GITHUB_ACTIONS']
gem 'sassc', '~> 2.1.0' # https://github.com/sass/sassc-ruby/issues/146
else
gem 'launchy'
gem 'annotate'
Expand Down
25 changes: 1 addition & 24 deletions app/assets/stylesheets/alchemy/tables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -57,29 +57,6 @@ th {
vertical-align: top;
border-bottom: 1px solid $medium-gray;
font-weight: bold;

i {
font-style: normal;
position: absolute;
right: 2px;
top: 4px;
text-shadow: 1px 1px 1px #fff;
}

a {

&.sortable {
display: block;
margin: -4px -8px;
padding: 4px 18px 4px 8px;
text-shadow: 1px 1px 1px #fff;
}

&.sorted {
position: relative;
background: $medium-gray;
}
}
}

tr.even td {
Expand Down Expand Up @@ -141,7 +118,7 @@ td {
width: 80px;
}

&.date {
&.date, &.datetime {
width: 150px;
}

Expand Down
1 change: 1 addition & 0 deletions app/controllers/alchemy/admin/attachments_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class AttachmentsController < ResourcesController

def index
@query = Attachment.ransack(search_filter_params[:q])
@query.sorts = 'name asc' if @query.sorts.empty?
@attachments = @query.result

if search_filter_params[:tagged_with].present?
Expand Down
1 change: 1 addition & 0 deletions app/controllers/alchemy/admin/languages_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module Admin
class LanguagesController < ResourcesController
def index
@query = Language.on_current_site.ransack(search_filter_params[:q])
@query.sorts = default_sort_order if @query.sorts.empty?
@languages = @query.result.page(params[:page] || 1).per(items_per_page)
end

Expand Down
6 changes: 6 additions & 0 deletions app/controllers/alchemy/admin/resources_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class ResourcesController < Alchemy::Admin::BaseController

def index
@query = resource_handler.model.ransack(search_filter_params[:q])
@query.sorts = default_sort_order if @query.sorts.empty?
items = @query.result

if contains_relations?
Expand Down Expand Up @@ -162,6 +163,11 @@ def items_per_page_options
per_page = Alchemy::Config.get(:items_per_page)
[per_page, per_page * 2, per_page * 4]
end

def default_sort_order
name = resource_handler.attributes.detect { |attr| attr[:name] == 'name' }
name ? 'name asc' : "#{resource_handler.attributes.first[:name]} asc"
end
end
end
end
1 change: 1 addition & 0 deletions app/controllers/alchemy/admin/tags_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class TagsController < ResourcesController

def index
@query = Gutentag::Tag.ransack(search_filter_params[:q])
@query.sorts = default_sort_order if @query.sorts.empty?
@tags = @query
.result
.page(params[:page] || 1)
Expand Down
8 changes: 4 additions & 4 deletions app/views/alchemy/admin/attachments/_files_list.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
<thead>
<tr>
<th class="icon"></th>
<th class="name"><%= sort_link(@query, :name, hide_indicator: true) %></th>
<th class="file_name"><%= sort_link(@query, :file_name, hide_indicator: true) %></th>
<th class="name"><%= sort_link(@query, :name) %></th>
<th class="file_name"><%= sort_link(@query, :file_name) %></th>
<th class="file_type"><%= Alchemy::Attachment.human_attribute_name('file_mime_type') %></th>
<th class="file_size"><%= sort_link(@query, :file_size, hide_indicator: true) %></th>
<th class="date"><%= sort_link(@query, :created_at, hide_indicator: true) %></th>
<th class="file_size"><%= sort_link(@query, :file_size) %></th>
<th class="date"><%= sort_link(@query, :created_at, default_order: 'desc') %></th>
<th class="tools"></th>
</tr>
</thead>
Expand Down
6 changes: 3 additions & 3 deletions app/views/alchemy/admin/languages/_table.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
<thead>
<tr>
<th>
<%= sort_link @query, :name, hide_indicator: true %>
<%= sort_link @query, :name %>
</th>
<th>
<%= sort_link @query, :language_code, hide_indicator: true %>
<%= sort_link @query, :language_code %>
</th>
<th>
<%= sort_link @query, :country_code, hide_indicator: true %>
<%= sort_link @query, :country_code %>
</th>
<th>
<%= Alchemy::Language.human_attribute_name(:code) %>
Expand Down
2 changes: 1 addition & 1 deletion app/views/alchemy/admin/resources/_resource.html.erb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<tr class="<%= cycle('even', 'odd') %>">
<% resource_handler.attributes.each do |attribute| %>
<% resource_handler.sorted_attributes.each do |attribute| %>
<td class="<%= attribute[:type] %> <%= attribute[:name] %>">
<% if attribute[:type] == :boolean %>
<%= resource.public_send(attribute[:name]) ? render_icon(:check) : nil %>
Expand Down
4 changes: 2 additions & 2 deletions app/views/alchemy/admin/resources/_table.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
<table class="list" id="<%= resource_handler.resources_name %>_list">
<thead>
<tr>
<% resource_handler.attributes.each do |attribute| %>
<% resource_handler.sorted_attributes.each do |attribute| %>
<th class="<%= attribute[:type] %> <%= attribute[:name] %>">
<%= sort_link [:resource_url_proxy, @query],
sortable_resource_header_column(attribute),
resource_handler.model.human_attribute_name(attribute[:name]),
hide_indicator: true %>
default_order: attribute[:type].to_s =~ /date|time/ ? 'desc' : 'asc' %>
</th>
<% end %>
<th class="tools"></th>
Expand Down
4 changes: 2 additions & 2 deletions app/views/alchemy/admin/tags/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
<thead>
<tr>
<th class="icon"></th>
<th class="name"><%= sort_link(@query, :name, hide_indicator: true) %></th>
<th class="name"><%= sort_link(@query, :name) %></th>
<th class="count"><%= Gutentag::Tag.human_attribute_name(:taggings_types) %></th>
<th class="count"><%= sort_link(@query, :taggings_count, hide_indicator: true) %></th>
<th class="count"><%= sort_link(@query, :taggings_count) %></th>
<th class="tools"></th>
</tr>
</thead>
Expand Down
2 changes: 1 addition & 1 deletion config/locales/alchemy.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,7 @@ en:
time:
formats:
alchemy:
default: "%a, %d %b %Y %H:%M:%S %z"
default: "%m.%d.%Y %H:%M"
essence_date: "%Y-%m-%d"
page_status: "%m.%d.%Y %H:%M"
short_datetime: "%d %b %H:%M"
Expand Down
10 changes: 10 additions & 0 deletions lib/alchemy/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ class Engine < Rails::Engine
Gutentag.normaliser = ->(value) { value.to_s }
end

# Custom Ransack sort arrows
initializer 'alchemy.ransack' do
Ransack.configure do |config|
config.custom_arrows = {
up_arrow: '<i class="fa fas fa-xs fa-arrow-up"></i>',
down_arrow: '<i class="fa fas fa-xs fa-arrow-down"></i>'
}
end
end

config.after_initialize do
require_relative './userstamp'
end
Expand Down
11 changes: 9 additions & 2 deletions lib/alchemy/resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ class Resource
attr_accessor :resource_relations, :model_associations
attr_reader :model

DEFAULT_SKIPPED_ATTRIBUTES = %w(id updated_at created_at creator_id updater_id)
DEFAULT_SKIPPED_ASSOCIATIONS = %w(creator updater)
DEFAULT_SKIPPED_ATTRIBUTES = %w(id created_at creator_id)
DEFAULT_SKIPPED_ASSOCIATIONS = %w(creator)
SEARCHABLE_COLUMN_TYPES = [:string, :text]

def initialize(controller_path, module_definition = nil, custom_model = nil)
Expand Down Expand Up @@ -168,6 +168,13 @@ def attributes
end.compact
end

def sorted_attributes
@_sorted_attributes ||= attributes.
sort_by { |attr| attr[:name] == 'name' ? 0 : 1 }.
sort_by! { |attr| attr[:type] == :boolean ? 1 : 0 }.
sort_by! { |attr| attr[:name] == 'updated_at' ? 1 : 0 }
end

def editable_attributes
attributes.reject { |h| restricted_attributes.map(&:to_s).include?(h[:name].to_s) }
end
Expand Down
31 changes: 28 additions & 3 deletions spec/controllers/alchemy/admin/resources_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,36 @@
end

context 'with sort parameter given' do
let(:params) { {q: {s: "name asc"}} }
let(:params) { {q: {s: "name desc"}} }

it "returns records in the right order" do
it "returns records in the defined order" do
get :index, params: params
expect(assigns(:events)).to eq([lustig, peter])
expect(assigns(:events)).to eq([peter, lustig])
end
end

context 'without sort parameter given' do
context 'if resource has name attribute' do
it "returns records sorted by name" do
get :index
expect(assigns(:events)).to eq([lustig, peter])
end
end

context 'if resource has no name attribute' do
let!(:booking1) { Booking.create!(from: 2.week.from_now) }
let!(:booking2) { Booking.create!(from: 1.weeks.from_now) }

controller(::Alchemy::Admin::ResourcesController) do
def resource_handler
@_resource_handler ||= Alchemy::Resource.new(controller_path, alchemy_module, Booking)
end
end

it "returns records sorted by first attribute" do
get :index
expect(assigns(:resources)).to eq([booking2, booking1])
end
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion spec/features/admin/resources_integration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@

it "lists the new item" do
expect(page).to have_content "My second event"
expect(page).to have_content "03 Mar 2012"
expect(page).to have_content "03.12.2020"
end

it "shows a success message" do
Expand Down
22 changes: 22 additions & 0 deletions spec/libraries/resource_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,28 @@ module Alchemy
end
end

describe "#sorted_attributes" do
subject { resource.sorted_attributes }

let(:columns) do
[
double(:column, {name: 'title', type: :string}),
double(:column, {name: 'name', type: :string}),
double(:column, {name: 'updated_at', type: :datetime}),
double(:column, {name: 'public', type: :boolean})
]
end

it "sorts by name, and updated_at" do
is_expected.to eq([
{name: "name", type: :string},
{name: "title", type: :string},
{name: "public", type: :boolean},
{name: "updated_at", type: :datetime}
])
end
end

context "when alchemy_resource_relations defined as class method in the model" do
let(:resource) { Resource.new("admin/events") }

Expand Down