From b36cbc7d219f686eb6bd7848bd0bd9d20f4314ec Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9rgio=20Saquetim?=
<1108771+megothss@users.noreply.github.com>
Date: Fri, 5 Jul 2024 13:11:15 -0300
Subject: [PATCH] DEV: Untangle the admin sidebar from the sidebar code
(#27640)
---
.../app/components/sidebar/api-section.gjs | 146 ++++++------------
.../app/components/sidebar/api-sections.gjs | 81 ++++++++--
.../app/components/sidebar/back-to-forum.gjs | 31 ++--
.../components/sidebar/filter-no-results.gjs | 33 ++--
.../app/components/sidebar/footer.gjs | 4 +-
.../{admin-header.gjs => panel-header.gjs} | 13 +-
.../app/components/sidebar/section-header.gjs | 2 +-
.../app/components/sidebar/section.gjs | 14 +-
.../sidebar/toggle-all-sections.gjs | 23 +--
.../app/lib/sidebar/admin-sidebar.js | 18 +++
.../lib/sidebar/base-custom-sidebar-panel.js | 18 +++
.../discourse/app/lib/sidebar/helpers.js | 8 +
.../discourse/app/services/sidebar-state.js | 7 +-
.../stylesheets/common/base/menu-panel.scss | 2 +-
.../stylesheets/common/base/sidebar.scss | 5 +-
config/locales/client.en.yml | 6 +-
spec/system/admin_sidebar_navigation_spec.rb | 26 ++++
.../components/navigation_menu/sidebar.rb | 8 +
spec/system/viewing_sidebar_spec.rb | 6 +
19 files changed, 270 insertions(+), 181 deletions(-)
rename app/assets/javascripts/discourse/app/components/sidebar/{admin-header.gjs => panel-header.gjs} (58%)
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 =
+ {{#if @section.filtered}}
+
+ {{#each @section.filteredLinks key="name" as |link|}}
+
+ {{/each}}
+
+ {{/if}}
+;
- 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)
- )
- );
- });
- }
-
-
- {{#if this.shouldDisplay}}
-
- {{#each this.filteredLinks key="name" as |link|}}
-
- {{/each}}
-
- {{/if}}
-
-}
+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);
}
-
+
- {{#each this.sections as |sectionConfig|}}
-
+ {{#each this.filteredSections as |section|}}
+
{{/each}}
-
-
}
+
+// 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 =
+
+;
-
- {{#if this.shouldDisplay}}
-
- {{/if}}
-
-}
+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
+ );
}
@@ -35,9 +24,11 @@ export default class FilterNoResults extends Component {
-
+ {{#if this.noResultsDescription}}
+
+ {{/if}}
{{/if}}
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;
}
{{#if this.shouldDisplay}}
-