Skip to content
Open
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
7 changes: 5 additions & 2 deletions app/controllers/topics_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
27 changes: 27 additions & 0 deletions app/helpers/topics_helper.rb
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
21 changes: 8 additions & 13 deletions app/views/topics/_list.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,21 @@
<% if @topics.any? %>
<% @topics.each do |topic| %>
<tr class="border-b border-gray-100 transition-all hover:bg-gray-50">
<!-- Published -->
<td class="table-cell text-gray-500 font-mono text-xs">
<%= topic.published_at&.strftime("%b %d, %Y") %>
</td>

<!-- Title -->
<td class="table-cell">
<div class="flex flex-col items-center gap-1">
<div class="font-semibold text-gray-900 text-sm"><%= topic.title %></div>
<div class="text-gray-500 text-xs">Published <%= topic.published_at&.strftime('%b %d, %Y') %></div>
</div>
</td>

<!-- Description -->
<td class="hide-mobile table-cell text-gray-700 text-sm">
<% if topic.description.present? %>
<%= truncate(topic.description, length: 60, omission: '…') %>
<% else %>
<span class="text-gray-400 italic">No description</span>
<% end %>
</td>

<!-- UID -->
<td class="hide-mobile table-cell text-gray-500 font-mono text-xs">
<%= topic.uid.present? ? truncate(topic.uid, length: 12, omission: '…') : '-' %>
<!-- Added -->
<td class="table-cell text-gray-500 font-mono text-xs">
<%= topic.created_at.strftime("%b %d, %Y") %>
</td>

<!-- Language -->
Expand Down
1 change: 1 addition & 0 deletions app/views/topics/_search.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
</div>
<div class="card-body-sm">
<%= 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" %>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we still pass search_params to this partial and use :sort this these params?

<div id="topics-search-grid" class="form-grid-auto items-start">
<!-- Query -->
<div class="form-grid-full">
Expand Down
18 changes: 9 additions & 9 deletions app/views/topics/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@

<!-- Search Card -->
<div class="mb-8">
<%= render "search", providers: @providers, languages: @languages, params: search_params %>
<%= render "search", providers: @providers, languages: @languages %>
</div>

<!-- Topics Table Card -->
Expand Down Expand Up @@ -83,14 +83,14 @@
<table class="w-full border-collapse table-fixed">
<thead>
<tr class="bg-gradient-gray border-b-2 border-gray-200">
<th class="px-6 py-5 text-left text-xs font-bold text-gray-600 uppercase tracking-wider truncate">Title</th>
<th class="px-6 py-5 text-left text-xs font-bold text-gray-600 uppercase tracking-wider truncate hide-mobile">Description</th>
<th class="px-6 py-5 text-left text-xs font-bold text-gray-600 uppercase tracking-wider truncate hide-mobile">UID</th>
<th class="px-6 py-5 text-left text-xs font-bold text-gray-600 uppercase tracking-wider truncate">Language</th>
<th class="px-6 py-5 text-left text-xs font-bold text-gray-600 uppercase tracking-wider truncate hide-mobile">Provider</th>
<th class="px-6 py-5 text-left text-xs font-bold text-gray-600 uppercase tracking-wider truncate"># of Documents</th>
<th class="px-6 py-5 text-left text-xs font-bold text-gray-600 uppercase tracking-wider truncate">State</th>
<th class="px-6 py-5 text-right text-xs font-bold text-gray-600 uppercase tracking-wider w-40 actions-col">Actions</th>
<th scope="col" class="px-6 py-5 text-left text-xs font-bold text-gray-600 uppercase tracking-wider truncate" aria-sort="<%= topic_sort_aria(:published_at) %>"><%= topic_sort_header("Published", :published_at) %></th>
<th scope="col" class="px-6 py-5 text-left text-xs font-bold text-gray-600 uppercase tracking-wider truncate">Title</th>
<th scope="col" class="px-6 py-5 text-left text-xs font-bold text-gray-600 uppercase tracking-wider truncate" aria-sort="<%= topic_sort_aria(:created_at) %>"><%= topic_sort_header("Added", :created_at) %></th>
<th scope="col" class="px-6 py-5 text-left text-xs font-bold text-gray-600 uppercase tracking-wider truncate">Language</th>
<th scope="col" class="px-6 py-5 text-left text-xs font-bold text-gray-600 uppercase tracking-wider truncate hide-mobile">Provider</th>
<th scope="col" class="px-6 py-5 text-left text-xs font-bold text-gray-600 uppercase tracking-wider truncate"># of Documents</th>
<th scope="col" class="px-6 py-5 text-left text-xs font-bold text-gray-600 uppercase tracking-wider truncate">State</th>
<th scope="col" class="px-6 py-5 text-right text-xs font-bold text-gray-600 uppercase tracking-wider w-40 actions-col">Actions</th>
</tr>
</thead>
<%= render "list", topics: @topics, params: search_params %>
Expand Down
45 changes: 45 additions & 0 deletions spec/requests/topics/index_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down