diff --git a/javascripts/discourse/components/categories-groups.js b/javascripts/discourse/components/categories-groups.js index 365ef71..f7538b5 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 categoryGroupVisibility = obj.visibility ?? [0]; // Iterate through each category/link in the order specified in settings categoryArray.forEach((categoryOrLinkId) => { @@ -71,9 +74,14 @@ export default class CategoriesGroups extends Component { } }); - if (categoryGroup.length > 0) { + const displayGroup = categoryGroupVisibility.some((group) => + currentUserGroups.includes(group) + ); + + if (displayGroup && categoryGroup.length > 0) { groups.push({ name: obj.categoryGroup, items: categoryGroup }); } + return groups; }, []); diff --git a/locales/en.yml b/locales/en.yml index cf5a859..73c5619 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." + 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" + 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..3f3965a --- /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, visibility: [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..da60db9 100644 --- a/settings.yml +++ b/settings.yml @@ -1,52 +1,63 @@ -category_groups: - type: "list" - default: "Default Categories: staff, site-feedback, lounge" -extra_links: - default: > - [] - json_schema: >- +grouped_categories: + refresh: true + 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", + "visibility": [ + 0 + ] } + ] + schema: + name: "Category Groups" + identifier: categoryGroup + properties: + categoryGroup: + type: string + required: true + categories: + type: string + required: true + visibility: + type: groups + min: 1 + +links: + refresh: true + 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 diff --git a/spec/system/custom_category_group_spec.rb b/spec/system/custom_category_group_spec.rb index 6e30d04..f8ec0bf 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!