Skip to content

Commit

Permalink
Merge pull request #3479 from alphagov/add-sort-facet
Browse files Browse the repository at this point in the history
New all content finder UI: Add ability to sort
  • Loading branch information
csutter authored Sep 26, 2024
2 parents cfcc1c1 + 2c2607d commit ddd83ed
Show file tree
Hide file tree
Showing 12 changed files with 207 additions and 3 deletions.
12 changes: 9 additions & 3 deletions app/controllers/finders_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,15 @@ def results
end

def all_facets
return @facets if defined?(@facets)

FacetsBuilder.new(content_item:, search_results:, value_hash: filter_params).facets
@all_facets ||= FacetsBuilder.new(
content_item:,
search_results:,
value_hash: filter_params,
).facets.tap do |built_facets|
if content_item.all_content_finder? && enable_new_all_content_finder_ui?
built_facets.prepend(SortFacet.new)
end
end
end

def facets
Expand Down
45 changes: 45 additions & 0 deletions app/models/sort_facet.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# SortFacet is a "virtual" facet, in that it is only used for the new all content finder UI, where
# sorting forms part of the overall filtering UI instead of being separate
class SortFacet
KEY = "order".freeze

def name
"Sort by"
end
alias_method :ga4_section, :name

def key
KEY
end

def to_partial_path
self.class.name.underscore
end

def user_visible?
true
end

# The methods below are the minimum required for this virtual facet to take the place of a real
# `Facet`

def has_filters?
false
end

def filterable?
true
end

def hide_facet_tag?
false
end

def metadata?
false
end

private

attr_reader :sort_presenter
end
10 changes: 10 additions & 0 deletions app/presenters/sort_option_presenter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ def to_hash
}
end

def to_radio_option
return nil if disabled

{
value:,
text: label,
checked: selected,
}
end

private

attr_reader :default, :selected, :disabled
Expand Down
4 changes: 4 additions & 0 deletions app/presenters/sort_presenter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ def sort_options
content_item_sort_options
end

def to_radio_options
presented_sort_options.map(&:to_radio_option).compact
end

private

attr_reader :user_selected_order, :keywords, :content_item_sort_options
Expand Down
17 changes: 17 additions & 0 deletions app/views/finders/all_content_finder_facets/_sort_facet.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<%= render "components/filter_section", {
heading_text: sort_facet.name,
id: "facet_sort",
index_section: index,
index_section_count: count,
} do %>
<%= render "govuk_publishing_components/components/radio", {
heading: "Sort order",
heading_level: 0,
# Legend is visually hidden as non-screenreader users already have the section heading above
visually_hidden_heading: true,
margin_bottom: 2,
name: sort_facet.key,
small: true,
items: @sort_presenter.to_radio_options,
} %>
<% end %>
8 changes: 8 additions & 0 deletions features/all_content_finder.feature
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ Feature: All content finder ("site search")
And I open the filter panel
Then I can see a filter section for every visible facet on the all content finder
Scenario: Changing the sort order of a search
When I search all content for "dark gray all alone"
And I open the filter panel
And I open the "Sort by" filter section
And I select the "Updated (oldest)" option
And I apply the filters
Then I can see sorted results
Scenario: Spelling suggestion
When I search all content for "drving"
Then I see a "driving" spelling suggestion
1 change: 1 addition & 0 deletions features/step_definitions/search_steps.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
stub_search_api_request_with_manual_filter_all_content_results
stub_search_api_request_with_misspelt_query
stub_search_api_request_with_query
stub_search_api_request_with_sorted_query
end

Given(/^the new all content finder UI is (\w+)$/) do |state|
Expand Down
19 changes: 19 additions & 0 deletions features/step_definitions/site_search_steps.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,23 @@
click_on "Filter and sort"
end

When(/^I open the "([^"]*)" filter section$/) do |title|
# Capybara #click can't deal with <details> elements, so need to manually find summary first
section = find("details summary", text: title)
section.click
end

When(/^I select the "([^"]*)" option$/) do |option|
choose option
end

When("I apply the filters") do
click_on "Apply filters"
end

