diff --git a/app/assets/javascripts/discourse/app/components/sidebar/api-section.gjs b/app/assets/javascripts/discourse/app/components/sidebar/api-section.gjs index 6e46073a77c..3cc7fa9a059 100644 --- a/app/assets/javascripts/discourse/app/components/sidebar/api-section.gjs +++ b/app/assets/javascripts/discourse/app/components/sidebar/api-section.gjs @@ -1,99 +1,55 @@ -import Component from "@glimmer/component"; -import { getOwner, setOwner } from "@ember/owner"; -import { service } from "@ember/service"; import Section from "./section"; import SectionLink from "./section-link"; -export default class SidebarApiSection extends Component { - @service sidebarState; +const SidebarApiSection = ; - constructor() { - super(...arguments); - - this.section = new this.args.sectionConfig(); - setOwner(this.section, getOwner(this)); - } - - get shouldDisplay() { - return ( - !this.sidebarState.currentPanel.filterable || - this.sidebarState.filter.length === 0 || - this.filteredLinks.length > 0 - ); - } - - get filteredLinks() { - if (!this.sidebarState.filter) { - return this.section.links; - } - - if ( - this.section.text.toLowerCase().match(this.sidebarState.sanitizedFilter) - ) { - return this.section.links; - } - - return this.section.links.filter((link) => { - return ( - link.text - .toString() - .toLowerCase() - .match(this.sidebarState.sanitizedFilter) || - link.keywords.navigation.some((keyword) => - keyword.match(this.sidebarState.filter) - ) - ); - }); - } - - -} +export default SidebarApiSection; diff --git a/app/assets/javascripts/discourse/app/components/sidebar/api-sections.gjs b/app/assets/javascripts/discourse/app/components/sidebar/api-sections.gjs index 47607ea4200..7d527ae53e2 100644 --- a/app/assets/javascripts/discourse/app/components/sidebar/api-sections.gjs +++ b/app/assets/javascripts/discourse/app/components/sidebar/api-sections.gjs @@ -1,32 +1,89 @@ import Component from "@glimmer/component"; +import { cached } from "@glimmer/tracking"; +import { getOwner, setOwner } from "@ember/owner"; import { service } from "@ember/service"; -import AdminHeader from "./admin-header"; import ApiSection from "./api-section"; -import FilterNoResults from "./filter-no-results"; +import PanelHeader from "./panel-header"; export default class SidebarApiSections extends Component { @service sidebarState; get sections() { + let sectionConfigs; + if (this.sidebarState.combinedMode) { - return this.sidebarState.panels + sectionConfigs = this.sidebarState.panels .filter((panel) => !panel.hidden) .flatMap((panel) => panel.sections); } else { - return this.sidebarState.currentPanel.sections; + sectionConfigs = this.sidebarState.currentPanel.sections; } + + return sectionConfigs.map((Section) => { + const SidebarSection = prepareSidebarSectionClass(Section); + + const sectionInstance = new SidebarSection({ + filterable: + !this.sidebarState.combinedMode && + this.sidebarState.currentPanel.filterable, + sidebarState: this.sidebarState, + }); + + setOwner(sectionInstance, getOwner(this)); + + return sectionInstance; + }); + } + + get filteredSections() { + return this.sections.filter((section) => section.filtered); } } + +// extends the class provided for the section to add functionality we don't want to be overridable when defining custom +// sections using the plugin API, like for example the filtering capabilities +function prepareSidebarSectionClass(Section) { + return class extends Section { + constructor({ filterable, sidebarState }) { + super(); + + this.filterable = filterable; + this.sidebarState = sidebarState; + } + + @cached + get filteredLinks() { + if (!this.filterable || !this.sidebarState.filter) { + return this.links; + } + + if (this.text.toLowerCase().match(this.sidebarState.sanitizedFilter)) { + return this.links; + } + + return this.links.filter((link) => { + return ( + link.text + .toString() + .toLowerCase() + .match(this.sidebarState.sanitizedFilter) || + link.keywords.navigation.some((keyword) => + keyword.match(this.sidebarState.filter) + ) + ); + }); + } + + get filtered() { + return !this.filterable || this.filteredLinks?.length > 0; + } + }; +} diff --git a/app/assets/javascripts/discourse/app/components/sidebar/back-to-forum.gjs b/app/assets/javascripts/discourse/app/components/sidebar/back-to-forum.gjs index 7d85e4cca1b..5f237193d3a 100644 --- a/app/assets/javascripts/discourse/app/components/sidebar/back-to-forum.gjs +++ b/app/assets/javascripts/discourse/app/components/sidebar/back-to-forum.gjs @@ -1,28 +1,17 @@ -import Component from "@glimmer/component"; import { LinkTo } from "@ember/routing"; -import { service } from "@ember/service"; -import { ADMIN_PANEL } from "discourse/lib/sidebar/panels"; import { defaultHomepage } from "discourse/lib/utilities"; import icon from "discourse-common/helpers/d-icon"; import i18n from "discourse-common/helpers/i18n"; -export default class BackToForum extends Component { - @service sidebarState; +const BackToForum = ; - -} +export default BackToForum; diff --git a/app/assets/javascripts/discourse/app/components/sidebar/filter-no-results.gjs b/app/assets/javascripts/discourse/app/components/sidebar/filter-no-results.gjs index f0fb2701503..8c9330e8e7d 100644 --- a/app/assets/javascripts/discourse/app/components/sidebar/filter-no-results.gjs +++ b/app/assets/javascripts/discourse/app/components/sidebar/filter-no-results.gjs @@ -1,32 +1,21 @@ import Component from "@glimmer/component"; import { service } from "@ember/service"; -import { htmlSafe } from "@ember/template"; import i18n from "discourse-common/helpers/i18n"; -import getURL from "discourse-common/lib/get-url"; -import I18n from "discourse-i18n"; export default class FilterNoResults extends Component { @service sidebarState; - /** - * Component is rendered when panel is filtreable - * Visibility is additionally controlled by CSS rule `.sidebar-section-wrapper + .sidebar-no-results` - */ get shouldDisplay() { - return this.sidebarState.currentPanel.filterable; + return ( + this.sidebarState.currentPanel.filterable && + !!(this.args.sections?.length === 0) + ); } get noResultsDescription() { - const params = { - filter: this.sidebarState.filter, - settings_filter_url: getURL( - `/admin/site_settings/category/all_results?filter=${this.sidebarState.filter}` - ), - user_list_filter_url: getURL( - `/admin/users/list/active?username=${this.sidebarState.filter}` - ), - }; - return htmlSafe(I18n.t("sidebar.no_results.description", params)); + return this.sidebarState.currentPanel.filterNoResultsDescription( + this.sidebarState.filter + ); } diff --git a/app/assets/javascripts/discourse/app/components/sidebar/footer.gjs b/app/assets/javascripts/discourse/app/components/sidebar/footer.gjs index eddcb7fb13d..58ddde88fc1 100644 --- a/app/assets/javascripts/discourse/app/components/sidebar/footer.gjs +++ b/app/assets/javascripts/discourse/app/components/sidebar/footer.gjs @@ -5,7 +5,7 @@ import DButton from "discourse/components/d-button"; import SidebarSectionForm from "discourse/components/modal/sidebar-section-form"; import PluginOutlet from "discourse/components/plugin-outlet"; import routeAction from "discourse/helpers/route-action"; -import { ADMIN_PANEL } from "discourse/lib/sidebar/panels"; +import { MAIN_PANEL } from "discourse/lib/sidebar/panels"; export default class SidebarFooter extends Component { @service capabilities; @@ -16,7 +16,7 @@ export default class SidebarFooter extends Component { @service sidebarState; get showManageSectionsButton() { - return this.currentUser && !this.sidebarState.isCurrentPanel(ADMIN_PANEL); + return this.currentUser && this.sidebarState.isCurrentPanel(MAIN_PANEL); } get showToggleMobileButton() { diff --git a/app/assets/javascripts/discourse/app/components/sidebar/admin-header.gjs b/app/assets/javascripts/discourse/app/components/sidebar/panel-header.gjs similarity index 58% rename from app/assets/javascripts/discourse/app/components/sidebar/admin-header.gjs rename to app/assets/javascripts/discourse/app/components/sidebar/panel-header.gjs index 272f2acf344..abd01d2b021 100644 --- a/app/assets/javascripts/discourse/app/components/sidebar/admin-header.gjs +++ b/app/assets/javascripts/discourse/app/components/sidebar/panel-header.gjs @@ -1,28 +1,29 @@ import Component from "@glimmer/component"; import { service } from "@ember/service"; -import { ADMIN_PANEL } from "discourse/lib/sidebar/panels"; import BackToForum from "./back-to-forum"; import Filter from "./filter"; +import FilterNoResults from "./filter-no-results"; import ToggleAllSections from "./toggle-all-sections"; -export default class AdminHeader extends Component { +export default class PanelHeader extends Component { @service sidebarState; get shouldDisplay() { - return this.sidebarState.isCurrentPanel(ADMIN_PANEL); + return this.sidebarState.currentPanel.displayHeader; } } diff --git a/app/assets/javascripts/discourse/app/components/sidebar/section-header.gjs b/app/assets/javascripts/discourse/app/components/sidebar/section-header.gjs index d2dab8694df..5458ac7044f 100644 --- a/app/assets/javascripts/discourse/app/components/sidebar/section-header.gjs +++ b/app/assets/javascripts/discourse/app/components/sidebar/section-header.gjs @@ -5,7 +5,7 @@ const SidebarSectionHeader =