DEV: Migrate `categories` setting to new objects setting type (#51)
Since https://github.com/discourse/discourse/commit/a440e15, we have started to support objects typed theme setting so we are switching this theme component to use it instead as it provides a much better UX for configuring the settings required for the theme component.
This commit is contained in:
parent
7da1900e78
commit
04c2b2b6ff
|
@ -1,3 +1,4 @@
|
||||||
|
< 3.3.0.beta2-dev: 7da1900e78ba47886f44f9ab09036c3dd6b66f56
|
||||||
< 3.3.0.beta1-dev: c46f2905bde50b23f9008560c747d635f5a73455
|
< 3.3.0.beta1-dev: c46f2905bde50b23f9008560c747d635f5a73455
|
||||||
< 3.2.0.beta2: 1398eeeff550c1da186a47b6d3878d3230f62340
|
< 3.2.0.beta2: 1398eeeff550c1da186a47b6d3878d3230f62340
|
||||||
3.1.999: e7b1e68708abaad7a815d69228075cf57b532f11
|
3.1.999: e7b1e68708abaad7a815d69228075cf57b532f11
|
||||||
|
|
|
@ -55,20 +55,6 @@ export default class DiscourseCategoryBanners extends Component {
|
||||||
return settings.show_description && this.category.description?.length > 0;
|
return settings.show_description && this.category.description?.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#parseCategories(categoriesStr) {
|
|
||||||
const categories = {};
|
|
||||||
categoriesStr.split("|").forEach((item) => {
|
|
||||||
item = item.split(":");
|
|
||||||
|
|
||||||
if (item[0]) {
|
|
||||||
categories[item[0].toLowerCase()] = item[1]
|
|
||||||
? item[1].toLowerCase()
|
|
||||||
: "all";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return categories;
|
|
||||||
}
|
|
||||||
|
|
||||||
#parseExceptions(exceptionsStr) {
|
#parseExceptions(exceptionsStr) {
|
||||||
return exceptionsStr
|
return exceptionsStr
|
||||||
.split("|")
|
.split("|")
|
||||||
|
@ -76,20 +62,41 @@ export default class DiscourseCategoryBanners extends Component {
|
||||||
.map((value) => value.toLowerCase());
|
.map((value) => value.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
#checkTargetCategory(categories) {
|
#checkTargetCategory() {
|
||||||
const currentCategoryName = this.category?.name.toLowerCase();
|
if (settings.categories.length === 0) {
|
||||||
const parentCategoryName = this.category?.parentCategory
|
return true;
|
||||||
? this.category.parentCategory.name.toLowerCase()
|
}
|
||||||
: null;
|
|
||||||
|
|
||||||
return (
|
const currentCategoryId = this.category?.id;
|
||||||
Object.keys(categories).length === 0 ||
|
|
||||||
categories[currentCategoryName] === "all" ||
|
const activeCategory = settings.categories.find((category) => {
|
||||||
categories[currentCategoryName] === "no_sub" ||
|
return category.category_id[0] === currentCategoryId;
|
||||||
(this.category?.parentCategory &&
|
});
|
||||||
(categories[parentCategoryName] === "all" ||
|
|
||||||
categories[parentCategoryName] === "only_sub"))
|
if (
|
||||||
);
|
activeCategory &&
|
||||||
|
(activeCategory.target === "all" || activeCategory.target === "no_sub")
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parentCategoryId = this.category?.parentCategory?.id;
|
||||||
|
|
||||||
|
if (parentCategoryId) {
|
||||||
|
const activeParentCategory = settings.categories.find((category) => {
|
||||||
|
return category.category_id[0] === parentCategoryId;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (
|
||||||
|
activeParentCategory &&
|
||||||
|
(activeParentCategory.target === "all" ||
|
||||||
|
activeParentCategory.target === "only_sub")
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
|
@ -117,10 +124,9 @@ export default class DiscourseCategoryBanners extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const categories = this.#parseCategories(settings.categories);
|
|
||||||
const exceptions = this.#parseExceptions(settings.exceptions);
|
const exceptions = this.#parseExceptions(settings.exceptions);
|
||||||
const isException = exceptions.includes(this.category?.name.toLowerCase());
|
const isException = exceptions.includes(this.category?.name.toLowerCase());
|
||||||
const isTarget = this.#checkTargetCategory(categories);
|
const isTarget = this.#checkTargetCategory();
|
||||||
const hideMobile = this.site.mobileView && !settings.show_mobile;
|
const hideMobile = this.site.mobileView && !settings.show_mobile;
|
||||||
const hideSubCategory =
|
const hideSubCategory =
|
||||||
this.category?.parentCategory && !settings.show_subcategory;
|
this.category?.parentCategory && !settings.show_subcategory;
|
||||||
|
|
|
@ -6,15 +6,20 @@ en:
|
||||||
show_subcategory: 'Show banners for subcategories'
|
show_subcategory: 'Show banners for subcategories'
|
||||||
hide_if_no_description: 'Hide banners if category description is not set'
|
hide_if_no_description: 'Hide banners if category description is not set'
|
||||||
show_category_logo: 'Show category logo'
|
show_category_logo: 'Show category logo'
|
||||||
exceptions: "Banner will not show for these category NAMES."
|
exceptions: "Banner will not show for these category NAMES"
|
||||||
categories: |
|
categories:
|
||||||
Banner will only show for these categories. Format as <code>name:target</code> (e.g., <code>staff:all</code>).
|
description: Categories to show a banner for
|
||||||
Accepted targets:
|
schema:
|
||||||
<ul>
|
properties:
|
||||||
<li> all - named category and subcategories (default);
|
category_id:
|
||||||
<li> no_sub - only the named category;
|
label: Category
|
||||||
<li> only_sub - only subcategories of the named category.
|
description: "Category to show a banner for"
|
||||||
</ul>
|
target:
|
||||||
plugin_outlet: "Changes the position of the banner on the page."
|
label: Target
|
||||||
|
description: |
|
||||||
|
all - Banner will show for selected category and its subcategories
|
||||||
|
no_sub - Banner will only show for the selected category
|
||||||
|
only_sub - Banner will only show for the subcategories of the selected category
|
||||||
|
plugin_outlet: "Changes the position of the banner on the page"
|
||||||
show_category_icon: Show category icon from the <a href="https://meta.discourse.org/t/category-icons/104683" target="_blank">Discourse Category Icons component</a>
|
show_category_icon: Show category icon from the <a href="https://meta.discourse.org/t/category-icons/104683" target="_blank">Discourse Category Icons component</a>
|
||||||
override_category_icon_color: When the category icons are used, enabling this will make the icon match the banner text color
|
override_category_icon_color: When the category icons are used, enabling this will make the icon match the banner text color
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
const VALID_TARGETS = ["all", "no_sub", "only_sub"];
|
||||||
|
|
||||||
|
export default function migrate(settings, helpers) {
|
||||||
|
if (settings.has("categories")) {
|
||||||
|
const categories = settings.get("categories");
|
||||||
|
const newCategories = [];
|
||||||
|
|
||||||
|
categories.split("|").forEach((item) => {
|
||||||
|
const [categoryName, target] = item.split(":");
|
||||||
|
const categoryId = helpers.getCategoryIdByName(categoryName);
|
||||||
|
|
||||||
|
if (categoryId) {
|
||||||
|
const category = {
|
||||||
|
category_id: [categoryId],
|
||||||
|
};
|
||||||
|
|
||||||
|
if (VALID_TARGETS.includes(target)) {
|
||||||
|
category.target = target;
|
||||||
|
} else {
|
||||||
|
category.target = "all";
|
||||||
|
}
|
||||||
|
|
||||||
|
newCategories.push(category);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
settings.set("categories", newCategories);
|
||||||
|
}
|
||||||
|
|
||||||
|
return settings;
|
||||||
|
}
|
28
settings.yml
28
settings.yml
|
@ -27,16 +27,24 @@ exceptions:
|
||||||
list_type: simple
|
list_type: simple
|
||||||
|
|
||||||
categories:
|
categories:
|
||||||
default: ""
|
type: objects
|
||||||
type: list
|
default: []
|
||||||
description: |
|
schema:
|
||||||
Banner will only show for these categories. Format as <code>name:target</code> (e.g., <code>staff:all</code>).
|
name: category
|
||||||
Accepted targets:
|
identifier: category_id
|
||||||
<ul>
|
properties:
|
||||||
<li> all - named category and subcategories (default);
|
category_id:
|
||||||
<li> no_sub - only the named category;
|
type: categories
|
||||||
<li> only_sub - only subcategories of the named category.
|
required: true
|
||||||
</ul>
|
validations:
|
||||||
|
max: 1
|
||||||
|
target:
|
||||||
|
type: enum
|
||||||
|
default: all
|
||||||
|
choices:
|
||||||
|
- all
|
||||||
|
- no_sub
|
||||||
|
- only_sub
|
||||||
|
|
||||||
plugin_outlet:
|
plugin_outlet:
|
||||||
default: "below-site-header"
|
default: "below-site-header"
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
RSpec.describe "0001-migrate-categories-setting migration" do
|
||||||
|
let!(:theme) { upload_theme_component }
|
||||||
|
|
||||||
|
fab!(:category_1) { Fabricate(:category) }
|
||||||
|
fab!(:category_2) { Fabricate(:category) }
|
||||||
|
fab!(:category_3) { Fabricate(:category) }
|
||||||
|
fab!(:category_4) { Fabricate(:category) }
|
||||||
|
|
||||||
|
it "sets target to `all` if previous target property is not one of `all`, `no_sub` or `only_sub`" do
|
||||||
|
theme.theme_settings.create!(
|
||||||
|
name: "categories",
|
||||||
|
theme:,
|
||||||
|
data_type: ThemeSetting.types[:string],
|
||||||
|
value: "#{category_1.name}:something|#{category_2.name}:something_else",
|
||||||
|
)
|
||||||
|
|
||||||
|
run_theme_migration(theme, "0001-migrate-categories-setting")
|
||||||
|
|
||||||
|
expect(theme.settings[:categories].value).to eq(
|
||||||
|
[
|
||||||
|
{ "category_id" => [category_1.id], "target" => "all" },
|
||||||
|
{ "category_id" => [category_2.id], "target" => "all" },
|
||||||
|
],
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not migrate settings where a relevant category is not found for the given category names in the database" do
|
||||||
|
theme.theme_settings.create!(
|
||||||
|
name: "categories",
|
||||||
|
theme:,
|
||||||
|
data_type: ThemeSetting.types[:string],
|
||||||
|
value: "non_existent_category:something",
|
||||||
|
)
|
||||||
|
|
||||||
|
run_theme_migration(theme, "0001-migrate-categories-setting")
|
||||||
|
|
||||||
|
expect(theme.settings[:categories].value).to eq([])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should migrate settings where a relevant category is found for the given category names in the database" do
|
||||||
|
theme.theme_settings.create!(
|
||||||
|
name: "categories",
|
||||||
|
theme:,
|
||||||
|
data_type: ThemeSetting.types[:string],
|
||||||
|
value:
|
||||||
|
"#{category_1.name}:no_sub|#{category_2.name}:only_sub|invalid:something_else|#{category_3.name}:all|#{category_4.name}",
|
||||||
|
)
|
||||||
|
|
||||||
|
run_theme_migration(theme, "0001-migrate-categories-setting")
|
||||||
|
|
||||||
|
expect(theme.settings[:categories].value).to eq(
|
||||||
|
[
|
||||||
|
{ "category_id" => [category_1.id], "target" => "no_sub" },
|
||||||
|
{ "category_id" => [category_2.id], "target" => "only_sub" },
|
||||||
|
{ "category_id" => [category_3.id], "target" => "all" },
|
||||||
|
{ "category_id" => [category_4.id], "target" => "all" },
|
||||||
|
],
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
|
@ -26,7 +26,7 @@ RSpec.describe "Category Banners", type: :system do
|
||||||
|
|
||||||
context "when `categories` setting has been set" do
|
context "when `categories` setting has been set" do
|
||||||
it "displays category banner for category and its subcategory when target is set to `all`" do
|
it "displays category banner for category and its subcategory when target is set to `all`" do
|
||||||
theme.update_setting(:categories, "#{category.name}:all")
|
theme.update_setting(:categories, [{ category_id: [category.id], target: "all" }])
|
||||||
theme.save!
|
theme.save!
|
||||||
|
|
||||||
visit(category.url)
|
visit(category.url)
|
||||||
|
@ -39,7 +39,7 @@ RSpec.describe "Category Banners", type: :system do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "displays category banner only for root category when target is set to `no_sub`" do
|
it "displays category banner only for root category when target is set to `no_sub`" do
|
||||||
theme.update_setting(:categories, "#{category.name}:no_sub")
|
theme.update_setting(:categories, [{ category_id: [category.id], target: "no_sub" }])
|
||||||
theme.save!
|
theme.save!
|
||||||
|
|
||||||
visit(category.url)
|
visit(category.url)
|
||||||
|
@ -52,7 +52,7 @@ RSpec.describe "Category Banners", type: :system do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "displays category banner only for sub categories when target is set to `only_sub`" do
|
it "displays category banner only for sub categories when target is set to `only_sub`" do
|
||||||
theme.update_setting(:categories, "#{category.name}:only_sub")
|
theme.update_setting(:categories, [{ category_id: [category.id], target: "only_sub" }])
|
||||||
theme.save!
|
theme.save!
|
||||||
|
|
||||||
visit(category.url)
|
visit(category.url)
|
||||||
|
|
Loading…
Reference in New Issue