Then("I can see a filter section for every visible facet on the all content finder") do
# These are visible filter types and should have a section
expect(page).to have_selector("h2", text: "Sort by")
expect(page).to have_selector("h2", text: "Filter by Topic")
expect(page).to have_selector("h2", text: "Filter by Type")
expect(page).to have_selector("h2", text: "Filter by Updated")
Expand All @@ -26,3 +41,7 @@
expect(page).not_to have_selector("h2", text: "Filter by World location")
expect(page).not_to have_selector("h2", text: "Filter by Topical event")
end

Then("I can see sorted results") do
expect(page).to have_link("Loving him was red")
end
37 changes: 37 additions & 0 deletions features/support/document_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,24 @@ def stub_search_api_request_with_query
.to_return(body: all_documents_json)
end

def stub_search_api_request_with_sorted_query
stub_request(:get, SEARCH_ENDPOINT)
.with(query: hash_including("q" => "dark gray all alone"))
.to_return(body: %({ "results": [], "total": 0, "start": 0}))

stub_request(:get, SEARCH_V2_ENDPOINT)
.with(query: hash_including("q" => "dark gray all alone"))
.to_return(body: %({ "results": [], "total": 0, "start": 0}))

stub_request(:get, SEARCH_ENDPOINT)
.with(query: hash_including("q" => "dark gray all alone", "order" => "public_timestamp"))
.to_return(body: sorted_documents_json)

stub_request(:get, SEARCH_V2_ENDPOINT)
.with(query: hash_including("q" => "dark gray all alone", "order" => "public_timestamp"))
.to_return(body: sorted_documents_json)
end

def stub_search_api_request_with_misspelt_query
stub_request(:get, SEARCH_ENDPOINT)
.with(query: hash_including("q" => "drving"))
Expand Down Expand Up @@ -670,6 +688,25 @@ def all_documents_json
})
end

def sorted_documents_json
%({
"results": [
{
"title": "Loving him was red",
"public_timestamp": "2012-10-22",
"summary": "Losing him was blue like I'd never known",
"document_type": "song",
"link": "/red",
"_id": "/red"
}
],
"total": 1,
"start": 0,
"facets": {},
"suggested_queries": []
})
end

def no_results_json
%({
"results": [],
Expand Down
28 changes: 28 additions & 0 deletions spec/models/sort_facet_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
require "spec_helper"

describe SortFacet do
subject(:sort_facet) { described_class.new }

describe "#name" do
it "returns a value" do
expect(sort_facet.name).not_to be_blank
end
end

describe "#ga4_section" do
it "is identical to #name" do
expect(sort_facet.ga4_section).to eq(sort_facet.name)
end
end

describe "#to_partial_path" do
it "is the underscored class name" do
expect(sort_facet.to_partial_path).to eq("sort_facet")
end
end

it { is_expected.to be_user_visible }
it { is_expected.to be_filterable }
it { is_expected.not_to be_hide_facet_tag }
it { is_expected.not_to be_metadata }
end
16 changes: 16 additions & 0 deletions spec/presenters/sort_option_presenter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

let(:default_sort_option) { described_class.new(label: "Most viewed", key: "most-viewed", default: true) }

let(:disabled_sort_option) { described_class.new(label: "Show in order of redness", key: "redness", disabled: true) }

describe "#value" do
context "a value is provided" do
it "returns the given value" do
Expand Down Expand Up @@ -44,4 +46,18 @@
)
end
end

describe "#to_radio_option" do
it "returns a hash appropriate for the radio component" do
expect(sort_option.to_radio_option).to eq(
value: "updated-newest",
text: "Updated (newest)",
checked: false,
)
end

it "returns nil for a disabled option" do
expect(disabled_sort_option.to_radio_option).to be_nil
end
end
end
13 changes: 13 additions & 0 deletions spec/presenters/sort_presenter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,19 @@
end
end

describe "#to_radio_options" do
let(:values) { { "keywords" => "red", "order" => "relevance" } }

it "returns only enabled sort options as radio options" do
expect(presenter_with_relevance.to_radio_options).to eq(
[
{ value: "updated-newest", text: "Updated (newest)", checked: false },
{ value: "relevance", text: "Relevance", checked: true },
],
)
end
end

private

def content_item(sort_options: nil)
Expand Down

0 comments on commit ddd83ed

Please sign in to comment.