mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
FEATURE: More flexible admin plugin config nav definition (#26254)
This commit changes the API for registering the plugin config page nav configuration from a server-side to a JS one; there is no need for it to be server-side. It also makes some changes to allow for 2 different ways of displaying navigation for plugin pages, depending on complexity: * TOP - This is the best mode for simple plugins without a lot of different custom configuration pages, and it reuses the grey horizontal nav bar already used for admins. * SIDEBAR - This is better for more complex plugins; likely this won't be used in the near future, but it's readily available if needed There is a new AdminPluginConfigNavManager service too to manage which plugin the admin is actively viewing, otherwise we would have trouble hiding the main plugin nav for admins when viewing a single plugin.
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { LinkTo } from "@ember/routing";
|
||||
import { inject as service } from "@ember/service";
|
||||
import concatClass from "discourse/helpers/concat-class";
|
||||
import I18n from "discourse-i18n";
|
||||
|
||||
export default class AdminPluginConfigArea extends Component {
|
||||
@service adminPluginNavManager;
|
||||
|
||||
linkText(navLink) {
|
||||
if (navLink.label) {
|
||||
return I18n.t(navLink.label);
|
||||
@@ -13,10 +16,13 @@ export default class AdminPluginConfigArea extends Component {
|
||||
}
|
||||
|
||||
<template>
|
||||
{{#if @innerSidebarNavLinks}}
|
||||
{{#if this.adminPluginNavManager.isSidebarMode}}
|
||||
<nav class="admin-nav admin-plugin-inner-sidebar-nav pull-left">
|
||||
<ul class="nav nav-stacked">
|
||||
{{#each @innerSidebarNavLinks as |navLink|}}
|
||||
{{#each
|
||||
this.adminPluginNavManager.currentConfigNav.links
|
||||
as |navLink|
|
||||
}}
|
||||
<li
|
||||
class={{concatClass
|
||||
"admin-plugin-inner-sidebar-nav__item"
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { inject as service } from "@ember/service";
|
||||
import HorizontalOverflowNav from "discourse/components/horizontal-overflow-nav";
|
||||
import NavItem from "discourse/components/nav-item";
|
||||
import i18n from "discourse-common/helpers/i18n";
|
||||
import AdminPluginConfigArea from "./admin-plugin-config-area";
|
||||
|
||||
export default class extends Component {
|
||||
@service currentUser;
|
||||
|
||||
get configNavRoutes() {
|
||||
return this.args.plugin.configNavRoutes || [];
|
||||
}
|
||||
@service adminPluginNavManager;
|
||||
|
||||
get mainAreaClasses() {
|
||||
let classes = ["admin-plugin-config-page__main-area"];
|
||||
|
||||
if (this.configNavRoutes.length) {
|
||||
if (this.adminPluginNavManager.isSidebarMode) {
|
||||
classes.push("-with-inner-sidebar");
|
||||
} else {
|
||||
classes.push("-without-inner-sidebar");
|
||||
@@ -22,32 +21,61 @@ export default class extends Component {
|
||||
return classes.join(" ");
|
||||
}
|
||||
|
||||
linkText(navLink) {
|
||||
if (navLink.label) {
|
||||
return i18n(navLink.label);
|
||||
} else {
|
||||
return navLink.text;
|
||||
}
|
||||
}
|
||||
|
||||
<template>
|
||||
<div class="admin-plugin-config-page">
|
||||
<div class="admin-plugin-config-page__metadata">
|
||||
<h2>
|
||||
{{@plugin.nameTitleized}}
|
||||
</h2>
|
||||
<p>
|
||||
{{@plugin.about}}
|
||||
{{#if @plugin.linkUrl}}
|
||||
|
|
||||
<a
|
||||
href={{@plugin.linkUrl}}
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
{{i18n "admin.plugins.learn_more"}}
|
||||
</a>
|
||||
{{/if}}
|
||||
{{#if this.adminPluginNavManager.isTopMode}}
|
||||
<div class="admin-controls">
|
||||
<HorizontalOverflowNav
|
||||
class="nav-pills action-list main-nav nav plugin-nav"
|
||||
>
|
||||
{{#each
|
||||
this.adminPluginNavManager.currentConfigNav.links
|
||||
as |navLink|
|
||||
}}
|
||||
<NavItem
|
||||
@route={{navLink.route}}
|
||||
@i18nLabel={{this.linkText navLink}}
|
||||
title={{this.linkText navLink}}
|
||||
class="admin-plugin-config-page__top-nav-item"
|
||||
>
|
||||
{{this.linkText navLink}}
|
||||
</NavItem>
|
||||
{{/each}}
|
||||
</HorizontalOverflowNav>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
</p>
|
||||
<div class="admin-plugin-config-page__metadata">
|
||||
<div class="admin-plugin-config-area__metadata-title">
|
||||
<h2>
|
||||
{{@plugin.nameTitleized}}
|
||||
</h2>
|
||||
<p>
|
||||
{{@plugin.about}}
|
||||
{{#if @plugin.linkUrl}}
|
||||
|
|
||||
<a
|
||||
href={{@plugin.linkUrl}}
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
{{i18n "admin.plugins.learn_more"}}
|
||||
</a>
|
||||
{{/if}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="admin-plugin-config-page__content">
|
||||
<div class={{this.mainAreaClasses}}>
|
||||
<AdminPluginConfigArea
|
||||
@innerSidebarNavLinks={{@plugin.configNavRoutes}}
|
||||
>
|
||||
<AdminPluginConfigArea>
|
||||
{{yield}}
|
||||
</AdminPluginConfigArea>
|
||||
</div>
|
||||
|
||||
@@ -2,6 +2,7 @@ import Controller from "@ember/controller";
|
||||
import { service } from "@ember/service";
|
||||
|
||||
export default class AdminPluginsController extends Controller {
|
||||
@service adminPluginNavManager;
|
||||
@service router;
|
||||
|
||||
get adminRoutes() {
|
||||
@@ -21,6 +22,13 @@ export default class AdminPluginsController extends Controller {
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
get showTopNav() {
|
||||
return (
|
||||
!this.adminPluginNavManager.currentPlugin ||
|
||||
this.adminPluginNavManager.isSidebarMode
|
||||
);
|
||||
}
|
||||
|
||||
routeExists(route) {
|
||||
try {
|
||||
if (route.use_new_show_route) {
|
||||
|
||||
@@ -26,7 +26,6 @@ export default class AdminPlugin {
|
||||
this.version = args.version;
|
||||
this.metaUrl = args.meta_url;
|
||||
this.authors = args.authors;
|
||||
this.configNavRoutes = args.admin_config_nav_routes;
|
||||
}
|
||||
|
||||
get snakeCaseName() {
|
||||
|
||||
@@ -6,6 +6,7 @@ import AdminPlugin from "admin/models/admin-plugin";
|
||||
|
||||
export default class AdminPluginsShowRoute extends Route {
|
||||
@service router;
|
||||
@service adminPluginNavManager;
|
||||
|
||||
model(params) {
|
||||
const pluginId = sanitize(params.plugin_id).substring(0, 100);
|
||||
@@ -13,4 +14,12 @@ export default class AdminPluginsShowRoute extends Route {
|
||||
return AdminPlugin.create(plugin);
|
||||
});
|
||||
}
|
||||
|
||||
afterModel(model) {
|
||||
this.adminPluginNavManager.currentPlugin = model;
|
||||
}
|
||||
|
||||
deactivate() {
|
||||
this.adminPluginNavManager.currentPlugin = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import Service, { service } from "@ember/service";
|
||||
import {
|
||||
configNavForPlugin,
|
||||
PLUGIN_NAV_MODE_SIDEBAR,
|
||||
PLUGIN_NAV_MODE_TOP,
|
||||
} from "discourse/lib/admin-plugin-config-nav";
|
||||
|
||||
export default class AdminPluginNavManager extends Service {
|
||||
@service currentUser;
|
||||
@tracked currentPlugin;
|
||||
|
||||
get currentUserUsingAdminSidebar() {
|
||||
return this.currentUser?.use_admin_sidebar;
|
||||
}
|
||||
|
||||
get currentConfigNav() {
|
||||
return configNavForPlugin(this.currentPlugin.id);
|
||||
}
|
||||
|
||||
get isSidebarMode() {
|
||||
return this.currentConfigNav.mode === PLUGIN_NAV_MODE_SIDEBAR;
|
||||
}
|
||||
|
||||
get isTopMode() {
|
||||
return this.currentConfigNav.mode === PLUGIN_NAV_MODE_TOP;
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,22 @@
|
||||
{{#if this.model.length}}
|
||||
<h3>{{i18n "admin.plugins.installed"}}</h3>
|
||||
<AdminPluginsList @plugins={{this.model}} />
|
||||
{{else}}
|
||||
<p>{{i18n "admin.plugins.none_installed"}}</p>
|
||||
{{/if}}
|
||||
<div class="admin-plugins-list-container">
|
||||
{{#if this.model.length}}
|
||||
<h2>{{i18n "admin.plugins.installed"}}</h2>
|
||||
<AdminPluginsList @plugins={{this.model}} />
|
||||
{{else}}
|
||||
<p>{{i18n "admin.plugins.none_installed"}}</p>
|
||||
{{/if}}
|
||||
|
||||
<p class="admin-plugins-howto">
|
||||
<a href="https://meta.discourse.org/t/install-a-plugin/19157">
|
||||
{{i18n "admin.plugins.howto"}}
|
||||
</a>
|
||||
</p>
|
||||
<p class="admin-plugins-howto">
|
||||
<a href="https://meta.discourse.org/t/install-a-plugin/19157">
|
||||
{{i18n "admin.plugins.howto"}}
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<span>
|
||||
<PluginOutlet
|
||||
@name="admin-below-plugins-index"
|
||||
@connectorTagName="div"
|
||||
@outletArgs={{hash model=this.model}}
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
<PluginOutlet
|
||||
@name="admin-below-plugins-index"
|
||||
@connectorTagName="div"
|
||||
@outletArgs={{hash model=this.model}}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@@ -1,19 +1,21 @@
|
||||
<div class="admin-controls">
|
||||
<HorizontalOverflowNav class="main-nav nav plugin-nav">
|
||||
<NavItem @route="adminPlugins.index" @label="admin.plugins.title" />
|
||||
{{#each this.adminRoutes as |route|}}
|
||||
{{#if route.use_new_show_route}}
|
||||
<NavItem
|
||||
@route={{route.full_location}}
|
||||
@label={{route.label}}
|
||||
@routeParam={{route.location}}
|
||||
/>
|
||||
{{else}}
|
||||
<NavItem @route={{route.full_location}} @label={{route.label}} />
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
</HorizontalOverflowNav>
|
||||
</div>
|
||||
{{#if this.showTopNav}}
|
||||
<div class="admin-controls">
|
||||
<HorizontalOverflowNav class="main-nav nav plugin-nav">
|
||||
<NavItem @route="adminPlugins.index" @label="admin.plugins.title" />
|
||||
{{#each this.adminRoutes as |route|}}
|
||||
{{#if route.use_new_show_route}}
|
||||
<NavItem
|
||||
@route={{route.full_location}}
|
||||
@label={{route.label}}
|
||||
@routeParam={{route.location}}
|
||||
/>
|
||||
{{else}}
|
||||
<NavItem @route={{route.full_location}} @label={{route.label}} />
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
</HorizontalOverflowNav>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="admin-container">
|
||||
{{#each this.brokenAdminRoutes as |route|}}
|
||||
|
||||
Reference in New Issue
Block a user