mirror of
https://github.com/discourse/discourse.git
synced 2025-02-20 05:36:32 +08:00
DEV: Use default admin routes for plugins with settings (#30941)
This change adds a sidebar link for each plugin that fulfils the following criteria: - Does not have an explicit admin route defined in the plugin. - Has at least one site setting (not including enabled/disabled.) That sidebar link leads to the automatically generated plugin show settings page.
This commit is contained in:
parent
9991eacef4
commit
503f9b6f02
|
@ -1,6 +1,7 @@
|
|||
import Component from "@glimmer/component";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import { action } from "@ember/object";
|
||||
import didUpdate from "@ember/render-modifiers/modifiers/did-update";
|
||||
import { service } from "@ember/service";
|
||||
import ConditionalLoadingSpinner from "discourse/components/conditional-loading-spinner";
|
||||
import DBreadcrumbsItem from "discourse/components/d-breadcrumbs-item";
|
||||
|
@ -28,6 +29,11 @@ export default class AdminAreaSettings extends Component {
|
|||
return !this.loading && this.settings.length > 0;
|
||||
}
|
||||
|
||||
@action
|
||||
async reloadSettings() {
|
||||
await this.#loadSettings();
|
||||
}
|
||||
|
||||
@bind
|
||||
async #loadSettings() {
|
||||
this.loading = true;
|
||||
|
@ -69,6 +75,7 @@ export default class AdminAreaSettings extends Component {
|
|||
|
||||
<div
|
||||
class="content-body admin-config-area__settings admin-detail pull-left"
|
||||
{{didUpdate this.reloadSettings @plugin}}
|
||||
>
|
||||
{{#if this.showSettings}}
|
||||
<AdminFilteredSiteSettings
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { cached, tracked } from "@glimmer/tracking";
|
||||
import { capitalize, dasherize } from "@ember/string";
|
||||
import { dasherize } from "@ember/string";
|
||||
import { snakeCaseToCamelCase } from "discourse/lib/case-converter";
|
||||
import I18n, { i18n } from "discourse-i18n";
|
||||
|
||||
|
@ -50,29 +50,7 @@ export default class AdminPlugin {
|
|||
|
||||
@cached
|
||||
get nameTitleized() {
|
||||
// The category name is better in a lot of cases, as it's a human-inputted
|
||||
// translation, and we can handle things like SAML instead of showing them
|
||||
// as Saml from discourse-saml. We can fall back to the programmatic version
|
||||
// though if needed.
|
||||
let name;
|
||||
if (this.translatedCategoryName) {
|
||||
name = this.translatedCategoryName;
|
||||
} else {
|
||||
name = this.name
|
||||
.split(/[-_]/)
|
||||
.map((word) => {
|
||||
return capitalize(word);
|
||||
})
|
||||
.join(" ");
|
||||
}
|
||||
|
||||
// Cuts down on repetition.
|
||||
const discoursePrefix = "Discourse ";
|
||||
if (name.startsWith(discoursePrefix)) {
|
||||
name = name.slice(discoursePrefix.length);
|
||||
}
|
||||
|
||||
return name;
|
||||
return this.translatedCategoryName || this.humanizedName;
|
||||
}
|
||||
|
||||
@cached
|
||||
|
|
|
@ -60,7 +60,9 @@ class SidebarAdminSectionLink extends BaseCustomSidebarSectionLink {
|
|||
|
||||
get text() {
|
||||
return this.adminSidebarNavLink.label
|
||||
? i18n(this.adminSidebarNavLink.label)
|
||||
? i18n(this.adminSidebarNavLink.label, {
|
||||
translatedFallback: this.adminSidebarNavLink.text,
|
||||
})
|
||||
: this.adminSidebarNavLink.text;
|
||||
}
|
||||
|
||||
|
@ -316,6 +318,7 @@ function pluginAdminRouteLinks(router) {
|
|||
? [plugin.admin_route.location]
|
||||
: [],
|
||||
label: plugin.admin_route.label,
|
||||
text: plugin.humanized_name,
|
||||
icon: "gear",
|
||||
};
|
||||
});
|
||||
|
|
|
@ -12,6 +12,7 @@ acceptance("Admin - Plugins", function (needs) {
|
|||
{
|
||||
id: "some-test-plugin",
|
||||
name: "some-test-plugin",
|
||||
humanized_name: "Some test plugin",
|
||||
about: "Plugin description",
|
||||
version: "0.1",
|
||||
url: "https://example.com",
|
||||
|
@ -44,7 +45,7 @@ acceptance("Admin - Plugins", function (needs) {
|
|||
.dom(
|
||||
"table.admin-plugins-list .admin-plugins-list__row .admin-plugins-list__name-details .admin-plugins-list__name-with-badges .admin-plugins-list__name"
|
||||
)
|
||||
.hasText("Some Test Plugin", "displays the plugin in the table");
|
||||
.hasText("Some test plugin", "displays the plugin in the table");
|
||||
|
||||
assert
|
||||
.dom(".admin-plugins .admin-config-page .alert-error")
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
import { setupTest } from "ember-qunit";
|
||||
import { module, test } from "qunit";
|
||||
import AdminPlugin from "admin/models/admin-plugin";
|
||||
|
||||
module("Unit | Model | admin plugin", function (hooks) {
|
||||
setupTest(hooks);
|
||||
|
||||
test("nameTitleized", function (assert) {
|
||||
const adminPlugin = AdminPlugin.create({
|
||||
name: "docker_manager",
|
||||
});
|
||||
|
||||
assert.strictEqual(
|
||||
adminPlugin.nameTitleized,
|
||||
"Docker Manager",
|
||||
"it should return titleized name replacing underscores with spaces"
|
||||
);
|
||||
});
|
||||
});
|
|
@ -659,6 +659,7 @@ class ApplicationController < ActionController::Base
|
|||
.map do |plugin|
|
||||
{
|
||||
name: plugin.name.downcase,
|
||||
humanized_name: plugin.humanized_name,
|
||||
admin_route: plugin.full_admin_route,
|
||||
enabled: plugin.enabled?,
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ class AdminPluginSerializer < ApplicationSerializer
|
|||
:enabled_setting,
|
||||
:has_settings,
|
||||
:has_only_enabled_setting,
|
||||
:humanized_name,
|
||||
:is_official,
|
||||
:is_discourse_owned,
|
||||
:label,
|
||||
|
@ -27,6 +28,10 @@ class AdminPluginSerializer < ApplicationSerializer
|
|||
object.metadata.name
|
||||
end
|
||||
|
||||
def humanized_name
|
||||
object.humanized_name
|
||||
end
|
||||
|
||||
def about
|
||||
object.metadata.about
|
||||
end
|
||||
|
|
|
@ -120,7 +120,12 @@ class Plugin::Instance
|
|||
|
||||
def full_admin_route
|
||||
route = self.admin_route
|
||||
return unless route
|
||||
|
||||
if route.blank?
|
||||
return if !any_settings?
|
||||
|
||||
route = default_admin_route
|
||||
end
|
||||
|
||||
route
|
||||
.slice(:location, :label, :use_new_show_route)
|
||||
|
@ -130,6 +135,14 @@ class Plugin::Instance
|
|||
end
|
||||
end
|
||||
|
||||
def any_settings?
|
||||
return false if !configurable?
|
||||
|
||||
SiteSetting
|
||||
.all_settings(filter_plugin: self.name)
|
||||
.any? { |s| s[:setting] != @enabled_site_setting }
|
||||
end
|
||||
|
||||
def configurable?
|
||||
true
|
||||
end
|
||||
|
@ -146,7 +159,11 @@ class Plugin::Instance
|
|||
delegate :name, to: :metadata
|
||||
|
||||
def humanized_name
|
||||
(setting_category_name || name).delete_prefix("Discourse ").delete_prefix("discourse-")
|
||||
(setting_category_name || name)
|
||||
.delete_prefix("Discourse ")
|
||||
.delete_prefix("discourse-")
|
||||
.gsub("-", " ")
|
||||
.upcase_first
|
||||
end
|
||||
|
||||
def add_to_serializer(
|
||||
|
@ -1476,4 +1493,8 @@ class Plugin::Instance
|
|||
def register_permitted_bulk_action_parameter(name)
|
||||
DiscoursePluginRegistry.register_permitted_bulk_action_parameter(name, self)
|
||||
end
|
||||
|
||||
def default_admin_route
|
||||
{ label: "#{name.underscore}.title", location: name, use_new_show_route: true }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -22,6 +22,7 @@ RSpec.describe ApplicationController do
|
|||
expect(JSON.parse(preloaded_json["visiblePlugins"])).to include(
|
||||
{
|
||||
"name" => "chat",
|
||||
"humanized_name" => "Chat",
|
||||
"admin_route" => {
|
||||
"label" => "chat.admin.title",
|
||||
"location" => "chat",
|
||||
|
|
4
plugins/footnote/config/locales/client.en.yml
Normal file
4
plugins/footnote/config/locales/client.en.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
en:
|
||||
js:
|
||||
footnote:
|
||||
title: "Footnotes"
|
|
@ -33,7 +33,7 @@ TEXT
|
|||
end
|
||||
|
||||
it "defaults to using the plugin name with the discourse- prefix removed" do
|
||||
expect(plugin_instance.humanized_name).to eq("sample-plugin")
|
||||
expect(plugin_instance.humanized_name).to eq("Sample plugin")
|
||||
end
|
||||
|
||||
it "uses the plugin setting category name if it exists" do
|
||||
|
@ -43,7 +43,7 @@ TEXT
|
|||
|
||||
it "the plugin name the plugin site settings are still under the generic plugins: category" do
|
||||
plugin_instance.stubs(:setting_category).returns("plugins")
|
||||
expect(plugin_instance.humanized_name).to eq("sample-plugin")
|
||||
expect(plugin_instance.humanized_name).to eq("Sample plugin")
|
||||
end
|
||||
|
||||
it "removes any Discourse prefix from the setting category name" do
|
||||
|
|
|
@ -337,4 +337,19 @@ describe "Admin | Sidebar Navigation", type: :system do
|
|||
],
|
||||
)
|
||||
end
|
||||
|
||||
it "adds auto-generated plugin links for plugins with settings" do
|
||||
skip if Discourse.plugins.empty?
|
||||
|
||||
SiteSetting.enable_markdown_footnotes = true
|
||||
|
||||
visit("/admin")
|
||||
|
||||
sidebar.toggle_section(:plugins)
|
||||
|
||||
expect(page).to have_css(
|
||||
".sidebar-section-link-content-text",
|
||||
text: I18n.t("js.footnote.title"),
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -60,6 +60,10 @@ module PageObjects
|
|||
def toggle_all_sections
|
||||
find(".sidebar-toggle-all-sections").click
|
||||
end
|
||||
|
||||
def toggle_section(name)
|
||||
find("[data-section-name='admin-#{name.to_s.downcase}']").click
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue
Block a user