From bc2fdffa3e8a09848ef8702d2058165b7a2e00bd Mon Sep 17 00:00:00 2001 From: Thomas von Deyen Date: Thu, 12 Mar 2020 12:25:43 +0100 Subject: [PATCH 1/4] Add default sort order to resources Before we where relying on the default sort order of the database. That is, but does not have to be, the primary column in most databases. This changes this behavior to introduce a default_sort_order that uses the name column (if the resource has one) or the first attribute in an ascending sort order. Also adds a nice little indicator to the sorted column. --- app/assets/stylesheets/alchemy/tables.scss | 25 +-------------- .../alchemy/admin/attachments_controller.rb | 1 + .../alchemy/admin/languages_controller.rb | 1 + .../alchemy/admin/resources_controller.rb | 6 ++++ .../alchemy/admin/tags_controller.rb | 1 + .../admin/attachments/_files_list.html.erb | 8 ++--- .../alchemy/admin/languages/_table.html.erb | 6 ++-- .../alchemy/admin/resources/_table.html.erb | 2 +- app/views/alchemy/admin/tags/index.html.erb | 4 +-- lib/alchemy/engine.rb | 10 ++++++ .../admin/resources_controller_spec.rb | 31 +++++++++++++++++-- 11 files changed, 58 insertions(+), 37 deletions(-) diff --git a/app/assets/stylesheets/alchemy/tables.scss b/app/assets/stylesheets/alchemy/tables.scss index 30f97b3a72..393f47a519 100644 --- a/app/assets/stylesheets/alchemy/tables.scss +++ b/app/assets/stylesheets/alchemy/tables.scss @@ -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 { @@ -141,7 +118,7 @@ td { width: 80px; } - &.date { + &.date, &.datetime { width: 150px; } diff --git a/app/controllers/alchemy/admin/attachments_controller.rb b/app/controllers/alchemy/admin/attachments_controller.rb index ecbea2e0bf..54eecdc262 100644 --- a/app/controllers/alchemy/admin/attachments_controller.rb +++ b/app/controllers/alchemy/admin/attachments_controller.rb @@ -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? diff --git a/app/controllers/alchemy/admin/languages_controller.rb b/app/controllers/alchemy/admin/languages_controller.rb index 43c5566995..d96ad09ccb 100644 --- a/app/controllers/alchemy/admin/languages_controller.rb +++ b/app/controllers/alchemy/admin/languages_controller.rb @@ -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 diff --git a/app/controllers/alchemy/admin/resources_controller.rb b/app/controllers/alchemy/admin/resources_controller.rb index 49a0925ea1..015c03e2d6 100644 --- a/app/controllers/alchemy/admin/resources_controller.rb +++ b/app/controllers/alchemy/admin/resources_controller.rb @@ -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? @@ -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 diff --git a/app/controllers/alchemy/admin/tags_controller.rb b/app/controllers/alchemy/admin/tags_controller.rb index 5222131962..c219e44f4b 100644 --- a/app/controllers/alchemy/admin/tags_controller.rb +++ b/app/controllers/alchemy/admin/tags_controller.rb @@ -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) diff --git a/app/views/alchemy/admin/attachments/_files_list.html.erb b/app/views/alchemy/admin/attachments/_files_list.html.erb index 16e2207361..b184d5ecd1 100644 --- a/app/views/alchemy/admin/attachments/_files_list.html.erb +++ b/app/views/alchemy/admin/attachments/_files_list.html.erb @@ -11,11 +11,11 @@ - <%= sort_link(@query, :name, hide_indicator: true) %> - <%= sort_link(@query, :file_name, hide_indicator: true) %> + <%= sort_link(@query, :name) %> + <%= sort_link(@query, :file_name) %> <%= Alchemy::Attachment.human_attribute_name('file_mime_type') %> - <%= sort_link(@query, :file_size, hide_indicator: true) %> - <%= sort_link(@query, :created_at, hide_indicator: true) %> + <%= sort_link(@query, :file_size) %> + <%= sort_link(@query, :created_at, default_order: 'desc') %> diff --git a/app/views/alchemy/admin/languages/_table.html.erb b/app/views/alchemy/admin/languages/_table.html.erb index cc8b3f36da..df2984bff2 100644 --- a/app/views/alchemy/admin/languages/_table.html.erb +++ b/app/views/alchemy/admin/languages/_table.html.erb @@ -3,13 +3,13 @@ - <%= sort_link @query, :name, hide_indicator: true %> + <%= sort_link @query, :name %> - <%= sort_link @query, :language_code, hide_indicator: true %> + <%= sort_link @query, :language_code %> - <%= sort_link @query, :country_code, hide_indicator: true %> + <%= sort_link @query, :country_code %> <%= Alchemy::Language.human_attribute_name(:code) %> diff --git a/app/views/alchemy/admin/resources/_table.html.erb b/app/views/alchemy/admin/resources/_table.html.erb index 92c24ad78f..4b71a12eec 100644 --- a/app/views/alchemy/admin/resources/_table.html.erb +++ b/app/views/alchemy/admin/resources/_table.html.erb @@ -7,7 +7,7 @@ <%= 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' %> <% end %> diff --git a/app/views/alchemy/admin/tags/index.html.erb b/app/views/alchemy/admin/tags/index.html.erb index 307fd0e28e..44dc1d8d7b 100644 --- a/app/views/alchemy/admin/tags/index.html.erb +++ b/app/views/alchemy/admin/tags/index.html.erb @@ -23,9 +23,9 @@ - <%= sort_link(@query, :name, hide_indicator: true) %> + <%= sort_link(@query, :name) %> <%= Gutentag::Tag.human_attribute_name(:taggings_types) %> - <%= sort_link(@query, :taggings_count, hide_indicator: true) %> + <%= sort_link(@query, :taggings_count) %> diff --git a/lib/alchemy/engine.rb b/lib/alchemy/engine.rb index ed2e87ceaf..2b73074b72 100644 --- a/lib/alchemy/engine.rb +++ b/lib/alchemy/engine.rb @@ -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: '', + down_arrow: '' + } + end + end + config.after_initialize do require_relative './userstamp' end diff --git a/spec/controllers/alchemy/admin/resources_controller_spec.rb b/spec/controllers/alchemy/admin/resources_controller_spec.rb index 2c2c3fec35..ac3cccc6a1 100644 --- a/spec/controllers/alchemy/admin/resources_controller_spec.rb +++ b/spec/controllers/alchemy/admin/resources_controller_spec.rb @@ -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 From 31914f6b8381e167de0f41ce5a7cabb5225191bc Mon Sep 17 00:00:00 2001 From: Thomas von Deyen Date: Thu, 12 Mar 2020 16:47:15 +0100 Subject: [PATCH 2/4] Sort resources attributes columns by name and type --- .../admin/resources/_resource.html.erb | 2 +- .../alchemy/admin/resources/_table.html.erb | 2 +- lib/alchemy/resource.rb | 11 ++++++++-- spec/libraries/resource_spec.rb | 22 +++++++++++++++++++ 4 files changed, 33 insertions(+), 4 deletions(-) diff --git a/app/views/alchemy/admin/resources/_resource.html.erb b/app/views/alchemy/admin/resources/_resource.html.erb index e3580cc844..d0fdd7d179 100644 --- a/app/views/alchemy/admin/resources/_resource.html.erb +++ b/app/views/alchemy/admin/resources/_resource.html.erb @@ -1,5 +1,5 @@ -<% resource_handler.attributes.each do |attribute| %> +<% resource_handler.sorted_attributes.each do |attribute| %> <% if attribute[:type] == :boolean %> <%= resource.public_send(attribute[:name]) ? render_icon(:check) : nil %> diff --git a/app/views/alchemy/admin/resources/_table.html.erb b/app/views/alchemy/admin/resources/_table.html.erb index 4b71a12eec..47d65de87c 100644 --- a/app/views/alchemy/admin/resources/_table.html.erb +++ b/app/views/alchemy/admin/resources/_table.html.erb @@ -2,7 +2,7 @@ - <% resource_handler.attributes.each do |attribute| %> + <% resource_handler.sorted_attributes.each do |attribute| %>
<%= sort_link [:resource_url_proxy, @query], sortable_resource_header_column(attribute), diff --git a/lib/alchemy/resource.rb b/lib/alchemy/resource.rb index 55b8eab70d..272af441ad 100644 --- a/lib/alchemy/resource.rb +++ b/lib/alchemy/resource.rb @@ -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) @@ -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 diff --git a/spec/libraries/resource_spec.rb b/spec/libraries/resource_spec.rb index 6caf3ba941..d6aa5381a5 100644 --- a/spec/libraries/resource_spec.rb +++ b/spec/libraries/resource_spec.rb @@ -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") } From 7cdfdc349ef808cd65eff02712702008bfabb584 Mon Sep 17 00:00:00 2001 From: Thomas von Deyen Date: Thu, 12 Mar 2020 16:47:36 +0100 Subject: [PATCH 3/4] Shorten default date format --- config/locales/alchemy.en.yml | 2 +- spec/features/admin/resources_integration_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/locales/alchemy.en.yml b/config/locales/alchemy.en.yml index 95cf17ce42..b5408eaf4b 100644 --- a/config/locales/alchemy.en.yml +++ b/config/locales/alchemy.en.yml @@ -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" diff --git a/spec/features/admin/resources_integration_spec.rb b/spec/features/admin/resources_integration_spec.rb index d383ca8690..f22d72a2ee 100644 --- a/spec/features/admin/resources_integration_spec.rb +++ b/spec/features/admin/resources_integration_spec.rb @@ -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 From 8ad0674758692d665fb8d06ed36ae4a9b4df5020 Mon Sep 17 00:00:00 2001 From: Thomas von Deyen Date: Thu, 12 Mar 2020 22:16:37 +0100 Subject: [PATCH 4/4] Use SassC 2.1 on GitHub CI See https://github.com/sass/sassc-ruby/issues/146 --- Gemfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index bd7b44dfac..192413493e 100644 --- a/Gemfile +++ b/Gemfile @@ -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'