From a13000451b44d2f3aaf0d22e75a48fe69d630cb2 Mon Sep 17 00:00:00 2001 From: Osman Gormus Date: Sat, 12 Apr 2025 02:13:19 +0200 Subject: [PATCH 1/5] feat(settings): replace json_schema settings with object type Add a visibility option based on user groups. --- .../discourse/components/categories-groups.js | 29 +++-- locales/en.yml | 37 ++++++- migrations/settings/0001-use-objects.js | 20 ++++ settings.yml | 103 ++++++++++-------- 4 files changed, 130 insertions(+), 59 deletions(-) create mode 100644 migrations/settings/0001-use-objects.js diff --git a/javascripts/discourse/components/categories-groups.js b/javascripts/discourse/components/categories-groups.js index 365ef71..d261763 100644 --- a/javascripts/discourse/components/categories-groups.js +++ b/javascripts/discourse/components/categories-groups.js @@ -4,13 +4,6 @@ import { service } from "@ember/service"; import { slugify } from "discourse/lib/utilities"; import { i18n } from "discourse-i18n"; -function parseSettings(settings) { - return settings.split("|").map((i) => { - const [categoryGroup, categories] = i.split(":").map((str) => str.trim()); - return { categoryGroup, categories }; - }); -} - const ExtraLink = class { constructor(args) { this.isExtraLink = true; @@ -38,8 +31,17 @@ export default class CategoriesGroups extends Component { } get categoryGroupList() { - const parsedSettings = parseSettings(settings.category_groups); - const extraLinks = JSON.parse(settings.extra_links || "[]"); + const parsedSettings = settings.grouped_categories; + const extraLinks = settings.links; + + let currentUserGroups = [0]; + const currentUser = this.currentUser; + + if (currentUser) { + currentUser.groups.filter((group) => { + currentUserGroups.push(group.id); + }); + } // Initialize an array to keep track of found categories and used links const foundCategories = []; @@ -52,6 +54,7 @@ export default class CategoriesGroups extends Component { const categoryGroupList = parsedSettings.reduce((groups, obj) => { const categoryArray = obj.categories.split(",").map((str) => str.trim()); const categoryGroup = []; + const securityGroups = obj.security ?? [0]; // Iterate through each category/link in the order specified in settings categoryArray.forEach((categoryOrLinkId) => { @@ -74,7 +77,13 @@ export default class CategoriesGroups extends Component { if (categoryGroup.length > 0) { groups.push({ name: obj.categoryGroup, items: categoryGroup }); } - return groups; + + if (securityGroups.some((group) => + currentUserGroups.includes(group) + )) { + return groups; + } + return []; }, []); // Find ungrouped categories diff --git a/locales/en.yml b/locales/en.yml index cf5a859..e4e5b93 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -2,8 +2,41 @@ en: theme_metadata: description: "custom category page with group settings" settings: - category_groups: "Format as: Group name: category-slug, extra-link-id, category-slug-2" - extra_links: "Extra links that can be mixed into category list. Add link ID in category_groups setting to render" + grouped_categories: + description: "Group categories together" + schema: + properties: + categoryGroup: + label: "Group heading" + description: "The name of the group" + categories: + label: "Slugs" + description: "The category slugs and/or extra-link IDs, separated by commas." + security: + label: "Security" + description: "The user groups that can see this category group. Leave empty, or select 'everyone' to show to all users." + links: + description: "Extra links that can be mixed into category list. Add link ID in Grouped categories setting to render" + schema: + properties: + id: + label: "ID" + description: "The ID of the link" + url: + label: "URL" + description: "The URL of the link" + color: + label: "Color" + description: "CSS compatible hexadecimal color code for the link. ie. #F1592A" + title: + label: "Title" + description: "The title of the link" + description: + label: "Description" + description: "The description of the link" + icon: + label: "Icon" + description: "The icon of the link" show_on_mobile: "Show the collapsible category box groups on mobile" show_ungrouped: "Display a group of categories that aren't assigned to another group" hide_muted_subcategories: "When enabled, a non-muted parent category will not appear under the muted section if it has a muted subcategory" diff --git a/migrations/settings/0001-use-objects.js b/migrations/settings/0001-use-objects.js new file mode 100644 index 0000000..ce6ce87 --- /dev/null +++ b/migrations/settings/0001-use-objects.js @@ -0,0 +1,20 @@ +export default function migrate(settings) { + if (settings.has("category_groups")) { + const groups = settings.get("category_groups"); + const categoryGroups = groups.split("|").map((i) => { + const [categoryGroup, categories] = i.split(":").map((str) => str.trim()); + return { categoryGroup, categories, security: [0] }; + }); + + settings.set("grouped_categories", categoryGroups); + settings.delete("category_groups"); + } + + if (settings.has("extra_links")) { + const links = settings.get("extra_links"); + settings.set("links", JSON.parse(links || "[]")); + settings.delete("extra_links"); + } + + return settings; +} \ No newline at end of file diff --git a/settings.yml b/settings.yml index ef458c0..07040a9 100644 --- a/settings.yml +++ b/settings.yml @@ -1,52 +1,61 @@ -category_groups: - type: "list" - default: "Default Categories: staff, site-feedback, lounge" -extra_links: - default: > - [] - json_schema: >- +grouped_categories: + type: objects + default: [ { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string", - "title": "ID", - "description": "A unique identifier for the link" - }, - "url": { - "type": "string", - "title": "URL", - "description": "The URL for the link" - }, - "color": { - "type": "string", - "title": "Color", - "description": "The color associated with the link", - "format": "color" - }, - "title": { - "type": "string", - "title": "Title", - "description": "The title of the link" - }, - "description": { - "type": "string", - "format": "markdown", - "title": "Description", - "description": "A short description of the link" - }, - "icon": { - "type": "string", - "title": "Icon", - "description": "An icon for the link. Example: heart", - "default": "" - } - }, - "required": ["id", "url", "title", "color"] - } + "categoryGroup": "Default Categories", + "categories": "staff, site-feedback, lounge", + "security": [ + 0 + ] } + ] + schema: + name: "Category Groups" + identifier: categoryGroup + properties: + categoryGroup: + type: string + required: true + categories: + type: string + required: true + security: + type: groups + min: 1 + +links: + type: objects + default: [ + { + "id": "example", + "url": "https://example.com", + "color": "#F1592A", + "title": "Example Link", + "description": "This is an example link", + "icon": "" + } + ] + schema: + name: "Links" + identifier: id + properties: + id: + type: string + required: true + url: + type: string + required: true + url: true + color: + type: string + required: true + title: + type: string + required: true + description: + type: string + icon: + type: string show_on_mobile: default: true From ae44a52af47c38600234de321c0e448994c94cc2 Mon Sep 17 00:00:00 2001 From: Osman Gormus Date: Sat, 12 Apr 2025 11:14:34 +0200 Subject: [PATCH 2/5] chore(visibility): fixed group visibility --- .../discourse/components/categories-groups.js | 13 ++++++------- settings.yml | 2 ++ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/javascripts/discourse/components/categories-groups.js b/javascripts/discourse/components/categories-groups.js index d261763..126317d 100644 --- a/javascripts/discourse/components/categories-groups.js +++ b/javascripts/discourse/components/categories-groups.js @@ -74,16 +74,15 @@ export default class CategoriesGroups extends Component { } }); - if (categoryGroup.length > 0) { + const displayGroup = securityGroups.some((group) => + currentUserGroups.includes(group) + ); + + if (displayGroup && categoryGroup.length > 0) { groups.push({ name: obj.categoryGroup, items: categoryGroup }); } - if (securityGroups.some((group) => - currentUserGroups.includes(group) - )) { - return groups; - } - return []; + return groups; }, []); // Find ungrouped categories diff --git a/settings.yml b/settings.yml index 07040a9..9bfe014 100644 --- a/settings.yml +++ b/settings.yml @@ -1,4 +1,5 @@ grouped_categories: + refresh: true type: objects default: [ { @@ -24,6 +25,7 @@ grouped_categories: min: 1 links: + refresh: true type: objects default: [ { From 2430b735b52dcdf23ab3f2cf376f6aa9d1355ecb Mon Sep 17 00:00:00 2001 From: Osman Gormus Date: Sat, 12 Apr 2025 11:23:27 +0200 Subject: [PATCH 3/5] chore(visibility): rename the new feature more appropriately --- javascripts/discourse/components/categories-groups.js | 4 ++-- locales/en.yml | 4 ++-- migrations/settings/0001-use-objects.js | 2 +- settings.yml | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/javascripts/discourse/components/categories-groups.js b/javascripts/discourse/components/categories-groups.js index 126317d..f7538b5 100644 --- a/javascripts/discourse/components/categories-groups.js +++ b/javascripts/discourse/components/categories-groups.js @@ -54,7 +54,7 @@ export default class CategoriesGroups extends Component { const categoryGroupList = parsedSettings.reduce((groups, obj) => { const categoryArray = obj.categories.split(",").map((str) => str.trim()); const categoryGroup = []; - const securityGroups = obj.security ?? [0]; + const categoryGroupVisibility = obj.visibility ?? [0]; // Iterate through each category/link in the order specified in settings categoryArray.forEach((categoryOrLinkId) => { @@ -74,7 +74,7 @@ export default class CategoriesGroups extends Component { } }); - const displayGroup = securityGroups.some((group) => + const displayGroup = categoryGroupVisibility.some((group) => currentUserGroups.includes(group) ); diff --git a/locales/en.yml b/locales/en.yml index e4e5b93..73c5619 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -12,8 +12,8 @@ en: categories: label: "Slugs" description: "The category slugs and/or extra-link IDs, separated by commas." - security: - label: "Security" + visibility: + label: "Visibility" description: "The user groups that can see this category group. Leave empty, or select 'everyone' to show to all users." links: description: "Extra links that can be mixed into category list. Add link ID in Grouped categories setting to render" diff --git a/migrations/settings/0001-use-objects.js b/migrations/settings/0001-use-objects.js index ce6ce87..3f3965a 100644 --- a/migrations/settings/0001-use-objects.js +++ b/migrations/settings/0001-use-objects.js @@ -3,7 +3,7 @@ export default function migrate(settings) { const groups = settings.get("category_groups"); const categoryGroups = groups.split("|").map((i) => { const [categoryGroup, categories] = i.split(":").map((str) => str.trim()); - return { categoryGroup, categories, security: [0] }; + return { categoryGroup, categories, visibility: [0] }; }); settings.set("grouped_categories", categoryGroups); diff --git a/settings.yml b/settings.yml index 9bfe014..da60db9 100644 --- a/settings.yml +++ b/settings.yml @@ -5,7 +5,7 @@ grouped_categories: { "categoryGroup": "Default Categories", "categories": "staff, site-feedback, lounge", - "security": [ + "visibility": [ 0 ] } @@ -20,7 +20,7 @@ grouped_categories: categories: type: string required: true - security: + visibility: type: groups min: 1 From ab814ad45dcf9a0f8957b51020c6305b3e69509c Mon Sep 17 00:00:00 2001 From: Osman Gormus Date: Sat, 12 Apr 2025 22:25:45 +0200 Subject: [PATCH 4/5] chore(tests): fix tests for changed settings --- spec/system/custom_category_group_spec.rb | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/spec/system/custom_category_group_spec.rb b/spec/system/custom_category_group_spec.rb index 6e30d04..43acb30 100644 --- a/spec/system/custom_category_group_spec.rb +++ b/spec/system/custom_category_group_spec.rb @@ -18,7 +18,7 @@ def self.description before do sign_in(Fabricate(:admin)) theme_component.update_setting( - :extra_links, + :links, [ { "id" => ExampleGroupLink.id, @@ -32,8 +32,14 @@ def self.description ) theme_component.update_setting(:fancy_styling, true) theme_component.update_setting( - :category_groups, - "Default Categories: #{ExampleGroupLink.id}, #{category.slug}", + :grouped_categories, + [ + { + "categoryGroup" => "Default Categories", + "categories" => "#{ExampleGroupLink.id}, #{category.slug}", + "visibility" => [0], + } + ].to_json, ) SiteSetting.desktop_category_page_style = "categories_boxes" theme_component.save! From 51b660b6207b5f0602ee4abf59e5b68bffbda408 Mon Sep 17 00:00:00 2001 From: Osman Gormus Date: Sat, 12 Apr 2025 22:38:49 +0200 Subject: [PATCH 5/5] chore(tests): fix trailing_comma formatting issue --- spec/system/custom_category_group_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/system/custom_category_group_spec.rb b/spec/system/custom_category_group_spec.rb index 43acb30..f8ec0bf 100644 --- a/spec/system/custom_category_group_spec.rb +++ b/spec/system/custom_category_group_spec.rb @@ -38,7 +38,7 @@ def self.description "categoryGroup" => "Default Categories", "categories" => "#{ExampleGroupLink.id}, #{category.slug}", "visibility" => [0], - } + }, ].to_json, ) SiteSetting.desktop_category_page_style = "categories_boxes"