From 6de00f89c2cf5f9a3aca1775d73675d3c1a61b9c Mon Sep 17 00:00:00 2001 From: Martin Brennan Date: Mon, 18 Dec 2023 11:48:25 +1000 Subject: [PATCH] FEATURE: Initial admin sidebar navigation (#24789) This is v0 of admin sidebar navigation, which moves all of the top-level admin nav from the top of the page into a sidebar. This is hidden behind a enable_admin_sidebar_navigation site setting, and is opt-in for now. This sidebar is dynamically shown whenever the user enters an admin route in the UI, and is hidden and replaced with either the: * Main forum sidebar * Chat sidebar Depending on where they navigate to. For now, custom sections are not supported in the admin sidebar. This commit removes the experimental admin sidebar generation rake task but keeps the experimental sidebar UI for now for further testing; it just uses the real nav as the default now. --- .../admin-config-area-sidebar-experiment.js | 1 + .../admin/addon/controllers/admin.js | 3 + .../admin/addon/routes/admin-revamp.js | 7 +- .../javascripts/admin/addon/routes/admin.js | 18 +- .../admin/addon/templates/admin.hbs | 63 ++--- .../instance-initializers/admin-sidebar.js | 73 ++++-- .../app/lib/sidebar/admin-nav-map.js | 230 +++++++----------- .../admin-revamp-section-link.js | 5 +- app/models/sidebar_url.rb | 6 - config/locales/client.en.yml | 3 + config/locales/server.en.yml | 1 + config/site_settings.yml | 3 + lib/svg_sprite.rb | 2 + lib/tasks/javascript.rake | 138 ----------- spec/models/sidebar_section_spec.rb | 13 +- .../admin_revamp_sidebar_navigation_spec.rb | 25 +- .../components/navigation_menu/base.rb | 28 ++- 17 files changed, 252 insertions(+), 367 deletions(-) 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 33e243182a9..6799b3332b0 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 @@ -10,6 +10,7 @@ import { ADMIN_NAV_MAP } from "discourse/lib/sidebar/admin-nav-map"; import { resetPanelSections } from "discourse/lib/sidebar/custom-sections"; import { ADMIN_PANEL } from "discourse/services/sidebar-state"; +// TODO (martin) (2024-02-01) Remove this experimental UI. export default class AdminConfigAreaSidebarExperiment extends Component { @service adminSidebarExperimentStateManager; @service toasts; diff --git a/app/assets/javascripts/admin/addon/controllers/admin.js b/app/assets/javascripts/admin/addon/controllers/admin.js index a636b077208..bb82a5c136d 100644 --- a/app/assets/javascripts/admin/addon/controllers/admin.js +++ b/app/assets/javascripts/admin/addon/controllers/admin.js @@ -1,4 +1,5 @@ import Controller from "@ember/controller"; +import { readOnly } from "@ember/object/computed"; import { inject as service } from "@ember/service"; import { dasherize } from "@ember/string"; import discourseComputed from "discourse-common/utils/decorators"; @@ -6,6 +7,8 @@ import discourseComputed from "discourse-common/utils/decorators"; export default class AdminController extends Controller { @service router; + @readOnly("siteSettings.enable_admin_sidebar_navigation") showAdminSidebar; + @discourseComputed("siteSettings.enable_group_directory") showGroups(enableGroupDirectory) { return !enableGroupDirectory; diff --git a/app/assets/javascripts/admin/addon/routes/admin-revamp.js b/app/assets/javascripts/admin/addon/routes/admin-revamp.js index 880d47d40e9..c24449cef4d 100644 --- a/app/assets/javascripts/admin/addon/routes/admin-revamp.js +++ b/app/assets/javascripts/admin/addon/routes/admin-revamp.js @@ -14,12 +14,7 @@ export default class AdminRoute extends DiscourseRoute { } activate() { - if ( - !this.siteSettings.userInAnyGroups( - "enable_experimental_admin_ui_groups", - this.currentUser - ) - ) { + if (!this.siteSettings.enable_admin_sidebar_navigation) { return DiscourseURL.redirectTo("/admin"); } diff --git a/app/assets/javascripts/admin/addon/routes/admin.js b/app/assets/javascripts/admin/addon/routes/admin.js index ded5cf48e37..f824af8de8c 100644 --- a/app/assets/javascripts/admin/addon/routes/admin.js +++ b/app/assets/javascripts/admin/addon/routes/admin.js @@ -1,23 +1,35 @@ import { inject as service } from "@ember/service"; import DiscourseRoute from "discourse/routes/discourse"; -import { MAIN_PANEL } from "discourse/services/sidebar-state"; +import { ADMIN_PANEL, MAIN_PANEL } from "discourse/services/sidebar-state"; import I18n from "discourse-i18n"; export default class AdminRoute extends DiscourseRoute { @service sidebarState; + @service siteSettings; titleToken() { return I18n.t("admin_title"); } activate() { + if (this.siteSettings.enable_admin_sidebar_navigation) { + this.sidebarState.setPanel(ADMIN_PANEL); + this.sidebarState.setSeparatedMode(); + this.sidebarState.hideSwitchPanelButtons(); + } + this.controllerFor("application").setProperties({ showTop: false, }); } - deactivate() { + deactivate(transition) { this.controllerFor("application").set("showTop", true); - this.sidebarState.setPanel(MAIN_PANEL); + + if (this.siteSettings.enable_admin_sidebar_navigation) { + if (!transition?.to.name.startsWith("admin")) { + this.sidebarState.setPanel(MAIN_PANEL); + } + } } } diff --git a/app/assets/javascripts/admin/addon/templates/admin.hbs b/app/assets/javascripts/admin/addon/templates/admin.hbs index d03ada8566a..3128a3fead2 100644 --- a/app/assets/javascripts/admin/addon/templates/admin.hbs +++ b/app/assets/javascripts/admin/addon/templates/admin.hbs @@ -4,37 +4,40 @@
-
- +
+ {{/unless}}
diff --git a/app/assets/javascripts/discourse/app/instance-initializers/admin-sidebar.js b/app/assets/javascripts/discourse/app/instance-initializers/admin-sidebar.js index 8ed92805678..46151e2d0c7 100644 --- a/app/assets/javascripts/discourse/app/instance-initializers/admin-sidebar.js +++ b/app/assets/javascripts/discourse/app/instance-initializers/admin-sidebar.js @@ -4,6 +4,7 @@ import { addSidebarSection, } from "discourse/lib/sidebar/custom-sections"; import { ADMIN_PANEL } from "discourse/services/sidebar-state"; +import I18n from "discourse-i18n"; function defineAdminSectionLink(BaseCustomSidebarSectionLink) { const SidebarAdminSectionLink = class extends BaseCustomSidebarSectionLink { @@ -33,7 +34,9 @@ function defineAdminSectionLink(BaseCustomSidebarSectionLink) { } get text() { - return this.adminSidebarNavLink.text; + return this.adminSidebarNavLink.label + ? I18n.t(this.adminSidebarNavLink.label) + : this.adminSidebarNavLink.text; } get prefixType() { @@ -77,7 +80,9 @@ function defineAdminSection( } get text() { - return this.adminNavSectionData.text; + return this.adminNavSectionData.label + ? I18n.t(this.adminNavSectionData.label) + : this.adminNavSectionData.text; } get links() { @@ -103,22 +108,47 @@ export function useAdminNavConfig(navMap) { hideSectionHeader: true, links: [ { - name: "Back to Forum", + name: "back_to_forum", route: "discovery.latest", - text: "Back to Forum", + label: "admin.back_to_forum", icon: "arrow-left", }, { - name: "Lobby", - route: "admin-revamp.lobby", - text: "Lobby", + name: "admin_dashboard", + route: "admin.dashboard", + label: "admin.dashboard.title", icon: "home", }, { - name: "legacy", - route: "admin", - text: "Legacy Admin", - icon: "wrench", + name: "admin_site_settings", + route: "adminSiteSettings", + label: "admin.site_settings.title", + icon: "cog", + }, + { + name: "admin_users", + route: "adminUsers", + label: "admin.users.title", + icon: "users", + }, + { + name: "admin_reports", + route: "adminReports", + label: "admin.dashboard.reports_tab", + icon: "chart-pie", + }, + { + name: "admin_plugins", + route: "adminPlugins", + label: "admin.plugins.title", + icon: "puzzle-piece", + }, + + { + name: "admin_badges", + route: "adminBadges", + label: "admin.badges.title", + icon: "certificate", }, ], }, @@ -157,12 +187,7 @@ export default { return; } - if ( - !this.siteSettings.userInAnyGroups( - "enable_experimental_admin_ui_groups", - this.currentUser - ) - ) { + if (!this.siteSettings.enable_admin_sidebar_navigation) { return; } @@ -179,7 +204,19 @@ export default { ); const savedConfig = this.adminSidebarExperimentStateManager.navConfig; - const navConfig = useAdminNavConfig(savedConfig || ADMIN_NAV_MAP); + const navMap = savedConfig || ADMIN_NAV_MAP; + + if (this.siteSettings.experimental_form_templates) { + navMap.findBy("name", "customize").links.push({ + name: "admin_customize_form_templates", + route: "adminCustomizeFormTemplates", + label: "admin.form_templates.nav_title", + icon: "list", + }); + } + + const navConfig = useAdminNavConfig(navMap); + buildAdminSidebar(navConfig, adminSectionLinkClass); }, }; diff --git a/app/assets/javascripts/discourse/app/lib/sidebar/admin-nav-map.js b/app/assets/javascripts/discourse/app/lib/sidebar/admin-nav-map.js index d07f89cf615..318956053d9 100644 --- a/app/assets/javascripts/discourse/app/lib/sidebar/admin-nav-map.js +++ b/app/assets/javascripts/discourse/app/lib/sidebar/admin-nav-map.js @@ -1,232 +1,182 @@ -// DO NOT EDIT THIS FILE!!! -// Update it by running `rake javascript:update_constants` - export const ADMIN_NAV_MAP = [ - { - name: "root", - text: "Root", - links: [ - { name: "admin-revamp", route: "admin-revamp", text: "Revamp" }, - { name: "admin", route: "admin", text: "Admin" }, - ], - }, - { - name: "plugins", - text: "Plugins", - links: [{ name: "admin_plugins", route: "adminPlugins", text: "Plugins" }], - }, - { - name: "site_settings", - text: "Site Settings", - links: [ - { - name: "admin_site_settings", - route: "adminSiteSettings", - text: "Site Settings", - }, - ], - }, - { - name: "reports", - text: "Reports", - links: [{ name: "admin_reports", route: "adminReports", text: "Reports" }], - }, - { - name: "users", - text: "Users", - links: [ - { name: "admin_users_list", route: "adminUsersList", text: "List" }, - { name: "admin_users", route: "adminUsers", text: "Users" }, - ], - }, { name: "email", text: "Email", links: [ - { name: "admin_email_sent", route: "adminEmail.sent", text: "Sent" }, + { + name: "admin_email", + route: "adminEmail.index", + label: "admin.email.settings", + icon: "cog", + }, + { + name: "admin_email_sent", + route: "adminEmail.sent", + label: "admin.email.sent", + icon: "arrow-right", + }, { name: "admin_email_skipped", route: "adminEmail.skipped", - text: "Skipped", + label: "admin.email.skipped", + icon: "angle-double-right", }, { name: "admin_email_bounced", route: "adminEmail.bounced", - text: "Bounced", + label: "admin.email.bounced", + icon: "times", }, { name: "admin_email_received", route: "adminEmail.received", - text: "Received", + label: "admin.email.received", + icon: "inbox", }, { name: "admin_email_rejected", route: "adminEmail.rejected", - text: "Rejected", + label: "admin.email.rejected", + icon: "ban", }, - { - name: "admin_email_preview-digest", - route: "adminEmail.previewDigest", - text: "Preview Digest", - }, - { - name: "admin_email_advanced-test", - route: "adminEmail.advancedTest", - text: "Advanced Test", - }, - { name: "admin_email", route: "adminEmail", text: "Email" }, ], }, { name: "logs", - text: "Logs", + label: "admin.logs.title", links: [ { name: "admin_logs_staff_action_logs", route: "adminLogs.staffActionLogs", - text: "Staff Action Logs", + label: "admin.logs.staff_actions.title", + icon: "user-shield", }, { name: "admin_logs_screened_emails", route: "adminLogs.screenedEmails", - text: "Screened Emails", + label: "admin.logs.screened_emails.title", + icon: "envelope", }, { name: "admin_logs_screened_ip_addresses", route: "adminLogs.screenedIpAddresses", - text: "Screened Ip Addresses", + label: "admin.logs.screened_ips.title", + icon: "globe", }, { name: "admin_logs_screened_urls", route: "adminLogs.screenedUrls", - text: "Screened Urls", + label: "admin.logs.screened_urls.title", + icon: "globe", }, { name: "admin_logs_search_logs", route: "adminSearchLogs", - text: "Search Logs", + label: "admin.logs.search_logs.title", + icon: "search", }, - { - name: "admin_logs_search_logs_term", - route: "adminSearchLogs.term", - text: "Search Term", - }, - { name: "admin_logs", route: "adminLogs", text: "Logs" }, ], }, { name: "customize", - text: "Customize", + label: "admin.customize.title", links: [ - { name: "admin_customize", route: "adminCustomize", text: "Customize" }, { name: "admin_customize_themes", route: "adminCustomizeThemes", - text: "Themes", + label: "admin.customize.theme.title", + icon: "paint-brush", }, { name: "admin_customize_colors", route: "adminCustomize.colors", - text: "Colors", - }, - { - name: "admin_customize_permalinks", - route: "adminPermalinks", - text: "Permalinks", - }, - { - name: "admin_customize_embedding", - route: "adminEmbedding", - text: "Embedding", - }, - { - name: "admin_customize_user_fields", - route: "adminUserFields", - text: "User Fields", - }, - { name: "admin_customize_emojis", route: "adminEmojis", text: "Emojis" }, - { - name: "admin_customize_form-templates", - route: "adminCustomizeFormTemplates", - text: "Form Templates", - }, - { - name: "admin_customize_form-templates_new", - route: "adminCustomizeFormTemplates.new", - text: "Form Templates New", + label: "admin.customize.colors.title", + icon: "palette", }, { name: "admin_customize_site_texts", route: "adminSiteText", - text: "Site Texts", + label: "admin.site_text.title", + icon: "language", }, { name: "admin_customize_email_templates", route: "adminCustomizeEmailTemplates", - text: "Email Templates", - }, - { - name: "admin_customize_robots", - route: "adminCustomizeRobotsTxt", - text: "Robots", + label: "admin.email.templates_title", + icon: "envelope", }, { name: "admin_customize_email_style", route: "adminCustomizeEmailStyle", - text: "Email Style", + label: "admin.customize.email_style.title", + icon: "envelope", + }, + { + name: "admin_customize_user_fields", + route: "adminUserFields", + label: "admin.user_fields.title", + icon: "user-edit", + }, + { + name: "admin_customize_emojis", + route: "adminEmojis", + label: "admin.emoji.title", + icon: "discourse-emojis", + }, + { + name: "admin_customize_permalinks", + route: "adminPermalinks", + label: "admin.permalink.title", + icon: "link", + }, + { + name: "admin_customize_embedding", + route: "adminEmbedding", + label: "admin.embedding.title", + icon: "code", }, { name: "admin_customize_watched_words", route: "adminWatchedWords", - text: "Watched Words", - }, - ], - }, - { - name: "dashboard", - text: "Dashboard", - links: [ - { - name: "admin_dashboard_moderation", - route: "admin.dashboardModeration", - text: "Moderation", - }, - { - name: "admin_dashboard_security", - route: "admin.dashboardSecurity", - text: "Security", - }, - { - name: "admin_dashboard_reports", - route: "admin.dashboardReports", - text: "Reports", + label: "admin.watched_words.title", + icon: "eye", }, ], }, { name: "api", - text: "Api", + label: "admin.api.title", links: [ - { name: "admin_api_keys", route: "adminApiKeys", text: "Keys" }, + { + name: "admin_api_keys", + route: "adminApiKeys", + icon: "key", + label: "admin.api.keys", + }, { name: "admin_api_web_hooks", route: "adminWebHooks", - text: "Web Hooks", + label: "admin.web_hooks.title", + icon: "globe", }, - { name: "admin_api", route: "adminApi", text: "Api" }, ], }, { name: "backups", - text: "Backups", + label: "admin.backups.menu.backups", links: [ - { name: "admin_backups_logs", route: "admin.backups.logs", text: "Logs" }, - { name: "admin_backups", route: "admin.backups", text: "Backups" }, + { + name: "admin_backups", + route: "admin.backups.index", + label: "admin.backups.menu.backups", + icon: "archive", + }, + { + name: "admin_backups_logs", + route: "admin.backups.logs", + label: "admin.backups.menu.logs", + icon: "stream", + }, ], }, - { - name: "badges", - text: "Badges", - links: [{ name: "admin_badges", route: "adminBadges", text: "Badges" }], - }, ]; diff --git a/app/assets/javascripts/discourse/app/lib/sidebar/user/community-section/admin-revamp-section-link.js b/app/assets/javascripts/discourse/app/lib/sidebar/user/community-section/admin-revamp-section-link.js index 9da418eeeaf..fa28d36f10a 100644 --- a/app/assets/javascripts/discourse/app/lib/sidebar/user/community-section/admin-revamp-section-link.js +++ b/app/assets/javascripts/discourse/app/lib/sidebar/user/community-section/admin-revamp-section-link.js @@ -31,10 +31,7 @@ export default class AdminRevampSectionLink extends BaseSectionLink { return ( this.currentUser.staff && - this.siteSettings.userInAnyGroups( - "enable_experimental_admin_ui_groups", - this.currentUser - ) + this.siteSettings.enable_admin_sidebar_navigation ); } diff --git a/app/models/sidebar_url.rb b/app/models/sidebar_url.rb index 76a498f6c50..6e21a3e76c5 100644 --- a/app/models/sidebar_url.rb +++ b/app/models/sidebar_url.rb @@ -22,12 +22,6 @@ class SidebarUrl < ActiveRecord::Base }, { name: "Review", path: "/review", icon: "flag", segment: SidebarUrl.segments["primary"] }, { name: "Admin", path: "/admin", icon: "wrench", segment: SidebarUrl.segments["primary"] }, - { - name: "Admin Revamp", - path: "/admin-revamp", - icon: "star", - segment: SidebarUrl.segments["primary"], - }, { name: "Users", path: "/u", icon: "users", segment: SidebarUrl.segments["secondary"] }, { name: "About", diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 6457cb9a1c2..e0401e475a3 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -4722,6 +4722,7 @@ en: admin: title: "Discourse Admin" moderator: "Moderator" + back_to_forum: "Back to Forum" tags: remove_muted_tags_from_latest: @@ -4911,6 +4912,7 @@ en: user: "User" title: "API" key: "Key" + keys: "Keys" created: Created updated: Updated last_used: Last Used @@ -5529,6 +5531,7 @@ en: title: "Emails" settings: "Settings" templates: "Templates" + templates_title: "Email Templates" preview_digest: "Preview Summary" advanced_test: title: "Advanced Test" diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index d5031c3136f..073762db19d 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -2490,6 +2490,7 @@ en: enable_experimental_lightbox: "EXPERIMENTAL: Replace the default image lightbox with the revamped design." experimental_form_templates: "EXPERIMENTAL: Enable the form templates feature. After enabled, manage the templates at Customize / Templates." + enable_admin_sidebar_navigation: "EXPERIMENTAL: Enable sidebar navigation for the admin UI, which replaces the top-level admin navigation buttons." page_loading_indicator: "Configure the loading indicator which appears during page navigations within Discourse. 'Spinner' is a full page indicator. 'Slider' shows a narrow bar at the top of the screen." show_user_menu_avatars: "Show user avatars in the user menu" diff --git a/config/site_settings.yml b/config/site_settings.yml index 910a3288981..3f525053b04 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -2280,6 +2280,9 @@ developer: refresh: true hidden: true client: true + enable_admin_sidebar_navigation: + default: false + client: true lazy_load_categories: default: false client: true diff --git a/lib/svg_sprite.rb b/lib/svg_sprite.rb index ca8bb833046..6e237a8b3c2 100644 --- a/lib/svg_sprite.rb +++ b/lib/svg_sprite.rb @@ -19,6 +19,7 @@ module SvgSprite archive arrow-down arrow-left + arrow-right arrow-up arrows-alt-h arrows-alt-v @@ -171,6 +172,7 @@ module SvgSprite mobile-alt moon paint-brush + palette paper-plane pause pencil-alt diff --git a/lib/tasks/javascript.rake b/lib/tasks/javascript.rake index c1a4667d328..5abfad215df 100644 --- a/lib/tasks/javascript.rake +++ b/lib/tasks/javascript.rake @@ -129,140 +129,6 @@ def absolute_sourcemap(dest) end end -def generate_admin_sidebar_nav_map - vague_categories = { "root" => [] } - - admin_routes = - Rails - .application - .routes - .routes - .map do |route| - next if route.verb != "GET" - path = route.path.spec.to_s.gsub("(.:format)", "") - next if !path.include?("admin") - next if path.include?("/:") || path.include?("admin-login") - path - end - .compact - - # TODO (martin): This will generate the engine routes based on installed plugins, - # so it is not generic enough to use here. Need to think of another way to do - # this and reconcile with the Ember routes from the client; maybe some button - # that does it at runtime for this experiment? - engine_routes = [] - # engine_routes = Rails::Engine - # .subclasses - # .map do |engine| - # engine - # .routes - # .routes - # .map do |route| - # next if route.verb != "GET" - # path = route.path.spec.to_s.gsub("(.:format)", "") - # next if !path.include?("admin") - # next if path.include?("/:") || path.include?("admin-login") - # path - # end - # .compact - # end - # .flatten - - admin_routes = admin_routes.concat(engine_routes) - - admin_routes.each do |path| - split_path = path.split("/") - if split_path.length >= 3 - vague_categories[split_path[2]] ||= [] - vague_categories[split_path[2]] << { path: path } - else - vague_categories["root"] << { path: path } - end - end - - # rubocop:disable Lint/Void - # Copy this JS to your browser to get the Ember routes. - <<~JS - let routeMap = {} - for (const [key, value] of Object.entries( - Object.fromEntries( - Object.entries( - Discourse.__container__.lookup("service:router")._router._routerMicrolib - .recognizer.names - ).filter(([key]) => key.includes("admin")) - ) - )) { - let route = value.segments - .map((s) => s.value) - .join("/") - .replace("//", "/"); - if ( - route.includes("dummy") || - route.includes("loading") || - route.includes("_id") || - route.includes("admin-invite") - ) { - continue; - } - routeMap[key] = route; - } - console.log(JSON.stringify(routeMap)); - JS - # rubocop:enable Lint/Void - - # Paste the output below between ROUTE_MAP. - # - ember_route_map = <<~ROUTE_MAP - {"admin.dashboard.general":"/admin/","admin.dashboard":"/admin/","admin":"/admin/","admin.dashboardModeration":"/admin/dashboard/moderation","admin.dashboardSecurity":"/admin/dashboard/security","admin.dashboardReports":"/admin/dashboard/reports","adminSiteSettings.index":"/admin/site_settings/","adminSiteSettings":"/admin/site_settings/","adminEmail.sent":"/admin/email/sent","adminEmail.skipped":"/admin/email/skipped","adminEmail.bounced":"/admin/email/bounced","adminEmail.received":"/admin/email/received","adminEmail.rejected":"/admin/email/rejected","adminEmail.previewDigest":"/admin/email/preview-digest","adminEmail.advancedTest":"/admin/email/advanced-test","adminEmail.index":"/admin/email/","adminEmail":"/admin/email/","adminCustomize.colors.index":"/admin/customize/colors/","adminCustomize.colors":"/admin/customize/colors/","adminCustomizeThemes.index":"/admin/customize/themes/","adminCustomizeThemes":"/admin/customize/themes/","adminSiteText.edit":"/admin/customize/site_texts/id","adminSiteText.index":"/admin/customize/site_texts/","adminSiteText":"/admin/customize/site_texts/","adminUserFields":"/admin/customize/user_fields","adminEmojis":"/admin/customize/emojis","adminPermalinks":"/admin/customize/permalinks","adminEmbedding":"/admin/customize/embedding","adminCustomizeEmailTemplates.edit":"/admin/customize/email_templates/id","adminCustomizeEmailTemplates.index":"/admin/customize/email_templates/","adminCustomizeEmailTemplates":"/admin/customize/email_templates/","adminCustomizeRobotsTxt":"/admin/customize/robots","adminCustomizeEmailStyle.edit":"/admin/customize/email_style/field_name","adminCustomizeEmailStyle.index":"/admin/customize/email_style/","adminCustomizeEmailStyle":"/admin/customize/email_style/","adminCustomizeFormTemplates.new":"/admin/customize/form-templates/new","adminCustomizeFormTemplates.edit":"/admin/customize/form-templates/id","adminCustomizeFormTemplates.index":"/admin/customize/form-templates/","adminCustomizeFormTemplates":"/admin/customize/form-templates/","adminWatchedWords.index":"/admin/customize/watched_words/","adminWatchedWords":"/admin/customize/watched_words/","adminCustomize.index":"/admin/customize/","adminCustomize":"/admin/customize/","adminApiKeys.new":"/admin/api/keys/new","adminApiKeys.index":"/admin/api/keys/","adminApiKeys":"/admin/api/keys/","adminWebHooks.index":"/admin/api/web_hooks/","adminWebHooks":"/admin/api/web_hooks/","adminApi.index":"/admin/api/","adminApi":"/admin/api/","admin.backups.logs":"/admin/backups/logs","admin.backups.index":"/admin/backups/","admin.backups":"/admin/backups/","adminReports.show":"/admin/reports/type","adminReports.index":"/admin/reports/","adminReports":"/admin/reports/","adminLogs.staffActionLogs":"/admin/logs/staff_action_logs","adminLogs.screenedEmails":"/admin/logs/screened_emails","adminLogs.screenedIpAddresses":"/admin/logs/screened_ip_addresses","adminLogs.screenedUrls":"/admin/logs/screened_urls","adminSearchLogs.index":"/admin/logs/search_logs/","adminSearchLogs":"/admin/logs/search_logs/","adminSearchLogs.term":"/admin/logs/search_logs/term","adminLogs.index":"/admin/logs/","adminLogs":"/admin/logs/","adminUsersList.show":"/admin/users/list/filter","adminUsersList.index":"/admin/users/list/","adminUsersList":"/admin/users/list/","adminUsers.index":"/admin/users/","adminUsers":"/admin/users/","adminBadges.index":"/admin/badges/","adminBadges":"/admin/badges/","adminPlugins.index":"/admin/plugins/","adminPlugins":"/admin/plugins/","admin-revamp.lobby":"/admin-revamp/","admin-revamp":"/admin-revamp/","admin-revamp.config.area":"/admin-revamp/config/area","admin-revamp.config.index":"/admin-revamp/config/","admin-revamp.config":"/admin-revamp/config/"} - ROUTE_MAP - ember_route_map = JSON.parse(ember_route_map) - - # Match the Ember routes to the rails routes. - vague_categories.each do |category, route_data| - route_data.each do |rails_route| - ember_route_map.each do |ember_route_name, ember_path| - rails_route[:ember_route] = ember_route_name if ember_path == rails_route[:path] || - ember_path == rails_route[:path] + "/" - end - end - end - - # Remove all rails routes that don't have an Ember equivalent. - vague_categories.each do |category, route_data| - vague_categories[category] = route_data.reject { |rails_route| !rails_route.key?(:ember_route) } - end - - # Remove all categories that don't have any routes (meaning they are all rails-only). - vague_categories.each do |category, route_data| - vague_categories.delete(category) if route_data.length == 0 - end - - # Output in the format needed for sidebar sections and links. - vague_categories.map do |category, route_data| - category_text = category.titleize.gsub("Admin ", "") - { - name: category, - text: category_text, - links: - route_data.map do |rails_route| - { - name: rails_route[:path].split("/").compact_blank.join("_").chomp, - route: rails_route[:ember_route], - text: - rails_route[:path] - .split("/") - .compact_blank - .join(" ") - .chomp - .titleize - .gsub("Admin ", "") - .gsub("#{category_text} ", ""), - } - end, - } - end -end - task "javascript:update_constants" => :environment do task_name = "update_constants" @@ -296,10 +162,6 @@ task "javascript:update_constants" => :environment do export const AUTO_GROUPS = #{auto_groups.to_json}; JS - write_template("discourse/app/lib/sidebar/admin-nav-map.js", task_name, <<~JS) - export const ADMIN_NAV_MAP = #{generate_admin_sidebar_nav_map.to_json} - JS - pretty_notifications = Notification.types.map { |n| " #{n[0]}: #{n[1]}," }.join("\n") write_template("discourse/tests/fixtures/concerns/notification-types.js", task_name, <<~JS) diff --git a/spec/models/sidebar_section_spec.rb b/spec/models/sidebar_section_spec.rb index 474109156af..b2e9f310c96 100644 --- a/spec/models/sidebar_section_spec.rb +++ b/spec/models/sidebar_section_spec.rb @@ -22,18 +22,7 @@ RSpec.describe SidebarSection do expect(community_section.reload.title).to eq("Community") expect(community_section.sidebar_section_links.all.map { |link| link.linkable.name }).to eq( - [ - "Topics", - "My Posts", - "Review", - "Admin", - "Admin Revamp", - "Users", - "About", - "FAQ", - "Groups", - "Badges", - ], + ["Topics", "My Posts", "Review", "Admin", "Users", "About", "FAQ", "Groups", "Badges"], ) end end diff --git a/spec/system/admin_revamp_sidebar_navigation_spec.rb b/spec/system/admin_revamp_sidebar_navigation_spec.rb index 379d09fab4e..ff8a898e6d6 100644 --- a/spec/system/admin_revamp_sidebar_navigation_spec.rb +++ b/spec/system/admin_revamp_sidebar_navigation_spec.rb @@ -2,18 +2,29 @@ describe "Admin Revamp | Sidebar Navigation", type: :system do fab!(:admin) - let(:sidebar_page) { PageObjects::Components::NavigationMenu::Sidebar.new } + let(:sidebar) { PageObjects::Components::NavigationMenu::Sidebar.new } before do - SiteSetting.enable_experimental_admin_ui_groups = Group::AUTO_GROUPS[:staff] - SidebarSection.find_by(section_type: "community").reset_community! + SiteSetting.enable_admin_sidebar_navigation = true sign_in(admin) end - it "navigates to the admin revamp from the sidebar" do + it "shows the sidebar when navigating to an admin route and hides it when leaving" do visit("/latest") - sidebar_page.click_section_link("Admin Revamp") - expect(page).to have_content("Lobby") - expect(page).to have_content("Legacy Admin") + sidebar.click_link_in_section("community", "admin") + expect(page).to have_current_path("/admin") + expect(sidebar).to be_visible + expect(page).to have_no_css(".admin-main-nav") + sidebar.click_link_in_section("admin-nav-section-root", "back_to_forum") + expect(page).to have_current_path("/latest") + expect(sidebar).to have_no_section("admin-nav-section-root") + end + + it "does not show the admin sidebar if the setting is disabled" do + SiteSetting.enable_admin_sidebar_navigation = false + visit("/latest") + sidebar.click_link_in_section("community", "admin") + expect(page).to have_current_path("/admin") + expect(sidebar).to have_no_section("admin-nav-section-root") end end diff --git a/spec/system/page_objects/components/navigation_menu/base.rb b/spec/system/page_objects/components/navigation_menu/base.rb index f78a3e39f4c..2d36514bbc5 100644 --- a/spec/system/page_objects/components/navigation_menu/base.rb +++ b/spec/system/page_objects/components/navigation_menu/base.rb @@ -4,16 +4,34 @@ module PageObjects module Components module NavigationMenu class Base < PageObjects::Components::Base - def community_section - find(".sidebar-section[data-section-name='community']") + SIDEBAR_SECTION_LINK_SELECTOR = "sidebar-section-link" + + def visible? + has_css?("#d-sidebar.sidebar-container") end - SIDEBAR_SECTION_LINK_SELECTOR = "sidebar-section-link" + def hidden? + has_no_css?("#d-sidebar.sidebar-container") + end + + def community_section + find_section("community") + end + + def find_section(name) + find(".sidebar-section[data-section-name='#{name}']") + end def click_section_link(name) find(".#{SIDEBAR_SECTION_LINK_SELECTOR}", text: name).click end + def click_link_in_section(section_name, link_name) + find_section(section_name.parameterize).find( + ".#{SIDEBAR_SECTION_LINK_SELECTOR}[data-link-name=\"#{link_name.parameterize}\"]", + ).click + end + def has_one_active_section_link? has_css?(".#{SIDEBAR_SECTION_LINK_SELECTOR}--active", count: 1) end @@ -30,6 +48,10 @@ module PageObjects has_css?(".sidebar-sections [data-section-name='#{name.parameterize}']") end + def has_no_section?(name) + has_no_css?(".sidebar-sections [data-section-name='#{name.parameterize}']") + end + def switch_to_chat find(".sidebar__panel-switch-button[data-key='chat']").click end