UX: Show parent category name for category hashtags (#31188)

This commit changes the display of category hashtag
autocomplete to show the parent category name in this
format:

* Parent Name > Child Name

This helps further distinguish categories in the autocomplete
where there may be multiple different parent categories with
the same name child category, e.g. if every category has an
Announcements subcategory.
This commit is contained in:
Martin Brennan 2025-02-05 12:31:50 +10:00 committed by GitHub
parent f01c0c9740
commit a2dbcedbd9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 49 additions and 9 deletions

View File

@ -18,7 +18,14 @@ class CategoryHashtagDataSource
def self.category_to_hashtag_item(category)
HashtagAutocompleteService::HashtagItem.new.tap do |item|
item.text = category.name
item.text =
(
if category.parent_category
"#{category.parent_category.name} > #{category.name}"
else
category.name
end
)
item.slug = category.slug
item.description = category.description_text
item.icon = icon

View File

@ -1,15 +1,23 @@
# frozen_string_literal: true
RSpec.describe CategoryHashtagDataSource do
fab!(:parent_category) { Fabricate(:category, slug: "fun", topic_count: 2) }
fab!(:parent_category) { Fabricate(:category, name: "Silly Land", slug: "fun", topic_count: 2) }
fab!(:category1) do
Fabricate(:category, slug: "random", topic_count: 12, parent_category: parent_category)
Fabricate(
:category,
name: "Random",
slug: "random",
topic_count: 12,
parent_category: parent_category,
)
end
fab!(:category2) { Fabricate(:category, name: "Book Section", slug: "books", topic_count: 566) }
fab!(:category3) { Fabricate(:category, slug: "movies", topic_count: 245) }
fab!(:category3) { Fabricate(:category, name: "Kino Korner", slug: "movies", topic_count: 245) }
fab!(:group)
fab!(:category4) { Fabricate(:private_category, slug: "secret", group: group, topic_count: 40) }
fab!(:category5) { Fabricate(:category, slug: "casual", topic_count: 99) }
fab!(:category4) do
Fabricate(:private_category, name: "Nunya", slug: "secret", group: group, topic_count: 40)
end
fab!(:category5) { Fabricate(:category, name: "Chillzone", slug: "casual", topic_count: 99) }
fab!(:user)
let(:guardian) { Guardian.new(user) }
let(:uncategorized_category) { Category.find(SiteSetting.uncategorized_category_id) }
@ -55,6 +63,16 @@ RSpec.describe CategoryHashtagDataSource do
expect(described_class.lookup(Guardian.new(user), ["secret"]).first).not_to eq(nil)
end
it "formats the category text for a category without a parent" do
result = described_class.lookup(guardian, ["movies"]).first
expect(result.text).to eq("Kino Korner")
end
it "formats the category text for a category with a parent" do
result = described_class.lookup(guardian, ["fun:random"]).first
expect(result.text).to eq("Silly Land > Random")
end
context "with sub-sub-categories" do
before { SiteSetting.max_category_nesting = 3 }
@ -94,6 +112,15 @@ RSpec.describe CategoryHashtagDataSource do
result = described_class.lookup(guardian, ["child:grandchild"])
expect(result.map(&:relative_url)).to eq([parent2_child_grandchild.url])
end
it "formats the category text for sub-sub-categories" do
parent = Fabricate(:category, slug: "parent", name: "Parent")
child = Fabricate(:category, slug: "child", parent_category_id: parent.id, name: "Child")
grandchild =
Fabricate(:category, slug: "grandchild", parent_category_id: child.id, name: "Grandchild")
result = described_class.lookup(guardian, ["child:grandchild"])
expect(result.last.text).to eq("Child > Grandchild")
end
end
end
@ -102,6 +129,7 @@ RSpec.describe CategoryHashtagDataSource do
result = described_class.search(guardian, "mov", 5).first
expect(result.ref).to eq("movies")
expect(result.slug).to eq("movies")
expect(result.text).to eq("Kino Korner")
end
it "finds categories by partial slug" do
@ -121,6 +149,11 @@ RSpec.describe CategoryHashtagDataSource do
expect(result.ref).to eq("fun:random")
expect(result.slug).to eq("random")
end
it "formats the text correctly for a parent:child category that is found" do
result = described_class.search(guardian, "random", 5).first
expect(result.text).to eq("Silly Land > Random")
end
end
describe "#search_without_term" do

View File

@ -212,8 +212,8 @@ RSpec.describe HashtagAutocompleteService do
expect(service.search("book", %w[category tag]).map(&:ref)).to eq(
[
"book-reviews:book", # category exact match on slug, name sorted
"book-library:book",
"book-reviews:book", # category exact match on slug, name sorted
"book-library", # category starts with match on slug, name sorted
"book-reviews",
"bookmania", # tag starts with match on slug, name sorted
@ -226,8 +226,8 @@ RSpec.describe HashtagAutocompleteService do
)
expect(service.search("book", %w[category tag]).map(&:text)).to eq(
[
"Good Books",
"Horror",
"Book Library > Horror",
"Book Reviews > Good Books",
"Book Library",
"Book Reviews",
"bookmania",