diff --git a/app/assets/javascripts/discourse/app/components/edit-category-settings.js b/app/assets/javascripts/discourse/app/components/edit-category-settings.js index 5844e45d0c4..c811ce2db6e 100644 --- a/app/assets/javascripts/discourse/app/components/edit-category-settings.js +++ b/app/assets/javascripts/discourse/app/components/edit-category-settings.js @@ -68,6 +68,13 @@ export default buildCategoryPanel("settings", { ); }, + @discourseComputed + availableListFilters() { + return ["all", "none"].map(p => { + return { name: I18n.t(`category.list_filters.${p}`), value: p }; + }); + }, + @discourseComputed searchPrioritiesOptions() { const options = []; diff --git a/app/assets/javascripts/discourse/app/models/category.js b/app/assets/javascripts/discourse/app/models/category.js index 2c0442a4703..7d950cae2c4 100644 --- a/app/assets/javascripts/discourse/app/models/category.js +++ b/app/assets/javascripts/discourse/app/models/category.js @@ -188,7 +188,8 @@ const Category = RestModel.extend({ ), search_priority: this.search_priority, reviewable_by_group_name: this.reviewable_by_group_name, - read_only_banner: this.read_only_banner + read_only_banner: this.read_only_banner, + default_list_filter: this.default_list_filter }, type: id ? "PUT" : "POST" }); diff --git a/app/assets/javascripts/discourse/app/pre-initializers/dynamic-route-builders.js b/app/assets/javascripts/discourse/app/pre-initializers/dynamic-route-builders.js index 9c96d01e429..47626918f03 100644 --- a/app/assets/javascripts/discourse/app/pre-initializers/dynamic-route-builders.js +++ b/app/assets/javascripts/discourse/app/pre-initializers/dynamic-route-builders.js @@ -13,6 +13,7 @@ export default { app.DiscoveryCategoryController = DiscoverySortableController.extend(); app.DiscoveryParentCategoryController = DiscoverySortableController.extend(); app.DiscoveryCategoryNoneController = DiscoverySortableController.extend(); + app.DiscoveryCategoryAllController = DiscoverySortableController.extend(); app.DiscoveryCategoryWithIDController = DiscoverySortableController.extend(); app.DiscoveryCategoryRoute = buildCategoryRoute("default"); @@ -20,6 +21,9 @@ export default { app.DiscoveryCategoryNoneRoute = buildCategoryRoute("default", { no_subcategories: true }); + app.DiscoveryCategoryAllRoute = buildCategoryRoute("default", { + no_subcategories: false + }); app.DiscoveryCategoryWithIDRoute = buildCategoryRoute("default"); const site = Site.current(); diff --git a/app/assets/javascripts/discourse/app/routes/app-route-map.js b/app/assets/javascripts/discourse/app/routes/app-route-map.js index fb13822bb26..9057ff2fe50 100644 --- a/app/assets/javascripts/discourse/app/routes/app-route-map.js +++ b/app/assets/javascripts/discourse/app/routes/app-route-map.js @@ -70,6 +70,7 @@ export default function() { // default filter for a category this.route("categoryNone", { path: "/c/*category_slug_path_with_id/none" }); + this.route("categoryAll", { path: "/c/*category_slug_path_with_id/all" }); this.route("category", { path: "/c/*category_slug_path_with_id" }); }); diff --git a/app/assets/javascripts/discourse/app/routes/build-category-route.js b/app/assets/javascripts/discourse/app/routes/build-category-route.js index eac84d84849..58e5584fd21 100644 --- a/app/assets/javascripts/discourse/app/routes/build-category-route.js +++ b/app/assets/javascripts/discourse/app/routes/build-category-route.js @@ -30,6 +30,11 @@ export default (filterArg, params) => { category, category_slug_path_with_id }); + } else if (modelParams.id === "all") { + modelParams.category_slug_path_with_id = [ + modelParams.parentSlug, + modelParams.slug + ].join("/"); } else { modelParams.category_slug_path_with_id = [ modelParams.parentSlug, @@ -76,10 +81,24 @@ export default (filterArg, params) => { return; } - this._setupNavigation(model.category); + const { category, modelParams } = model; + + if ( + category.default_list_filter === "none" && + filterArg === "default" && + modelParams && + modelParams.id !== "all" + ) { + this.replaceWith("discovery.categoryNone", { + category, + category_slug_path_with_id: modelParams.category_slug_path_with_id + }); + } + + this._setupNavigation(category); return all([ - this._createSubcategoryList(model.category), - this._retrieveTopicList(model.category, transition, model.modelParams) + this._createSubcategoryList(category), + this._retrieveTopicList(category, transition, modelParams) ]); }, diff --git a/app/assets/javascripts/discourse/app/templates/components/edit-category-settings.hbs b/app/assets/javascripts/discourse/app/templates/components/edit-category-settings.hbs index ab17a307c33..a569876fd8c 100644 --- a/app/assets/javascripts/discourse/app/templates/components/edit-category-settings.hbs +++ b/app/assets/javascripts/discourse/app/templates/components/edit-category-settings.hbs @@ -196,6 +196,21 @@ {{/unless}} + + + + {{i18n "category.default_list_filter"}} + + + {{combo-box + id="category-default-filter" + valueProperty="value" + content=availableListFilters + value=category.default_list_filter + }} + + + {{#if isParentCategory}} diff --git a/app/assets/javascripts/select-kit/addon/components/category-drop.js b/app/assets/javascripts/select-kit/addon/components/category-drop.js index 3722e734f5f..a0ad319a959 100644 --- a/app/assets/javascripts/select-kit/addon/components/category-drop.js +++ b/app/assets/javascripts/select-kit/addon/components/category-drop.js @@ -128,7 +128,9 @@ export default ComboBoxComponent.extend({ "selectKit.options.subCategory", function() { return getURL( - this.selectKit.options.subCategory ? this.parentCategoryUrl || "/" : "/" + this.selectKit.options.subCategory + ? `${this.parentCategoryUrl}/all` || "/" + : "/" ); } ), diff --git a/app/controllers/categories_controller.rb b/app/controllers/categories_controller.rb index 8a364806096..20e02ab0613 100644 --- a/app/controllers/categories_controller.rb +++ b/app/controllers/categories_controller.rb @@ -329,6 +329,7 @@ class CategoriesController < ApplicationController :required_tag_group_name, :min_tags_from_required_group, :read_only_banner, + :default_list_filter, custom_fields: [params[:custom_fields].try(:keys)], permissions: [*p.try(:keys)], allowed_tags: [], diff --git a/app/serializers/basic_category_serializer.rb b/app/serializers/basic_category_serializer.rb index 540422a0713..87c02a67a92 100644 --- a/app/serializers/basic_category_serializer.rb +++ b/app/serializers/basic_category_serializer.rb @@ -28,6 +28,7 @@ class BasicCategorySerializer < ApplicationSerializer :default_view, :subcategory_list_style, :default_top_period, + :default_list_filter, :minimum_required_tags, :navigate_to_first_post_after_read, :custom_fields diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 8f5e12383f9..b5db1f5059a 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -2826,6 +2826,7 @@ en: sort_order: "Topic List Sort By:" default_view: "Default Topic List:" default_top_period: "Default Top Period:" + default_list_filter: "Default List Filter:" allow_badges_label: "Allow badges to be awarded in this category" edit_permissions: "Edit Permissions" reviewable_by_group: "In addition to staff, posts and flags in this category can be also be reviewed by:" @@ -2888,6 +2889,9 @@ en: moderation: "Moderation" appearance: "Appearance" email: "Email" + list_filters: + all: "all" + none: "none" flagging: title: "Thanks for helping to keep our community civil!" diff --git a/config/routes.rb b/config/routes.rb index e763252bc69..1f843dcf6e3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -686,6 +686,7 @@ Discourse::Application.routes.draw do get "/l/#{filter}" => "list#category_#{filter}", as: "category_#{filter}" end + get "/all" => "list#category_default", as: "category_all", constraints: { format: 'html' } get "/" => "list#category_default", as: "category_default" end diff --git a/spec/requests/api/categories_spec.rb b/spec/requests/api/categories_spec.rb index 5de0bdeee9a..4e3e2bac512 100644 --- a/spec/requests/api/categories_spec.rb +++ b/spec/requests/api/categories_spec.rb @@ -195,6 +195,7 @@ describe 'categories' do default_view: { type: :string, nullable: true }, subcategory_list_style: { type: :string }, default_top_period: { type: :string }, + default_list_filter: { type: :string }, minimum_required_tags: { type: :integer }, navigate_to_first_post_after_read: { type: :boolean }, custom_fields: { @@ -370,6 +371,7 @@ describe 'categories' do default_view: { type: :string, nullable: true }, subcategory_list_style: { type: :string }, default_top_period: { type: :string }, + default_list_filter: { type: :string }, minimum_required_tags: { type: :integer }, navigate_to_first_post_after_read: { type: :boolean }, custom_fields: {