mirror of
https://github.com/discourse/discourse.git
synced 2025-05-26 09:21:48 +08:00
FIX: Push category hashtag slug match to top (#19174)
When searching for categories it is possible for a child category to have a slug that matches the term exactly, but will not be found by .lookup since we don't return these categories unless the ref matches parent:child. Introduces a search_sort method to each hashtag data source so they can provide their custom sort logic of results, in category's case putting all matching slugs to the top regardless of parent/child relationship then sorting by text.
This commit is contained in:
@ -9,8 +9,7 @@ class CategoryHashtagDataSource
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.category_to_hashtag_item(guardian_categories, category)
|
def self.category_to_hashtag_item(guardian_categories, category)
|
||||||
category =
|
category = Category.new(category.slice(:id, :slug, :name, :parent_category_id, :description))
|
||||||
Category.new(category.slice(:id, :slug, :name, :parent_category_id, :description))
|
|
||||||
|
|
||||||
HashtagAutocompleteService::HashtagItem.new.tap do |item|
|
HashtagAutocompleteService::HashtagItem.new.tap do |item|
|
||||||
item.text = category.name
|
item.text = category.name
|
||||||
@ -51,4 +50,13 @@ class CategoryHashtagDataSource
|
|||||||
.take(limit)
|
.take(limit)
|
||||||
.map { |category| category_to_hashtag_item(guardian_categories, category) }
|
.map { |category| category_to_hashtag_item(guardian_categories, category) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.search_sort(search_results, term)
|
||||||
|
search_results
|
||||||
|
.select { |item| item.slug == term }
|
||||||
|
.sort_by { |item| item.text.downcase }
|
||||||
|
.concat(
|
||||||
|
search_results.select { |item| item.slug != term }.sort_by { |item| item.text.downcase },
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -197,11 +197,12 @@ class HashtagAutocompleteService
|
|||||||
next if !all_data_items_valid?(search_results)
|
next if !all_data_items_valid?(search_results)
|
||||||
|
|
||||||
search_results =
|
search_results =
|
||||||
search_results
|
@@data_sources[type].search_sort(
|
||||||
.reject do |item|
|
search_results.reject do |item|
|
||||||
limited_results.any? { |exact| exact.type == type && exact.slug === item.slug }
|
limited_results.any? { |exact| exact.type == type && exact.slug === item.slug }
|
||||||
end
|
end,
|
||||||
.sort_by { |item| item.text.downcase }
|
term,
|
||||||
|
)
|
||||||
|
|
||||||
top_ranked_type = type if top_ranked_type.nil?
|
top_ranked_type = type if top_ranked_type.nil?
|
||||||
limited_results.concat(search_results)
|
limited_results.concat(search_results)
|
||||||
|
@ -51,4 +51,8 @@ class TagHashtagDataSource
|
|||||||
.take(limit)
|
.take(limit)
|
||||||
.map { |tag| tag_to_hashtag_item(tag, include_count: true) }
|
.map { |tag| tag_to_hashtag_item(tag, include_count: true) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.search_sort(search_results, _)
|
||||||
|
search_results.sort_by { |result| result.text.downcase }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -40,4 +40,8 @@ class Chat::ChatChannelHashtagDataSource
|
|||||||
[]
|
[]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.search_sort(search_results, _)
|
||||||
|
search_results.sort_by { |result| result.text.downcase }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -43,6 +43,10 @@ RSpec.describe HashtagAutocompleteService do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.search_sort(search_results, _)
|
||||||
|
search_results.sort_by { |item| item.text.downcase }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe ".contexts_with_ordered_types" do
|
describe ".contexts_with_ordered_types" do
|
||||||
@ -166,6 +170,37 @@ RSpec.describe HashtagAutocompleteService do
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "orders categories by exact match on slug (ignoring parent/child distinction) then name, and then name for everything else" do
|
||||||
|
category2 = Fabricate(:category, name: "Book Library", slug: "book-library")
|
||||||
|
Fabricate(:category, name: "Horror", slug: "book", parent_category: category2)
|
||||||
|
Fabricate(:category, name: "Romance", slug: "romance-books")
|
||||||
|
Fabricate(:category, name: "Abstract Philosophy", slug: "abstract-philosophy-books")
|
||||||
|
category6 = Fabricate(:category, name: "Book Reviews", slug: "book-reviews")
|
||||||
|
Fabricate(:category, name: "Good Books", slug: "book", parent_category: category6)
|
||||||
|
expect(subject.search("book", %w[category]).map(&:ref)).to eq(
|
||||||
|
%w[
|
||||||
|
book-reviews:book
|
||||||
|
book-library:book
|
||||||
|
abstract-philosophy-books
|
||||||
|
book-club
|
||||||
|
book-library
|
||||||
|
book-reviews
|
||||||
|
romance-books
|
||||||
|
],
|
||||||
|
)
|
||||||
|
expect(subject.search("book", %w[category]).map(&:text)).to eq(
|
||||||
|
[
|
||||||
|
"Good Books",
|
||||||
|
"Horror",
|
||||||
|
"Abstract Philosophy",
|
||||||
|
"Book Club",
|
||||||
|
"Book Library",
|
||||||
|
"Book Reviews",
|
||||||
|
"Romance",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
context "when multiple tags and categories are returned" do
|
context "when multiple tags and categories are returned" do
|
||||||
fab!(:category2) { Fabricate(:category, name: "Book Zone", slug: "book-zone") }
|
fab!(:category2) { Fabricate(:category, name: "Book Zone", slug: "book-zone") }
|
||||||
fab!(:category3) { Fabricate(:category, name: "Book Dome", slug: "book-dome") }
|
fab!(:category3) { Fabricate(:category, name: "Book Dome", slug: "book-dome") }
|
||||||
|
Reference in New Issue
Block a user