mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
UX: Introduce automatic 'categories topics' setting (#8804)
When 'categories topics' setting is set to 0, the system will automatically try to find a value to keep the two columns (categories and topics) symmetrical. The value is computed as 1.5x the number of top level categories and at least 5 topics will always be returned.
This commit is contained in:
@@ -8,6 +8,9 @@ class CategoriesController < ApplicationController
|
|||||||
before_action :initialize_staff_action_logger, only: [:create, :update, :destroy]
|
before_action :initialize_staff_action_logger, only: [:create, :update, :destroy]
|
||||||
skip_before_action :check_xhr, only: [:index, :categories_and_latest, :categories_and_top, :redirect]
|
skip_before_action :check_xhr, only: [:index, :categories_and_latest, :categories_and_top, :redirect]
|
||||||
|
|
||||||
|
SYMMETRICAL_CATEGORIES_TO_TOPICS_FACTOR = 1.5
|
||||||
|
MIN_CATEGORIES_TOPICS = 5
|
||||||
|
|
||||||
def redirect
|
def redirect
|
||||||
return if handle_permalink("/category/#{params[:path]}")
|
return if handle_permalink("/category/#{params[:path]}")
|
||||||
redirect_to path("/c/#{params[:path]}")
|
redirect_to path("/c/#{params[:path]}")
|
||||||
@@ -46,7 +49,7 @@ class CategoriesController < ApplicationController
|
|||||||
|
|
||||||
style = SiteSetting.desktop_category_page_style
|
style = SiteSetting.desktop_category_page_style
|
||||||
topic_options = {
|
topic_options = {
|
||||||
per_page: SiteSetting.categories_topics,
|
per_page: CategoriesController.topics_per_page,
|
||||||
no_definitions: true
|
no_definitions: true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,6 +229,15 @@ class CategoriesController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def self.topics_per_page
|
||||||
|
return SiteSetting.categories_topics if SiteSetting.categories_topics > 0
|
||||||
|
|
||||||
|
count = Category.where(parent_category: nil).count
|
||||||
|
count = (SYMMETRICAL_CATEGORIES_TO_TOPICS_FACTOR * count).to_i
|
||||||
|
count > MIN_CATEGORIES_TOPICS ? count : MIN_CATEGORIES_TOPICS
|
||||||
|
end
|
||||||
|
|
||||||
def categories_and_topics(topics_filter)
|
def categories_and_topics(topics_filter)
|
||||||
discourse_expires_in 1.minute
|
discourse_expires_in 1.minute
|
||||||
|
|
||||||
@@ -236,7 +248,7 @@ class CategoriesController < ApplicationController
|
|||||||
}
|
}
|
||||||
|
|
||||||
topic_options = {
|
topic_options = {
|
||||||
per_page: SiteSetting.categories_topics,
|
per_page: CategoriesController.topics_per_page,
|
||||||
no_definitions: true
|
no_definitions: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1686,7 +1686,7 @@ en:
|
|||||||
alert_admins_if_errors_per_minute: "Number of errors per minute in order to trigger an admin alert. A value of 0 disables this feature. NOTE: requires restart."
|
alert_admins_if_errors_per_minute: "Number of errors per minute in order to trigger an admin alert. A value of 0 disables this feature. NOTE: requires restart."
|
||||||
alert_admins_if_errors_per_hour: "Number of errors per hour in order to trigger an admin alert. A value of 0 disables this feature. NOTE: requires restart."
|
alert_admins_if_errors_per_hour: "Number of errors per hour in order to trigger an admin alert. A value of 0 disables this feature. NOTE: requires restart."
|
||||||
|
|
||||||
categories_topics: "Number of topics to show in /categories page."
|
categories_topics: "Number of topics to show in /categories page. If set to 0, it will automatically try to find a value to keep the two columns symmetrical (categories and topics)."
|
||||||
suggested_topics: "Number of suggested topics shown at the bottom of a topic."
|
suggested_topics: "Number of suggested topics shown at the bottom of a topic."
|
||||||
limit_suggested_to_category: "Only show topics from the current category in suggested topics."
|
limit_suggested_to_category: "Only show topics from the current category in suggested topics."
|
||||||
suggested_topics_max_days_old: "Suggested topics should not be more than n days old."
|
suggested_topics_max_days_old: "Suggested topics should not be more than n days old."
|
||||||
|
|||||||
@@ -135,8 +135,7 @@ basic:
|
|||||||
default: false
|
default: false
|
||||||
categories_topics:
|
categories_topics:
|
||||||
default: 20
|
default: 20
|
||||||
min: 5
|
validator: "CategoriesTopicsValidator"
|
||||||
max: 2000
|
|
||||||
suggested_topics:
|
suggested_topics:
|
||||||
client: true
|
client: true
|
||||||
default: 5
|
default: 5
|
||||||
|
|||||||
19
lib/validators/categories_topics_validator.rb
Normal file
19
lib/validators/categories_topics_validator.rb
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class CategoriesTopicsValidator
|
||||||
|
def initialize(opts = {})
|
||||||
|
@opts = opts
|
||||||
|
end
|
||||||
|
|
||||||
|
def valid_value?(val)
|
||||||
|
num = val.to_i
|
||||||
|
return false if num.to_s != val.to_s
|
||||||
|
return false if num != 0 && num < CategoriesController::MIN_CATEGORIES_TOPICS
|
||||||
|
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
def error_message
|
||||||
|
I18n.t('site_settings.errors.invalid_integer_min', min: 5)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -481,4 +481,41 @@ describe CategoriesController do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context '#categories_and_topics' do
|
||||||
|
before do
|
||||||
|
10.times.each { Fabricate(:topic) }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'works when SiteSetting.categories_topics is non-null' do
|
||||||
|
SiteSetting.categories_topics = 5
|
||||||
|
|
||||||
|
get '/categories_and_latest.json'
|
||||||
|
expect(JSON.parse(response.body)['topic_list']['topics'].size).to eq(5)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'works when SiteSetting.categories_topics is null' do
|
||||||
|
SiteSetting.categories_topics = 0
|
||||||
|
|
||||||
|
get '/categories_and_latest.json'
|
||||||
|
json = JSON.parse(response.body)
|
||||||
|
expect(json['category_list']['categories'].size).to eq(2) # 'Uncategorized' and category
|
||||||
|
expect(json['topic_list']['topics'].size).to eq(5)
|
||||||
|
|
||||||
|
Fabricate(:category, parent_category: category)
|
||||||
|
|
||||||
|
get '/categories_and_latest.json'
|
||||||
|
json = JSON.parse(response.body)
|
||||||
|
expect(json['category_list']['categories'].size).to eq(2)
|
||||||
|
expect(json['topic_list']['topics'].size).to eq(5)
|
||||||
|
|
||||||
|
Fabricate(:category)
|
||||||
|
Fabricate(:category)
|
||||||
|
|
||||||
|
get '/categories_and_latest.json'
|
||||||
|
json = JSON.parse(response.body)
|
||||||
|
expect(json['category_list']['categories'].size).to eq(4)
|
||||||
|
expect(json['topic_list']['topics'].size).to eq(6)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user