From d956050ca1c818b6f34bfdfc9da265c63aa1db43 Mon Sep 17 00:00:00 2001 From: Martin Brennan Date: Wed, 12 Feb 2025 14:09:39 +1000 Subject: [PATCH] FEATURE: Experimental admin search This feature allows admins to find what they are looking for in the admin interface via a command palette. This replaces the admin sidebar filter as the focus of the Ctrl+/ command, but the sidebar filter can also still be used. Perhaps at some point we may remove it or change the shortcut. The palette presents the following data for filtering: * The admin nav map, which is also used for the sidebar * All site settings * Themes * Components Admins can also filter which items are shown in the palette. This is still **extremely** WIP -- the interface for the palette is not ideal, it's not keyboard accessible, the design needs to be refined, the code needs to be refined, and there are still numerous other considerations here, like: * Do we want to include reports? * We need to include the automatically generated plugin setting pages added by Ted * Do we want to show screenshots for themes and components if available, or stick to icons? * Site setting filters are janky when visitng the same setting page with a different filter, the page is not refreshed --- .../addon/components/admin-palette-search.gjs | 132 +++++++++++ .../addon/components/modal/admin-palette.gjs | 20 ++ .../services/admin-palette-data-source.js | 209 ++++++++++++++++++ .../discourse/app/lib/keyboard-shortcuts.js | 13 +- .../app/lib/sidebar/admin-nav-map.js | 91 ++++++++ .../app/lib/sidebar/admin-sidebar.js | 47 ---- .../stylesheets/common/admin/admin_base.scss | 1 + .../common/admin/palette_search.scss | 42 ++++ app/controllers/admin/palette_controller.rb | 22 ++ app/serializers/basic_theme_serializer.rb | 6 +- app/serializers/theme_serializer.rb | 5 - config/locales/client.en.yml | 9 + config/routes.rb | 5 +- config/site_settings.yml | 4 + lib/site_setting_extension.rb | 24 +- .../config/locales/client.en.yml | 5 + .../config/locales/client.en.yml | 5 + .../config/locales/client.en.yml | 5 + plugins/footnote/config/locales/client.en.yml | 5 + plugins/poll/config/locales/client.en.yml | 5 + .../config/locales/client.en.yml | 5 + .../styleguide/config/locales/client.en.yml | 5 + 22 files changed, 602 insertions(+), 63 deletions(-) create mode 100644 app/assets/javascripts/admin/addon/components/admin-palette-search.gjs create mode 100644 app/assets/javascripts/admin/addon/components/modal/admin-palette.gjs create mode 100644 app/assets/javascripts/admin/addon/services/admin-palette-data-source.js create mode 100644 app/assets/stylesheets/common/admin/palette_search.scss create mode 100644 app/controllers/admin/palette_controller.rb diff --git a/app/assets/javascripts/admin/addon/components/admin-palette-search.gjs b/app/assets/javascripts/admin/addon/components/admin-palette-search.gjs new file mode 100644 index 00000000000..8f7d700e5ad --- /dev/null +++ b/app/assets/javascripts/admin/addon/components/admin-palette-search.gjs @@ -0,0 +1,132 @@ +import Component from "@glimmer/component"; +import { tracked } from "@glimmer/tracking"; +import { fn } from "@ember/helper"; +import { on } from "@ember/modifier"; +import { action } from "@ember/object"; +import { service } from "@ember/service"; +import { htmlSafe } from "@ember/template"; +import DButton from "discourse/components/d-button"; +import DToggleSwitch from "discourse/components/d-toggle-switch"; +import icon from "discourse/helpers/d-icon"; +import autoFocus from "discourse/modifiers/auto-focus"; + +export default class AdminPaletteSearch extends Component { + @service adminPaletteDataSource; + + @tracked filter = ""; + @tracked searchResults = []; + @tracked showTypeFilters = false; + @tracked showPageType = true; + @tracked showSettingType = true; + @tracked showThemeType = true; + @tracked showComponentType = true; + + constructor() { + super(...arguments); + this.adminPaletteDataSource.buildMap(); + } + + get visibleTypes() { + const types = []; + if (this.showPageType) { + types.push("page"); + } + if (this.showSettingType) { + types.push("setting"); + } + if (this.showThemeType) { + types.push("theme"); + } + if (this.showComponentType) { + types.push("component"); + } + return types; + } + + @action + toggleTypeFilters() { + this.showTypeFilters = !this.showTypeFilters; + } + + @action + toggleTypeFilter(type) { + this[type] = !this[type]; + this.search(); + } + + @action + changeSearchTerm(event) { + this.searchResults = []; + this.filter = event.target.value; + this.search(); + } + + @action + search() { + this.searchResults = this.adminPaletteDataSource.search(this.filter, { + types: this.visibleTypes, + }); + } + + +} diff --git a/app/assets/javascripts/admin/addon/components/modal/admin-palette.gjs b/app/assets/javascripts/admin/addon/components/modal/admin-palette.gjs new file mode 100644 index 00000000000..7e59dd83fa9 --- /dev/null +++ b/app/assets/javascripts/admin/addon/components/modal/admin-palette.gjs @@ -0,0 +1,20 @@ +import Component from "@glimmer/component"; +import { service } from "@ember/service"; +import DModal from "discourse/components/d-modal"; +import AdminPaletteSearch from "admin/components/admin-palette-search"; + +export default class AdminPaletteModal extends Component { + @service currentUser; + + +} diff --git a/app/assets/javascripts/admin/addon/services/admin-palette-data-source.js b/app/assets/javascripts/admin/addon/services/admin-palette-data-source.js new file mode 100644 index 00000000000..20561ca3fa0 --- /dev/null +++ b/app/assets/javascripts/admin/addon/services/admin-palette-data-source.js @@ -0,0 +1,209 @@ +import Service, { service } from "@ember/service"; +import { ajax } from "discourse/lib/ajax"; +import escapeRegExp from "discourse/lib/escape-regexp"; +import getURL from "discourse/lib/get-url"; +import PreloadStore from "discourse/lib/preload-store"; +import { ADMIN_NAV_MAP } from "discourse/lib/sidebar/admin-nav-map"; +import I18n, { i18n } from "discourse-i18n"; + +const RESULT_TYPES = ["page", "setting", "theme", "component"]; + +export default class AdminPaletteDataSource extends Service { + @service router; + @service siteSettings; + + pageMapItems = []; + settingMapItems = []; + themeMapItems = []; + componentMapItems = []; + settingPageMap = { + categories: {}, + areas: {}, + }; + _mapCached = false; + + buildMap() { + if (this._mapCached) { + return; + } + ADMIN_NAV_MAP.forEach((mapItem) => { + mapItem.links.forEach((link) => { + let url; + if (link.routeModels) { + url = this.router.urlFor(link.route, ...link.routeModels); + } else { + url = this.router.urlFor(link.route); + } + + const mapItemLabel = + mapItem.text || (mapItem.label ? i18n(mapItem.label) : ""); + const label = + mapItemLabel + + (mapItemLabel ? " > " : "") + + (link.text || (link.label ? i18n(link.label) : "")); + + if (link.settings_area) { + this.settingPageMap.areas[link.settings_area] = link.multi_tabbed + ? `${url}/settings` + : url; + } + + if (link.settings_category) { + this.settingPageMap.categories[link.settings_category] = + link.multi_tabbed ? `${url}/settings` : url; + } + + this.pageMapItems.push({ + label, + url, + keywords: + (link.keywords ? i18n(link.keywords).toLowerCase() : "") + + " " + + url + + " " + + label.toLowerCase(), + type: "page", + icon: link.icon, + description: link.description ? i18n(link.description) : "", + }); + }); + }); + + // TODO (martin) Probably hash these with the plugin name as key + const visiblePlugins = PreloadStore.get("visiblePlugins") || []; + ajax("/admin/palette/settings.json").then((result) => { + result.forEach((setting) => { + // TODO: (martin) Might want to use the sidebar link name for this instead of the + // plugin category? + + let rootLabel; + if (setting.plugin) { + rootLabel = + I18n.lookup( + `admin.site_settings.categories.${setting.plugin.replaceAll( + "-", + "_" + )}` + ) || i18n("admin.plugins.title"); + } else if (setting.primary_area) { + rootLabel = + I18n.lookup(`admin.config.${setting.primary_area}.title`) || + i18n(`admin.site_settings.categories.${setting.category}`); + } else { + rootLabel = i18n( + `admin.site_settings.categories.${setting.category}` + ); + } + const label = rootLabel + " > " + setting.setting; + + let url; + if (setting.plugin) { + const plugin = visiblePlugins.find( + (visiblePlugin) => visiblePlugin.name === setting.plugin + ); + if (plugin && plugin.admin_route) { + url = plugin.admin_route.use_new_show_route + ? this.router.urlFor( + `adminPlugins.show.settings`, + plugin.admin_route.location, + { queryParams: { filter: setting.setting } } + ) + : this.router.urlFor( + `adminPlugins.${plugin.admin_route.location}` + ); + } else { + url = getURL( + `/admin/site_settings/category/all_results?filter=${setting.setting}` + ); + } + } else if (this.settingPageMap.areas[setting.primary_area]) { + url = + this.settingPageMap.areas[setting.primary_area] + + `?filter=${setting.setting}`; + } else if (this.settingPageMap.categories[setting.category]) { + url = + this.settingPageMap.categories[setting.category] + + `?filter=${setting.setting}`; + } else { + url = getURL( + `/admin/site_settings/category/all_results?filter=${setting.setting}` + ); + } + + this.settingMapItems.push({ + label, + description: setting.description, + url, + keywords: ( + setting.setting + + " " + + setting.setting.split("_").join(" ") + + " " + + setting.description + + " " + + setting.keywords.join(" ") + + " " + + rootLabel + ).toLowerCase(), + type: "setting", + icon: "gear", + }); + }); + }); + ajax("/admin/palette/themes-and-components.json").then((result) => { + result.forEach((themeOrComponent) => { + if (themeOrComponent.component) { + this.componentMapItems.push({ + label: themeOrComponent.name, + description: themeOrComponent.description, + url: getURL(`/admin/customize/components/${themeOrComponent.id}`), + keywords: ( + "component" + + " " + + themeOrComponent.description + + " " + + themeOrComponent.name + ).toLowerCase(), + type: "component", + icon: "puzzle-piece", + }); + } else { + this.themeMapItems.push({ + label: themeOrComponent.name, + description: themeOrComponent.description, + url: getURL(`/admin/customize/themes/${themeOrComponent.id}`), + keywords: ( + "theme" + + " " + + themeOrComponent.description + + " " + + themeOrComponent.name + ).toLowerCase(), + type: "theme", + icon: "paintbrush", + }); + } + }); + }); + this._mapCached = true; + } + + search(filter, opts = {}) { + if (filter.length < 2) { + return []; + } + opts.types = opts.types || RESULT_TYPES; + const filteredResults = []; + const escapedFilterRegExp = escapeRegExp(filter.toLowerCase()); + + opts.types.forEach((type) => { + this[`${type}MapItems`].forEach((mapItem) => { + if (mapItem.keywords.match(escapedFilterRegExp)) { + filteredResults.push(mapItem); + } + }); + }); + + return filteredResults; + } +} diff --git a/app/assets/javascripts/discourse/app/lib/keyboard-shortcuts.js b/app/assets/javascripts/discourse/app/lib/keyboard-shortcuts.js index a52d555e694..3745088e634 100644 --- a/app/assets/javascripts/discourse/app/lib/keyboard-shortcuts.js +++ b/app/assets/javascripts/discourse/app/lib/keyboard-shortcuts.js @@ -12,6 +12,7 @@ import { import DiscourseURL from "discourse/lib/url"; import Composer from "discourse/models/composer"; import { capabilities } from "discourse/services/capabilities"; +import AdminPaletteModal from "admin/components/modal/admin-palette"; let disabledBindings = []; export function disableDefaultKeyboardShortcuts(bindings) { @@ -496,10 +497,20 @@ export default { if (filterInput) { this._scrollTo(0); - filterInput.focus(); + + if (this.siteSettings.use_experimental_admin_search) { + this.showAdminSearchModal(); + } else { + filterInput.focus(); + } } }, + showAdminSearchModal() { + const modal = getOwner(this).lookup("service:modal"); + modal.show(AdminPaletteModal); + }, + fullscreenComposer() { const composer = getOwner(this).lookup("service:composer"); if (composer.get("model")) { 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 1363203ff2e..7ca8b6d4aa2 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,4 +1,46 @@ export const ADMIN_NAV_MAP = [ + { + text: "", + name: "root", + hideSectionHeader: true, + links: [ + { + name: "admin_home", + route: "admin.dashboard.general", + label: "admin.dashboard.title", + icon: "house", + moderator: true, + }, + { + name: "admin_users", + route: "adminUsers", + label: "admin.community.sidebar_link.users", + icon: "users", + moderator: true, + }, + { + name: "admin_groups", + route: "groups", + label: "admin.community.sidebar_link.groups", + icon: "user-group", + moderator: true, + }, + { + name: "admin_all_site_settings", + route: "adminSiteSettings", + label: "admin.advanced.sidebar_link.all_site_settings", + icon: "gear", + }, + { + name: "admin_whats_new", + route: "admin.whatsNew", + label: "admin.account.sidebar_link.whats_new.title", + icon: "gift", + keywords: "admin.account.sidebar_link.whats_new.keywords", + moderator: true, + }, + ], + }, { name: "account", label: "admin.account.title", @@ -8,6 +50,8 @@ export const ADMIN_NAV_MAP = [ route: "admin.backups", label: "admin.account.sidebar_link.backups", icon: "box-archive", + settings_category: "backups", + multi_tabbed: true, }, ], }, @@ -33,6 +77,7 @@ export const ADMIN_NAV_MAP = [ route: "adminConfig.about", label: "admin.community.sidebar_link.about_your_site", icon: "gear", + settings_area: "about", }, { name: "admin_badges", @@ -45,36 +90,48 @@ export const ADMIN_NAV_MAP = [ route: "adminConfig.loginAndAuthentication.settings", label: "admin.community.sidebar_link.login_and_authentication", icon: "unlock", + description: "admin.config.login_and_authentication.header_description", + settings_category: "login", }, { name: "admin_notifications", route: "adminConfig.notifications.settings", label: "admin.community.sidebar_link.notifications", icon: "bell", + description: "admin.config.notifications.header_description", + settings_area: "notifications", }, { name: "admin_localization", route: "adminConfig.localization.settings", label: "admin.community.sidebar_link.localization.title", icon: "globe", + description: "admin.config.localization.header_description", + settings_area: "localization", }, { name: "admin_permalinks", route: "adminPermalinks", label: "admin.community.sidebar_link.permalinks", icon: "link", + settings_area: "permalinks", + multi_tabbed: true, }, { name: "admin_trust_levels", route: "adminConfig.trustLevels.settings", label: "admin.community.sidebar_link.trust_levels", icon: "user-shield", + description: "admin.config.trust_levels.header_description", + settings_area: "trust_levels", }, { name: "admin_group_permissions", route: "adminConfig.groupPermissions.settings", label: "admin.community.sidebar_link.group_permissions", icon: "user-gear", + description: "admin.config.group_permissions.header_description", + settings_area: "group_permissions", }, { name: "admin_user_fields", @@ -94,6 +151,7 @@ export const ADMIN_NAV_MAP = [ route: "adminConfig.legal.settings", label: "admin.community.sidebar_link.legal", icon: "gavel", + description: "admin.config.legal.header_description", }, { name: "admin_moderation_flags", @@ -101,6 +159,8 @@ export const ADMIN_NAV_MAP = [ label: "admin.community.sidebar_link.moderation_flags.title", keywords: "admin.community.sidebar_link.moderation_flags.keywords", icon: "flag", + settings_area: "flags", + multi_tabbed: true, }, ], }, @@ -113,12 +173,16 @@ export const ADMIN_NAV_MAP = [ route: "adminConfig.fonts.settings", label: "admin.appearance.sidebar_link.font_style", icon: "italic", + description: "admin.config.font_style.header_description", + settings_area: "fonts", }, { name: "admin_site_logo", route: "adminConfig.logo.settings", label: "admin.appearance.sidebar_link.site_logo", icon: "fab-discourse", + description: "admin.config.logo.header_description", + settings_category: "branding", }, { name: "admin_color_schemes", @@ -131,12 +195,16 @@ export const ADMIN_NAV_MAP = [ route: "adminEmojis", label: "admin.appearance.sidebar_link.emoji", icon: "discourse-emojis", + settings_area: "emojis", + multi_tabbed: true, }, { name: "admin_navigation", route: "adminConfig.navigation.settings", label: "admin.appearance.sidebar_link.navigation", icon: "diagram-project", + description: "admin.config.navigation.header_description", + settings_area: "navigation", }, { name: "admin_themes", @@ -190,12 +258,16 @@ export const ADMIN_NAV_MAP = [ route: "adminConfig.security.settings", label: "admin.security.sidebar_link.security", icon: "lock", + description: "admin.config.security.header_description", + settings_category: "security", }, { name: "admin_spam", route: "adminConfig.spam.settings", label: "admin.security.sidebar_link.spam", icon: "robot", + description: "admin.config.spam.header_description", + settings_category: "spam", }, { name: "admin_logs_staff_action_logs", @@ -241,54 +313,73 @@ export const ADMIN_NAV_MAP = [ route: "adminConfig.developer.settings", label: "admin.advanced.sidebar_link.developer", icon: "keyboard", + description: "admin.config.developer.header_description", + settings_category: "developer", }, { name: "admin_embedding", route: "adminEmbedding", label: "admin.advanced.sidebar_link.embedding", icon: "code", + settings_area: "embedding", }, { name: "admin_rate_limits", route: "adminConfig.rate-limits.settings", label: "admin.advanced.sidebar_link.rate_limits", icon: "rocket", + description: "admin.config.rate_limits.header_description", + settings_category: "rate_limits", }, { name: "admin_user_api", route: "adminConfig.user-api.settings", label: "admin.advanced.sidebar_link.user_api", icon: "shuffle", + description: "admin.config.user_api.header_description", + settings_category: "user_api", }, { name: "admin_onebox", route: "adminConfig.onebox.settings", label: "admin.advanced.sidebar_link.onebox", icon: "far-square", + description: "admin.config.onebox.header_description", + + settings_category: "onebox", }, { name: "admin_files", route: "adminConfig.files.settings", label: "admin.advanced.sidebar_link.files", icon: "file", + description: "admin.config.files.header_description", + settings_category: "files", }, { name: "admin_other_options", route: "adminConfig.other.settings", label: "admin.advanced.sidebar_link.other_options", icon: "discourse-other-tab", + description: "admin.config.other.header_description", + + settings_category: "uncategorized", }, { name: "admin_search", route: "adminConfig.search.settings", label: "admin.advanced.sidebar_link.search", icon: "magnifying-glass", + description: "admin.config.search.header_description", + settings_category: "search", }, { name: "admin_experimental", route: "adminConfig.experimental.settings", label: "admin.advanced.sidebar_link.experimental", icon: "discourse-sparkles", + description: "admin.config.experimental.header_description", + settings_category: "experimental", }, ], }, diff --git a/app/assets/javascripts/discourse/app/lib/sidebar/admin-sidebar.js b/app/assets/javascripts/discourse/app/lib/sidebar/admin-sidebar.js index 5dd9c6a7832..283f7fd264a 100644 --- a/app/assets/javascripts/discourse/app/lib/sidebar/admin-sidebar.js +++ b/app/assets/javascripts/discourse/app/lib/sidebar/admin-sidebar.js @@ -184,53 +184,6 @@ function defineAdminSection( } export function useAdminNavConfig(navMap) { - const adminNavSections = [ - { - text: "", - name: "root", - hideSectionHeader: true, - links: [ - { - name: "admin_home", - route: "admin.dashboard.general", - label: "admin.dashboard.title", - icon: "house", - moderator: true, - }, - { - name: "admin_users", - route: "adminUsers", - label: "admin.community.sidebar_link.users", - icon: "users", - moderator: true, - }, - { - name: "admin_groups", - route: "groups", - label: "admin.community.sidebar_link.groups", - icon: "user-group", - moderator: true, - }, - { - name: "admin_all_site_settings", - route: "adminSiteSettings", - label: "admin.advanced.sidebar_link.all_site_settings", - icon: "gear", - }, - { - name: "admin_whats_new", - route: "admin.whatsNew", - label: "admin.account.sidebar_link.whats_new.title", - icon: "gift", - keywords: "admin.account.sidebar_link.whats_new.keywords", - moderator: true, - }, - ], - }, - ]; - - navMap = adminNavSections.concat(navMap); - for (const [sectionName, additionalLinks] of Object.entries( additionalAdminSidebarSectionLinks )) { diff --git a/app/assets/stylesheets/common/admin/admin_base.scss b/app/assets/stylesheets/common/admin/admin_base.scss index aa688abbc9e..c9cb1b25613 100644 --- a/app/assets/stylesheets/common/admin/admin_base.scss +++ b/app/assets/stylesheets/common/admin/admin_base.scss @@ -1224,6 +1224,7 @@ a.inline-editable-field { @import "common/admin/plugins"; @import "common/admin/site-settings"; @import "common/admin/admin_config_area"; +@import "common/admin/palette_search"; @import "common/admin/admin_table"; @import "common/admin/admin_filter"; @import "common/admin/admin_reports"; diff --git a/app/assets/stylesheets/common/admin/palette_search.scss b/app/assets/stylesheets/common/admin/palette_search.scss new file mode 100644 index 00000000000..d5b9d36d332 --- /dev/null +++ b/app/assets/stylesheets/common/admin/palette_search.scss @@ -0,0 +1,42 @@ +.admin-palette { + &__search-result { + border-top: 1px solid var(--primary-low); + padding: 0.5em 0; + } + + &__description { + font-size: var(--font-down-1); + color: var(--primary-medium); + margin-top: 0.5em; + } + + &__name { + color: var(--primary); + display: flex; + flex-wrap: wrap; + justify-content: space-between; + align-items: center; + + .d-icon { + flex: 0; + margin-right: 0.5em; + } + } + + &__name-label { + flex: 1; + } + + &__type-pill { + background-color: var(--primary-low); + color: var(--primary-medium); + padding: 0.25em 0.5em; + border-radius: 0.25em; + font-size: var(--font-down-2); + margin-right: 0.5em; + } +} + +.admin-palette-type-filter { + display: flex; +} diff --git a/app/controllers/admin/palette_controller.rb b/app/controllers/admin/palette_controller.rb new file mode 100644 index 00000000000..9557283aeca --- /dev/null +++ b/app/controllers/admin/palette_controller.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +class Admin::PaletteController < Admin::AdminController + # TODO: (martin) Maybe get all of these at once for initial cache? + def settings + render_json_dump( + SiteSetting.all_settings( + filter_names: params[:filter_names], + filter_area: params[:filter_area], + filter_plugin: params[:plugin], + filter_categories: Array.wrap(params[:categories]), + include_locale_setting: params[:filter_area] == "localization", + basic_attributes: true, + ), + ) + end + + def themes_and_components + themes = Theme.include_relations.order(:name) + render_json_dump(serialize_data(themes, BasicThemeSerializer)) + end +end diff --git a/app/serializers/basic_theme_serializer.rb b/app/serializers/basic_theme_serializer.rb index c0affe8c61a..3339209f4a8 100644 --- a/app/serializers/basic_theme_serializer.rb +++ b/app/serializers/basic_theme_serializer.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class BasicThemeSerializer < ApplicationSerializer - attributes :id, :name, :created_at, :updated_at, :default, :component + attributes :id, :name, :description, :created_at, :updated_at, :default, :component def include_default? object.id == SiteSetting.default_theme_id @@ -10,4 +10,8 @@ class BasicThemeSerializer < ApplicationSerializer def default true end + + def description + object.internal_translations.find { |t| t.key == "theme_metadata.description" }&.value + end end diff --git a/app/serializers/theme_serializer.rb b/app/serializers/theme_serializer.rb index febd97eb210..9456f440db3 100644 --- a/app/serializers/theme_serializer.rb +++ b/app/serializers/theme_serializer.rb @@ -10,7 +10,6 @@ class ThemeSerializer < BasicThemeSerializer :settings, :errors, :supported?, - :description, :enabled?, :disabled_at, :theme_fields, @@ -84,10 +83,6 @@ class ThemeSerializer < BasicThemeSerializer @errors.present? end - def description - object.internal_translations.find { |t| t.key == "theme_metadata.description" }&.value - end - def include_disabled_at? object.component? && !object.enabled? end diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 97a4eaf8d79..3150e63a383 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -5160,12 +5160,21 @@ en: all: "All reports" config: + about: + title: "About your site" + header_decription: "Provide information here about this site and your team so that people can learn what your community is about, who is behind it, and how to reach you in case there is an issue. Displayed on your site's About page." developer: title: "Developer" header_description: "Developer settings to control rate limits, multipliers and calculations, safe mode, and other advanced features" experimental: title: "Experimental" header_description: "Toggle experimental features on or off for your site, most of these can be controlled on a group basis" + emojis: + title: "Emoji" + header_description: "Add new emoji that will be available to everyone. Select multiple files to create emojis using their file names. The selected group will be used for all files that are added at the same time" + flags: + title: "Moderation" + header_description: "The flagging system in Discourse helps you and your moderator team manage content and user behavior, keeping your community respectful and healthy. The defaults are suitable for most communities and you don’t have to change them. However, if your site has particular requirements you can disable flags you don’t need and add your own custom flags." font_style: title: "Font style" header_description: "Customize the font styles used by your themes" diff --git a/config/routes.rb b/config/routes.rb index dec00caed17..4f32739f5f9 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -386,9 +386,12 @@ Discourse::Application.routes.draw do post "preview" => "badges#preview" end end + + get "palette/settings" => "palette#settings" + get "palette/themes-and-components" => "palette#themes_and_components" + namespace :config, constraints: StaffConstraint.new do resources :site_settings, only: %i[index] - get "developer" => "site_settings#index" get "fonts" => "site_settings#index" get "files" => "site_settings#index" diff --git a/config/site_settings.yml b/config/site_settings.yml index b9a8e9537d4..a50ee718422 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -3533,6 +3533,10 @@ experimental: allow_any: false refresh: true area: "group_permissions|navigation" + use_experimental_admin_search: + default: false + hidden: true + client: true glimmer_topic_list_mode: client: true type: enum diff --git a/lib/site_setting_extension.rb b/lib/site_setting_extension.rb index e603dacfaf9..46c94444eb6 100644 --- a/lib/site_setting_extension.rb +++ b/lib/site_setting_extension.rb @@ -201,6 +201,7 @@ module SiteSettingExtension include_hidden: false, include_locale_setting: true, only_overridden: false, + basic_attributes: false, filter_categories: nil, filter_plugin: nil, filter_names: nil, @@ -271,15 +272,22 @@ module SiteSettingExtension setting: s, description: description(s), keywords: keywords(s), - default: default, - value: value.to_s, category: categories[s], - preview: previews[s], - secret: secret_settings.include?(s), - placeholder: placeholder(s), - mandatory_values: mandatory_values[s], - requires_confirmation: requires_confirmation_settings[s], - }.merge!(type_hash) + primary_area: areas[s]&.first, + } + + if !basic_attributes + opts.merge!( + default: default, + value: value.to_s, + preview: previews[s], + secret: secret_settings.include?(s), + placeholder: placeholder(s), + mandatory_values: mandatory_values[s], + requires_confirmation: requires_confirmation_settings[s], + ) + opts.merge!(type_hash) + end opts[:plugin] = plugins[s] if plugins[s] diff --git a/plugins/discourse-details/config/locales/client.en.yml b/plugins/discourse-details/config/locales/client.en.yml index 59e84a84753..66788556380 100644 --- a/plugins/discourse-details/config/locales/client.en.yml +++ b/plugins/discourse-details/config/locales/client.en.yml @@ -1,4 +1,9 @@ en: + admin_js: + admin: + site_settings: + categories: + discourse_details: "Discourse Details" js: details: title: Hide Details diff --git a/plugins/discourse-local-dates/config/locales/client.en.yml b/plugins/discourse-local-dates/config/locales/client.en.yml index a18bddd9762..2c47af983a4 100644 --- a/plugins/discourse-local-dates/config/locales/client.en.yml +++ b/plugins/discourse-local-dates/config/locales/client.en.yml @@ -1,4 +1,9 @@ en: + admin_js: + admin: + site_settings: + categories: + discourse_local_dates: "Discourse Local Dates" js: discourse_local_dates: relative_dates: diff --git a/plugins/discourse-narrative-bot/config/locales/client.en.yml b/plugins/discourse-narrative-bot/config/locales/client.en.yml index 912895794d3..cc8a59adcb1 100644 --- a/plugins/discourse-narrative-bot/config/locales/client.en.yml +++ b/plugins/discourse-narrative-bot/config/locales/client.en.yml @@ -4,3 +4,8 @@ en: welcome_post_type: new_user_track: "Start the new user tutorial for all new users" welcome_message: "Send all new users a welcome message with a quick start guide" + admin_js: + admin: + site_settings: + categories: + discourse_narrative_bot: "Discourse Narrative Bot" diff --git a/plugins/footnote/config/locales/client.en.yml b/plugins/footnote/config/locales/client.en.yml index 3ec76b7191c..81f49ce905e 100644 --- a/plugins/footnote/config/locales/client.en.yml +++ b/plugins/footnote/config/locales/client.en.yml @@ -1,4 +1,9 @@ en: + admin_js: + admin: + site_settings: + categories: + footnote: "Discourse Footnotes" js: footnote: title: "Footnotes" diff --git a/plugins/poll/config/locales/client.en.yml b/plugins/poll/config/locales/client.en.yml index 16ee4b2dcfa..b86d865549d 100644 --- a/plugins/poll/config/locales/client.en.yml +++ b/plugins/poll/config/locales/client.en.yml @@ -1,4 +1,9 @@ en: + admin_js: + admin: + site_settings: + categories: + poll: "Discourse Poll" js: poll: voters: diff --git a/plugins/spoiler-alert/config/locales/client.en.yml b/plugins/spoiler-alert/config/locales/client.en.yml index f4fb352b93d..8d615f509f5 100644 --- a/plugins/spoiler-alert/config/locales/client.en.yml +++ b/plugins/spoiler-alert/config/locales/client.en.yml @@ -1,4 +1,9 @@ en: + admin_js: + admin: + site_settings: + categories: + spoiler_alert: "Discourse Spoiler Alert" js: spoiler: title: Blur Spoiler diff --git a/plugins/styleguide/config/locales/client.en.yml b/plugins/styleguide/config/locales/client.en.yml index dd93bfdc82e..b394bf02294 100644 --- a/plugins/styleguide/config/locales/client.en.yml +++ b/plugins/styleguide/config/locales/client.en.yml @@ -1,4 +1,9 @@ en: + admin_js: + admin: + site_settings: + categories: + styleguide: "Discourse Styleguide" js: styleguide: title: "Styleguide"