From 1617dea668550c451bc1a69556050c1b895cc1c6 Mon Sep 17 00:00:00 2001 From: Lucas Franco Date: Mon, 13 Jul 2026 07:34:31 -0300 Subject: [PATCH 1/2] feat: add sortable columns for published and created dates in topics index --- app/controllers/topics_controller.rb | 7 +++-- app/helpers/topics_helper.rb | 27 +++++++++++++++++ app/views/topics/_list.html.erb | 21 +++++-------- app/views/topics/_search.html.erb | 1 + app/views/topics/index.html.erb | 18 +++++------ spec/requests/topics/index_spec.rb | 45 ++++++++++++++++++++++++++++ 6 files changed, 95 insertions(+), 24 deletions(-) diff --git a/app/controllers/topics_controller.rb b/app/controllers/topics_controller.rb index b1767ef5..d8f1b70c 100644 --- a/app/controllers/topics_controller.rb +++ b/app/controllers/topics_controller.rb @@ -5,7 +5,10 @@ class TopicsController < ApplicationController before_action :set_topic, only: [ :show, :edit, :update, :destroy, :archive, :unarchive ] def index - @pagy, @topics = pagy(scope.includes(:documents_attachments).search_with_params(search_params)) + topics = scope.includes(:documents_attachments).search_with_params(search_params) + topics = topics.reorder(created_at: Topic.sort_order(search_params[:order]&.to_sym)) if search_params[:sort] == "created_at" + + @pagy, @topics = pagy(topics) @available_providers = other_available_providers @languages = scope.map(&:language).uniq.sort_by(&:name) end @@ -107,7 +110,7 @@ def mutator def search_params return { state: :active } unless params[:search].present? - params.require(:search).permit(:query, :state, :language_id, :year, :month, :order, tag_list: []) + params.require(:search).permit(:query, :state, :language_id, :year, :month, :sort, :order, tag_list: []) end helper_method :search_params diff --git a/app/helpers/topics_helper.rb b/app/helpers/topics_helper.rb index f0be16ff..d8935fd3 100644 --- a/app/helpers/topics_helper.rb +++ b/app/helpers/topics_helper.rb @@ -1,4 +1,31 @@ module TopicsHelper + def topic_sort_header(label, column) + current_column = search_params[:sort].presence_in(%w[published_at created_at]) || "published_at" + current_order = search_params[:order].presence_in(%w[asc desc]) || "desc" + active = current_column == column.to_s + next_order = current_order + next_order = current_order == "asc" ? "desc" : "asc" if active + indicator = active ? (current_order == "asc" ? "▲" : "▼") : "↕" + query = search_params.to_h.merge(sort: column, order: next_order) + + link_to topics_path(search: query), + class: "inline-flex items-center gap-1 hover:text-gray-900 focus-visible:outline-2 focus-visible:outline-offset-2", + aria: { label: "Sort by #{label} #{next_order == "asc" ? "ascending" : "descending"}" }, + data: { turbo_frame: "_top" } do + safe_join([ + content_tag(:span, label), + content_tag(:span, indicator, class: active ? "text-gray-700" : "text-gray-400", aria: { hidden: true }), + ]) + end + end + + def topic_sort_aria(column) + current_column = search_params[:sort].presence_in(%w[published_at created_at]) || "published_at" + return "none" unless current_column == column.to_s + + search_params[:order] == "asc" ? "ascending" : "descending" + end + def card_preview_media(file) case file.content_type in /image/ then render_image(file) diff --git a/app/views/topics/_list.html.erb b/app/views/topics/_list.html.erb index b126f705..8429acc9 100644 --- a/app/views/topics/_list.html.erb +++ b/app/views/topics/_list.html.erb @@ -2,26 +2,21 @@ <% if @topics.any? %> <% @topics.each do |topic| %> + + + <%= topic.published_at&.strftime("%b %d, %Y") %> + +
<%= topic.title %>
-
Published <%= topic.published_at&.strftime('%b %d, %Y') %>
- - - <% if topic.description.present? %> - <%= truncate(topic.description, length: 60, omission: '…') %> - <% else %> - No description - <% end %> - - - - - <%= topic.uid.present? ? truncate(topic.uid, length: 12, omission: '…') : '-' %> + + + <%= topic.created_at.strftime("%b %d, %Y") %> diff --git a/app/views/topics/_search.html.erb b/app/views/topics/_search.html.erb index e61708c5..666377f0 100644 --- a/app/views/topics/_search.html.erb +++ b/app/views/topics/_search.html.erb @@ -11,6 +11,7 @@
<%= form_for :search, url: topics_path, method: :get, data: { controller: "topics", topics_target: "searchForm", turbo_frame: "topic-list", turbo_action: "advance" } do |f| %> + <%= f.hidden_field :sort, value: params.dig(:search, :sort) if params.dig(:search, :sort) == "created_at" %>
diff --git a/app/views/topics/index.html.erb b/app/views/topics/index.html.erb index df5b3a1e..b9b3de3d 100644 --- a/app/views/topics/index.html.erb +++ b/app/views/topics/index.html.erb @@ -38,7 +38,7 @@
- <%= render "search", providers: @providers, languages: @languages, params: search_params %> + <%= render "search", providers: @providers, languages: @languages %>
@@ -83,14 +83,14 @@ - - - - - - - - + + + + + + + + <%= render "list", topics: @topics, params: search_params %> diff --git a/spec/requests/topics/index_spec.rb b/spec/requests/topics/index_spec.rb index 3f36d4a4..c5a3ce72 100644 --- a/spec/requests/topics/index_spec.rb +++ b/spec/requests/topics/index_spec.rb @@ -27,6 +27,51 @@ expect(page).to have_css("td", text: "1") end + it "displays published and added dates without description or UID columns" do + create( + :topic, + provider:, + published_at: Time.zone.local(2021, 1, 1), + created_at: Time.zone.local(2022, 2, 2) + ) + + get topics_url + + expect(page).to have_css("th", text: "Published") + expect(page).to have_css("th", text: "Added") + expect(page).to have_css("td", text: "Jan 01, 2021") + expect(page).to have_css("td", text: "Feb 02, 2022") + expect(page).not_to have_css("th", text: "Description") + expect(page).not_to have_css("th", text: "UID") + + added_link = page.find_link("Added") + expect(added_link[:href]).to include("search%5Bsort%5D=created_at", "search%5Border%5D=desc") + expect(added_link["data-turbo-frame"]).to eq("_top") + expect(page).to have_css("th:not(.hide-mobile)", text: "Published") + expect(page).to have_css("th:not(.hide-mobile)", text: "Added") + end + + it "sorts topics by the selected column and direction" do + newer_topic = create(:topic, provider:, title: "Newer", created_at: Time.zone.local(2022, 1, 1)) + older_topic = create(:topic, provider:, title: "Older", created_at: Time.zone.local(2021, 1, 1)) + + get topics_url, params: { search: { state: "active", sort: "created_at", order: "asc" } } + + expect(assigns(:topics)).to eq([ older_topic, newer_topic ]) + expect(page).to have_css("input[type='hidden'][name='search[sort]'][value='created_at']", visible: :all) + expect(page).to have_select("search_order", selected: "asc") + expect(page).to have_css("th[aria-sort='ascending']", text: "Added") + end + + it "falls back to published date for an unsupported sort column" do + older_topic = create(:topic, provider:, published_at: Time.zone.local(2021, 1, 1)) + newer_topic = create(:topic, provider:, published_at: Time.zone.local(2022, 1, 1)) + + get topics_url, params: { search: { state: "active", sort: "uid", order: "asc" } } + + expect(assigns(:topics)).to eq([ older_topic, newer_topic ]) + end + describe "searching" do context "with a query" do it "filters topics by query" do From 29826255bea8812c19260d066c88101bbd96f61f Mon Sep 17 00:00:00 2001 From: Lucas Franco Date: Thu, 16 Jul 2026 07:58:23 -0300 Subject: [PATCH 2/2] 699 pass search params to topics search partial --- app/views/topics/_search.html.erb | 2 +- app/views/topics/index.html.erb | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/views/topics/_search.html.erb b/app/views/topics/_search.html.erb index 666377f0..9497a051 100644 --- a/app/views/topics/_search.html.erb +++ b/app/views/topics/_search.html.erb @@ -11,7 +11,7 @@
<%= form_for :search, url: topics_path, method: :get, data: { controller: "topics", topics_target: "searchForm", turbo_frame: "topic-list", turbo_action: "advance" } do |f| %> - <%= f.hidden_field :sort, value: params.dig(:search, :sort) if params.dig(:search, :sort) == "created_at" %> + <%= f.hidden_field :sort, value: search_params[:sort] if search_params[:sort] == "created_at" %>
diff --git a/app/views/topics/index.html.erb b/app/views/topics/index.html.erb index b9b3de3d..6bf35e97 100644 --- a/app/views/topics/index.html.erb +++ b/app/views/topics/index.html.erb @@ -38,7 +38,7 @@
- <%= render "search", providers: @providers, languages: @languages %> + <%= render "search", providers: @providers, languages: @languages, search_params: search_params %>
@@ -112,4 +112,3 @@ <% end %>
-
TitleDescriptionUIDLanguageProvider# of DocumentsStateActions<%= topic_sort_header("Published", :published_at) %>Title<%= topic_sort_header("Added", :created_at) %>LanguageProvider# of DocumentsStateActions