mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
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
This commit is contained in:
@@ -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,
|
||||
});
|
||||
}
|
||||
|
||||
<template>
|
||||
<input
|
||||
type="text"
|
||||
class="admin-palette__search-input"
|
||||
{{autoFocus}}
|
||||
{{on "input" this.changeSearchTerm}}
|
||||
/>
|
||||
<DButton @icon="filter" @action={{this.toggleTypeFilters}} />
|
||||
|
||||
{{#if this.showTypeFilters}}
|
||||
<div class="admin-palette-type-filter">
|
||||
<span class="admin-palette-type-filter__page">
|
||||
Pages
|
||||
<DToggleSwitch
|
||||
@state={{this.showPageType}}
|
||||
{{on "click" (fn this.toggleTypeFilter "showPageType")}}
|
||||
/>
|
||||
</span>
|
||||
<span class="admin-palette-type-filter__setting">
|
||||
Settings
|
||||
<DToggleSwitch
|
||||
@state={{this.showSettingType}}
|
||||
{{on "click" (fn this.toggleTypeFilter "showSettingType")}}
|
||||
/>
|
||||
</span>
|
||||
<span class="admin-palette-type-filter__theme">
|
||||
Themes
|
||||
<DToggleSwitch
|
||||
@state={{this.showThemeType}}
|
||||
{{on "click" (fn this.toggleTypeFilter "showThemeType")}}
|
||||
/>
|
||||
</span>
|
||||
<span class="admin-palette-type-filter__component">
|
||||
Components
|
||||
<DToggleSwitch
|
||||
@state={{this.showComponentType}}
|
||||
{{on "click" (fn this.toggleTypeFilter "showComponentType")}}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="admin-palette__search-results">
|
||||
{{#each this.searchResults as |result|}}
|
||||
<div class="admin-palette__search-result">
|
||||
<a href={{result.url}}>
|
||||
<div class="admin-palette__name">
|
||||
{{icon result.icon}}
|
||||
<span class="admin-palette__name-label">{{result.label}}</span>
|
||||
<span class="admin-palette__type-pill">{{result.type}}</span>
|
||||
</div>
|
||||
{{#if result.description}}
|
||||
<p class="admin-palette__description">{{htmlSafe
|
||||
result.description
|
||||
}}</p>
|
||||
{{/if}}
|
||||
</a>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
</template>
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
<template>
|
||||
<DModal
|
||||
@closeModal={{@closeModal}}
|
||||
class="admin-palette-modal"
|
||||
@title="admin.palette.search"
|
||||
@inline={{@inline}}
|
||||
@hideHeader={{true}}
|
||||
>
|
||||
<AdminPaletteSearch />
|
||||
</DModal>
|
||||
</template>
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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")) {
|
||||
|
||||
@@ -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",
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -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
|
||||
)) {
|
||||
|
||||
@@ -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";
|
||||
|
||||
42
app/assets/stylesheets/common/admin/palette_search.scss
Normal file
42
app/assets/stylesheets/common/admin/palette_search.scss
Normal file
@@ -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;
|
||||
}
|
||||
22
app/controllers/admin/palette_controller.rb
Normal file
22
app/controllers/admin/palette_controller.rb
Normal file
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 <a href='%{basePath}/about'>About page</a>."
|
||||
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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
en:
|
||||
admin_js:
|
||||
admin:
|
||||
site_settings:
|
||||
categories:
|
||||
discourse_details: "Discourse Details"
|
||||
js:
|
||||
details:
|
||||
title: Hide Details
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
en:
|
||||
admin_js:
|
||||
admin:
|
||||
site_settings:
|
||||
categories:
|
||||
discourse_local_dates: "Discourse Local Dates"
|
||||
js:
|
||||
discourse_local_dates:
|
||||
relative_dates:
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
en:
|
||||
admin_js:
|
||||
admin:
|
||||
site_settings:
|
||||
categories:
|
||||
footnote: "Discourse Footnotes"
|
||||
js:
|
||||
footnote:
|
||||
title: "Footnotes"
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
en:
|
||||
admin_js:
|
||||
admin:
|
||||
site_settings:
|
||||
categories:
|
||||
poll: "Discourse Poll"
|
||||
js:
|
||||
poll:
|
||||
voters:
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
en:
|
||||
admin_js:
|
||||
admin:
|
||||
site_settings:
|
||||
categories:
|
||||
spoiler_alert: "Discourse Spoiler Alert"
|
||||
js:
|
||||
spoiler:
|
||||
title: Blur Spoiler
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
en:
|
||||
admin_js:
|
||||
admin:
|
||||
site_settings:
|
||||
categories:
|
||||
styleguide: "Discourse Styleguide"
|
||||
js:
|
||||
styleguide:
|
||||
title: "Styleguide"
|
||||
|
||||
Reference in New Issue
Block a user