FIX: Show admin plugin route sub-links in sidebar (#24982)

This changes the Plugins link in the admin sidebar to
be a section instead, which then shows all enabled plugin
admin routes (which are custom routes some plugins e.g.
chat define).

This is done via adding some special preloaded data for
all controllers based on AdminController, and also specifically
on Admin::PluginsController, to have the routes loaded without
additional requests on page load.

We just use a cog for all the route icons for now...we don't
have anything better.
This commit is contained in:
Martin Brennan 2023-12-21 11:37:20 +10:00 committed by GitHub
parent 8fce890ead
commit 7fcef5f2f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 87 additions and 18 deletions

View File

@ -1,3 +1,4 @@
import PreloadStore from "discourse/lib/preload-store";
import { ADMIN_NAV_MAP } from "discourse/lib/sidebar/admin-nav-map"; import { ADMIN_NAV_MAP } from "discourse/lib/sidebar/admin-nav-map";
import { import {
addSidebarPanel, addSidebarPanel,
@ -137,13 +138,6 @@ export function useAdminNavConfig(navMap) {
label: "admin.dashboard.reports_tab", label: "admin.dashboard.reports_tab",
icon: "chart-pie", icon: "chart-pie",
}, },
{
name: "admin_plugins",
route: "adminPlugins",
label: "admin.plugins.title",
icon: "puzzle-piece",
},
{ {
name: "admin_badges", name: "admin_badges",
route: "adminBadges", route: "adminBadges",
@ -206,6 +200,17 @@ export default {
const savedConfig = this.adminSidebarExperimentStateManager.navConfig; const savedConfig = this.adminSidebarExperimentStateManager.navConfig;
const navMap = savedConfig || ADMIN_NAV_MAP; const navMap = savedConfig || ADMIN_NAV_MAP;
const enabledPluginAdminRoutes =
PreloadStore.get("enabledPluginAdminRoutes") || [];
enabledPluginAdminRoutes.forEach((pluginAdminRoute) => {
navMap.findBy("name", "admin_plugins").links.push({
name: `admin_plugin_${pluginAdminRoute.location}`,
route: `adminPlugins.${pluginAdminRoute.location}`,
label: pluginAdminRoute.label,
icon: "cog",
});
});
if (this.siteSettings.experimental_form_templates) { if (this.siteSettings.experimental_form_templates) {
navMap.findBy("name", "customize").links.push({ navMap.findBy("name", "customize").links.push({
name: "admin_customize_form_templates", name: "admin_customize_form_templates",
@ -215,8 +220,6 @@ export default {
}); });
} }
const navConfig = useAdminNavConfig(navMap); buildAdminSidebar(useAdminNavConfig(navMap), adminSectionLinkClass);
buildAdminSidebar(navConfig, adminSectionLinkClass);
}, },
}; };

View File

@ -1,4 +1,17 @@
export const ADMIN_NAV_MAP = [ export const ADMIN_NAV_MAP = [
{
name: "admin_plugins",
route: "adminPlugins.index",
label: "admin.plugins.title",
links: [
{
name: "admin_installed_plugins",
route: "adminPlugins",
label: "admin.plugins.installed",
icon: "puzzle-piece",
},
],
},
{ {
name: "email", name: "email",
text: "Email", text: "Email",

View File

@ -7,4 +7,13 @@ class Admin::AdminController < ApplicationController
def index def index
render body: nil render body: nil
end end
private
def preload_additional_json
store_preloaded(
"enabledPluginAdminRoutes",
MultiJson.dump(Discourse.plugins_sorted_by_name.filter_map(&:admin_route)),
)
end
end end

View File

@ -3,9 +3,18 @@
class Admin::PluginsController < Admin::StaffController class Admin::PluginsController < Admin::StaffController
def index def index
render_serialized( render_serialized(
Discourse.visible_plugins.sort_by { |p| p.name.downcase.delete_prefix("discourse-") }, Discourse.plugins_sorted_by_name(enabled_only: false),
AdminPluginSerializer, AdminPluginSerializer,
root: "plugins", root: "plugins",
) )
end end
private
def preload_additional_json
store_preloaded(
"enabledPluginAdminRoutes",
MultiJson.dump(Discourse.plugins_sorted_by_name.filter_map(&:admin_route)),
)
end
end end

View File

@ -446,6 +446,8 @@ class ApplicationController < ActionController::Base
current_user.sync_notification_channel_position current_user.sync_notification_channel_position
preload_current_user_data preload_current_user_data
end end
preload_additional_json
end end
def set_mobile_view def set_mobile_view
@ -671,6 +673,10 @@ class ApplicationController < ActionController::Base
store_preloaded("fontMap", MultiJson.dump(load_font_map)) if current_user.admin? store_preloaded("fontMap", MultiJson.dump(load_font_map)) if current_user.admin?
end end
def preload_additional_json
# noop, should be defined by subcontrollers
end
def custom_html_json def custom_html_json
target = view_context.mobile_view? ? :mobile : :desktop target = view_context.mobile_view? ? :mobile : :desktop

View File

@ -377,6 +377,11 @@ module Discourse
plugins.filter(&:visible?) plugins.filter(&:visible?)
end end
def self.plugins_sorted_by_name(enabled_only: true)
return visible_plugins.filter(&:enabled?).sort_by(&:name_without_prefix) if enabled_only
visible_plugins.sort_by(&:name_without_prefix)
end
def self.plugin_themes def self.plugin_themes
@plugin_themes ||= plugins.map(&:themes).flatten @plugin_themes ||= plugins.map(&:themes).flatten
end end

View File

@ -122,7 +122,7 @@ class Plugin::Instance
@enabled_site_setting ? SiteSetting.get(@enabled_site_setting) : true @enabled_site_setting ? SiteSetting.get(@enabled_site_setting) : true
end end
delegate :name, to: :metadata delegate :name, :name_without_prefix, to: :metadata
def add_to_serializer( def add_to_serializer(
serializer, serializer,

View File

@ -133,6 +133,10 @@ class Plugin::Metadata
end end
end end
def name_without_prefix
name.downcase.delete_prefix("discourse-")
end
def self.parse(text) def self.parse(text)
metadata = self.new metadata = self.new
text.each_line { |line| break unless metadata.parse_line(line) } text.each_line { |line| break unless metadata.parse_line(line) }

View File

@ -0,0 +1,17 @@
# frozen_string_literal: true
describe "Admin Revamp | Sidebar Navigation | Plugin Links", type: :system do
fab!(:admin)
let(:sidebar) { PageObjects::Components::NavigationMenu::Sidebar.new }
before do
chat_system_bootstrap
SiteSetting.enable_admin_sidebar_navigation = true
sign_in(admin)
end
it "shows links to enabled plugin admin routes" do
visit("/admin")
expect(sidebar).to have_section_link("Chat", href: "/admin/plugins/chat")
end
end

View File

@ -20,11 +20,14 @@ describe "Admin Revamp | Sidebar Navigation", type: :system do
expect(sidebar).to have_no_section("admin-nav-section-root") expect(sidebar).to have_no_section("admin-nav-section-root")
end end
it "does not show the admin sidebar if the setting is disabled" do context "when the setting is disabled" do
SiteSetting.enable_admin_sidebar_navigation = false before { SiteSetting.enable_admin_sidebar_navigation = false }
visit("/latest")
sidebar.click_link_in_section("community", "admin") it "does not show the admin sidebar" do
expect(page).to have_current_path("/admin") visit("/latest")
expect(sidebar).to have_no_section("admin-nav-section-root") 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 end
end end