diff --git a/app/assets/javascripts/admin/addon/components/admin-config-area-sidebar-experiment.js b/app/assets/javascripts/admin/addon/components/admin-config-area-sidebar-experiment.js index 948af5a8e0e..61945af2f90 100644 --- a/app/assets/javascripts/admin/addon/components/admin-config-area-sidebar-experiment.js +++ b/app/assets/javascripts/admin/addon/components/admin-config-area-sidebar-experiment.js @@ -2,13 +2,13 @@ import Component from "@glimmer/component"; import { tracked } from "@glimmer/tracking"; import { action } from "@ember/object"; import { inject as service } from "@ember/service"; +import { ADMIN_NAV_MAP } from "discourse/lib/sidebar/admin-nav-map"; import { buildAdminSidebar, useAdminNavConfig, -} from "discourse/instance-initializers/admin-sidebar"; -import { ADMIN_NAV_MAP } from "discourse/lib/sidebar/admin-nav-map"; +} from "discourse/lib/sidebar/admin-sidebar"; import { resetPanelSections } from "discourse/lib/sidebar/custom-sections"; -import { ADMIN_PANEL } from "discourse/services/sidebar-state"; +import { ADMIN_PANEL } from "discourse/lib/sidebar/panels"; // TODO (martin) (2024-02-01) Remove this experimental UI. export default class AdminConfigAreaSidebarExperiment extends Component { diff --git a/app/assets/javascripts/admin/addon/routes/admin-revamp.js b/app/assets/javascripts/admin/addon/routes/admin-revamp.js index 8c94766e881..5bd3536f7f8 100644 --- a/app/assets/javascripts/admin/addon/routes/admin-revamp.js +++ b/app/assets/javascripts/admin/addon/routes/admin-revamp.js @@ -1,7 +1,7 @@ import { inject as service } from "@ember/service"; +import { ADMIN_PANEL, MAIN_PANEL } from "discourse/lib/sidebar/panels"; import DiscourseURL from "discourse/lib/url"; import DiscourseRoute from "discourse/routes/discourse"; -import { ADMIN_PANEL, MAIN_PANEL } from "discourse/services/sidebar-state"; import I18n from "discourse-i18n"; export default class AdminRoute extends DiscourseRoute { diff --git a/app/assets/javascripts/admin/addon/routes/admin.js b/app/assets/javascripts/admin/addon/routes/admin.js index 306872c4aa6..2a929982546 100644 --- a/app/assets/javascripts/admin/addon/routes/admin.js +++ b/app/assets/javascripts/admin/addon/routes/admin.js @@ -1,6 +1,6 @@ import { inject as service } from "@ember/service"; +import { ADMIN_PANEL, MAIN_PANEL } from "discourse/lib/sidebar/panels"; import DiscourseRoute from "discourse/routes/discourse"; -import { ADMIN_PANEL, MAIN_PANEL } from "discourse/services/sidebar-state"; import I18n from "discourse-i18n"; export default class AdminRoute extends DiscourseRoute { diff --git a/app/assets/javascripts/discourse/app/lib/plugin-api.js b/app/assets/javascripts/discourse/app/lib/plugin-api.js index ea3457b5a24..f1607820323 100644 --- a/app/assets/javascripts/discourse/app/lib/plugin-api.js +++ b/app/assets/javascripts/discourse/app/lib/plugin-api.js @@ -42,7 +42,6 @@ import { } from "discourse/helpers/category-link"; import { addUsernameSelectorDecorator } from "discourse/helpers/decorate-username-selector"; import { registerCustomAvatarHelper } from "discourse/helpers/user-avatar"; -import { addAdminSidebarSectionLink } from "discourse/instance-initializers/admin-sidebar"; import { addBeforeAuthCompleteCallback } from "discourse/instance-initializers/auth-complete"; import { addPopupMenuOption } from "discourse/lib/composer/custom-popup-menu-options"; import { registerDesktopNotificationHandler } from "discourse/lib/desktop-notifications"; @@ -67,6 +66,7 @@ import { addTagsHtmlCallback } from "discourse/lib/render-tags"; import { addFeaturedLinkMetaDecorator } from "discourse/lib/render-topic-featured-link"; import { addSearchResultsCallback } from "discourse/lib/search"; import Sharing from "discourse/lib/sharing"; +import { addAdminSidebarSectionLink } from "discourse/lib/sidebar/admin-sidebar"; import { addSectionLink as addCustomCommunitySectionLink } from "discourse/lib/sidebar/custom-community-section-links"; import { addSidebarPanel, diff --git a/app/assets/javascripts/discourse/app/instance-initializers/admin-sidebar.js b/app/assets/javascripts/discourse/app/lib/sidebar/admin-sidebar.js similarity index 62% rename from app/assets/javascripts/discourse/app/instance-initializers/admin-sidebar.js rename to app/assets/javascripts/discourse/app/lib/sidebar/admin-sidebar.js index d7e60b20751..dcf7f455da8 100644 --- a/app/assets/javascripts/discourse/app/instance-initializers/admin-sidebar.js +++ b/app/assets/javascripts/discourse/app/lib/sidebar/admin-sidebar.js @@ -1,10 +1,11 @@ +import { isEmpty } from "@ember/utils"; import PreloadStore from "discourse/lib/preload-store"; import { ADMIN_NAV_MAP } from "discourse/lib/sidebar/admin-nav-map"; -import { - addSidebarPanel, - addSidebarSection, -} from "discourse/lib/sidebar/custom-sections"; -import { ADMIN_PANEL } from "discourse/services/sidebar-state"; +import BaseCustomSidebarPanel from "discourse/lib/sidebar/base-custom-sidebar-panel"; +import BaseCustomSidebarSection from "discourse/lib/sidebar/base-custom-sidebar-section"; +import BaseCustomSidebarSectionLink from "discourse/lib/sidebar/base-custom-sidebar-section-link"; +import { ADMIN_PANEL } from "discourse/lib/sidebar/panels"; +import { getOwnerWithFallback } from "discourse-common/lib/get-owner"; import I18n from "discourse-i18n"; let additionalAdminSidebarSectionLinks = {}; @@ -14,60 +15,52 @@ export function clearAdditionalAdminSidebarSectionLinks() { additionalAdminSidebarSectionLinks = {}; } -function defineAdminSectionLink(BaseCustomSidebarSectionLink) { - const SidebarAdminSectionLink = class extends BaseCustomSidebarSectionLink { - constructor({ adminSidebarNavLink }) { - super(...arguments); - this.adminSidebarNavLink = adminSidebarNavLink; - } +class SidebarAdminSectionLink extends BaseCustomSidebarSectionLink { + constructor({ adminSidebarNavLink }) { + super(...arguments); + this.adminSidebarNavLink = adminSidebarNavLink; + } - get name() { - return this.adminSidebarNavLink.name; - } + get name() { + return this.adminSidebarNavLink.name; + } - get classNames() { - return "admin-sidebar-nav-link"; - } + get classNames() { + return "admin-sidebar-nav-link"; + } - get route() { - return this.adminSidebarNavLink.route; - } + get route() { + return this.adminSidebarNavLink.route; + } - get href() { - return this.adminSidebarNavLink.href; - } + get href() { + return this.adminSidebarNavLink.href; + } - get models() { - return this.adminSidebarNavLink.routeModels; - } + get models() { + return this.adminSidebarNavLink.routeModels; + } - get text() { - return this.adminSidebarNavLink.label - ? I18n.t(this.adminSidebarNavLink.label) - : this.adminSidebarNavLink.text; - } + get text() { + return this.adminSidebarNavLink.label + ? I18n.t(this.adminSidebarNavLink.label) + : this.adminSidebarNavLink.text; + } - get prefixType() { - return "icon"; - } + get prefixType() { + return "icon"; + } - get prefixValue() { - return this.adminSidebarNavLink.icon; - } + get prefixValue() { + return this.adminSidebarNavLink.icon; + } - get title() { - return this.adminSidebarNavLink.text; - } - }; - - return SidebarAdminSectionLink; + get title() { + return this.adminSidebarNavLink.text; + } } -function defineAdminSection( - adminNavSectionData, - BaseCustomSidebarSection, - adminSectionLinkClass -) { +function defineAdminSection(adminNavSectionData) { const AdminNavSection = class extends BaseCustomSidebarSection { constructor() { super(...arguments); @@ -96,7 +89,7 @@ function defineAdminSection( get links() { return this.sectionLinks.map( (sectionLinkData) => - new adminSectionLinkClass({ adminSidebarNavLink: sectionLinkData }) + new SidebarAdminSectionLink({ adminSidebarNavLink: sectionLinkData }) ); } @@ -163,27 +156,6 @@ export function useAdminNavConfig(navMap) { return navMap; } -let adminSectionLinkClass = null; -export function buildAdminSidebar(navConfig) { - navConfig.forEach((adminNavSectionData) => { - addSidebarSection( - (BaseCustomSidebarSection, BaseCustomSidebarSectionLink) => { - // We only want to define the link class once even though we have many different sections. - adminSectionLinkClass = - adminSectionLinkClass || - defineAdminSectionLink(BaseCustomSidebarSectionLink); - - return defineAdminSection( - adminNavSectionData, - BaseCustomSidebarSection, - adminSectionLinkClass - ); - }, - ADMIN_PANEL - ); - }); -} - // This is used for a plugin API. export function addAdminSidebarSectionLink(sectionName, link) { if (!additionalAdminSidebarSectionLinks.hasOwnProperty(sectionName)) { @@ -237,41 +209,26 @@ function pluginAdminRouteLinks() { ); } -export default { - name: "admin-sidebar-initializer", +export default class AdminSidebarPanel extends BaseCustomSidebarPanel { + key = ADMIN_PANEL; + hidden = true; - initialize(owner) { - this.currentUser = owner.lookup("service:current-user"); - this.siteSettings = owner.lookup("service:site-settings"); - - if ( - !this.currentUser?.staff || - !this.siteSettings.userInAnyGroups( - "admin_sidebar_enabled_groups", - this.currentUser - ) - ) { - return; + get sections() { + const siteSettings = getOwnerWithFallback().lookup("service:site-settings"); + if (isEmpty(siteSettings.admin_sidebar_enabled_groups)) { + return []; } - this.adminSidebarExperimentStateManager = owner.lookup( + this.adminSidebarExperimentStateManager = getOwnerWithFallback(this).lookup( "service:admin-sidebar-experiment-state-manager" ); - addSidebarPanel( - (BaseCustomSidebarPanel) => - class AdminSidebarPanel extends BaseCustomSidebarPanel { - key = ADMIN_PANEL; - hidden = true; - } - ); - const savedConfig = this.adminSidebarExperimentStateManager.navConfig; const navMap = savedConfig || ADMIN_NAV_MAP; navMap.findBy("name", "plugins").links.push(...pluginAdminRouteLinks()); - if (this.siteSettings.experimental_form_templates) { + if (siteSettings.experimental_form_templates) { navMap.findBy("name", "customize").links.push({ name: "admin_customize_form_templates", route: "adminCustomizeFormTemplates", @@ -280,6 +237,10 @@ export default { }); } - buildAdminSidebar(useAdminNavConfig(navMap), adminSectionLinkClass); - }, -}; + const navConfig = useAdminNavConfig(navMap); + + return navConfig.map((adminNavSectionData) => { + return defineAdminSection(adminNavSectionData); + }); + } +} diff --git a/app/assets/javascripts/discourse/app/lib/sidebar/custom-sections.js b/app/assets/javascripts/discourse/app/lib/sidebar/custom-sections.js index 0a3d98fe30d..1c66b8d0903 100644 --- a/app/assets/javascripts/discourse/app/lib/sidebar/custom-sections.js +++ b/app/assets/javascripts/discourse/app/lib/sidebar/custom-sections.js @@ -1,7 +1,9 @@ import BaseCustomSidebarPanel from "discourse/lib/sidebar/base-custom-sidebar-panel"; import BaseCustomSidebarSection from "discourse/lib/sidebar/base-custom-sidebar-section"; import BaseCustomSidebarSectionLink from "discourse/lib/sidebar/base-custom-sidebar-section-link"; +import { MAIN_PANEL } from "discourse/lib/sidebar/panels"; import I18n from "discourse-i18n"; +import AdminSidebarPanel from "./admin-sidebar"; class MainSidebarPanel { sections = []; @@ -23,9 +25,9 @@ class MainSidebarPanel { } } -export let customPanels = [new MainSidebarPanel()]; - -export let currentPanelKey = "main"; +export let customPanels; +export let currentPanelKey; +resetSidebarPanels(); export function addSidebarPanel(func) { const panelClass = func.call(this, BaseCustomSidebarPanel); @@ -60,6 +62,6 @@ export function resetPanelSections( } export function resetSidebarPanels() { - customPanels = [new MainSidebarPanel()]; - currentPanelKey = "main"; + customPanels = [new MainSidebarPanel(), new AdminSidebarPanel()]; + currentPanelKey = MAIN_PANEL; } diff --git a/app/assets/javascripts/discourse/app/lib/sidebar/panels.js b/app/assets/javascripts/discourse/app/lib/sidebar/panels.js new file mode 100644 index 00000000000..9728f56801c --- /dev/null +++ b/app/assets/javascripts/discourse/app/lib/sidebar/panels.js @@ -0,0 +1,4 @@ +export const COMBINED_MODE = "combined"; +export const SEPARATED_MODE = "separated"; +export const MAIN_PANEL = "main"; +export const ADMIN_PANEL = "admin"; diff --git a/app/assets/javascripts/discourse/app/services/sidebar-state.js b/app/assets/javascripts/discourse/app/services/sidebar-state.js index 6e12bad088e..9f25c744a2c 100644 --- a/app/assets/javascripts/discourse/app/services/sidebar-state.js +++ b/app/assets/javascripts/discourse/app/services/sidebar-state.js @@ -5,11 +5,11 @@ import { currentPanelKey, customPanels as panels, } from "discourse/lib/sidebar/custom-sections"; - -const COMBINED_MODE = "combined"; -const SEPARATED_MODE = "separated"; -export const MAIN_PANEL = "main"; -export const ADMIN_PANEL = "admin"; +import { + COMBINED_MODE, + MAIN_PANEL, + SEPARATED_MODE, +} from "discourse/lib/sidebar/panels"; @disableImplicitInjections export default class SidebarState extends Service { diff --git a/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js b/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js index 042c354e6e2..3e995b7231a 100644 --- a/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js +++ b/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js @@ -28,7 +28,6 @@ import { resetUserMenuProfileTabItems } from "discourse/components/user-menu/pro import { resetCustomPostMessageCallbacks } from "discourse/controllers/topic"; import { clearHTMLCache } from "discourse/helpers/custom-html"; import { resetUsernameDecorators } from "discourse/helpers/decorate-username-selector"; -import { clearAdditionalAdminSidebarSectionLinks } from "discourse/instance-initializers/admin-sidebar"; import { resetBeforeAuthCompleteCallbacks } from "discourse/instance-initializers/auth-complete"; import { clearPopupMenuOptions } from "discourse/lib/composer/custom-popup-menu-options"; import { clearDesktopNotificationHandlers } from "discourse/lib/desktop-notifications"; @@ -50,6 +49,7 @@ import PreloadStore from "discourse/lib/preload-store"; import { clearTopicFooterButtons } from "discourse/lib/register-topic-footer-button"; import { clearTopicFooterDropdowns } from "discourse/lib/register-topic-footer-dropdown"; import { clearTagsHtmlCallbacks } from "discourse/lib/render-tags"; +import { clearAdditionalAdminSidebarSectionLinks } from "discourse/lib/sidebar/admin-sidebar"; import { resetDefaultSectionLinks as resetTopicsSectionLinks } from "discourse/lib/sidebar/custom-community-section-links"; import { resetSidebarPanels } from "discourse/lib/sidebar/custom-sections"; import { diff --git a/plugins/chat/assets/javascripts/discourse/lib/init-sidebar-state.js b/plugins/chat/assets/javascripts/discourse/lib/init-sidebar-state.js index 68ff26cf142..2e8116a857d 100644 --- a/plugins/chat/assets/javascripts/discourse/lib/init-sidebar-state.js +++ b/plugins/chat/assets/javascripts/discourse/lib/init-sidebar-state.js @@ -1,4 +1,4 @@ -import { ADMIN_PANEL, MAIN_PANEL } from "discourse/services/sidebar-state"; +import { ADMIN_PANEL, MAIN_PANEL } from "discourse/lib/sidebar/panels"; import { getUserChatSeparateSidebarMode } from "discourse/plugins/chat/discourse/lib/get-user-chat-separate-sidebar-mode"; export const CHAT_PANEL = "chat"; diff --git a/plugins/chat/assets/javascripts/discourse/services/chat-state-manager.js b/plugins/chat/assets/javascripts/discourse/services/chat-state-manager.js index 54ba27f5686..c51adeb4470 100644 --- a/plugins/chat/assets/javascripts/discourse/services/chat-state-manager.js +++ b/plugins/chat/assets/javascripts/discourse/services/chat-state-manager.js @@ -2,9 +2,9 @@ import { tracked } from "@glimmer/tracking"; import Service, { inject as service } from "@ember/service"; import KeyValueStore from "discourse/lib/key-value-store"; import { withPluginApi } from "discourse/lib/plugin-api"; +import { MAIN_PANEL } from "discourse/lib/sidebar/panels"; import { defaultHomepage } from "discourse/lib/utilities"; import Site from "discourse/models/site"; -import { MAIN_PANEL } from "discourse/services/sidebar-state"; import getURL from "discourse-common/lib/get-url"; import { getUserChatSeparateSidebarMode } from "discourse/plugins/chat/discourse/lib/get-user-chat-separate-sidebar-mode";