DEV: Remove admin-revamp and introduce foundations for admin config (#27293)
This commit removes the `/admin-revamp` routes which were introduced as a part of an experiment to revamp the admin pages. We still want to improve the admin/staff experience, but we're going to do them within the existing `/admin` routes instead of introducing a completely new route. Our initial efforts to improve the Discourse admin experience is this commit which introduces the foundation for a new subroute `/admin/config` which will house various new pages for configuring Discourse. The first new page (or "config area") will be `/admin/config/about` that will house all the settings and controls for configuring the `/about` page of Discourse. Internal topic: t/128544
This commit is contained in:
parent
aec892339e
commit
fed9055818
|
@ -1,46 +0,0 @@
|
|||
<div
|
||||
class="admin-config-area-sidebar-experiment"
|
||||
{{did-insert this.loadDefaultNavConfig}}
|
||||
>
|
||||
<h4>Sidebar Experiment</h4>
|
||||
<p>Changes you make here will be applied to the admin sidebar and persist
|
||||
between reloads
|
||||
<em>on this device only</em>. Note that in addition to the
|
||||
<code>text</code>
|
||||
and
|
||||
<code>route</code>
|
||||
options, you can also specify a
|
||||
<code>icon</code>
|
||||
or a
|
||||
<code>href</code>, if you want to link to a specific page but don't know the
|
||||
Ember route. You can also use the Ember Inspector extension to find route
|
||||
names, for example for plugin routes which are not auto-generated here.
|
||||
<br /><br />
|
||||
<code>routeModels</code>
|
||||
is an array of values that correspond to parts of the route; for example the
|
||||
topic route may be
|
||||
<code>/t/:id</code>, so to get a link to topic with ID 123 you would do
|
||||
<code>routeModels: [123]</code>.</p>
|
||||
|
||||
<p>All configuration options for a section and its links looks like this:</p>
|
||||
|
||||
<pre><code>{{this.exampleJson}}</code></pre>
|
||||
|
||||
<DButton
|
||||
@action={{this.resetToDefault}}
|
||||
@translatedLabel="Reset to Default"
|
||||
/>
|
||||
<DButton
|
||||
class="btn-primary"
|
||||
@action={{this.applyConfig}}
|
||||
@translatedLabel="Apply Config"
|
||||
/>
|
||||
|
||||
<div class="admin-config-area-sidebar-experiment__editor">
|
||||
<AceEditor
|
||||
@content={{this.editedNavConfig}}
|
||||
@editorId="admin-config-area-sidebar-experiment"
|
||||
@save={{this.applyNav}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
|
@ -1,130 +0,0 @@
|
|||
import Component from "@glimmer/component";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import { action } from "@ember/object";
|
||||
import { service } from "@ember/service";
|
||||
import { ADMIN_NAV_MAP } from "discourse/lib/sidebar/admin-nav-map";
|
||||
import {
|
||||
buildAdminSidebar,
|
||||
useAdminNavConfig,
|
||||
} from "discourse/lib/sidebar/admin-sidebar";
|
||||
import { resetPanelSections } from "discourse/lib/sidebar/custom-sections";
|
||||
import { ADMIN_PANEL } from "discourse/lib/sidebar/panels";
|
||||
|
||||
// TODO (martin) (2024-02-01) Remove this experimental UI.
|
||||
export default class AdminConfigAreaSidebarExperiment extends Component {
|
||||
@service adminSidebarStateManager;
|
||||
@service toasts;
|
||||
@service router;
|
||||
@tracked editedNavConfig;
|
||||
|
||||
validRouteNames = new Set();
|
||||
|
||||
get defaultAdminNav() {
|
||||
return JSON.stringify(ADMIN_NAV_MAP, null, 2);
|
||||
}
|
||||
|
||||
get exampleJson() {
|
||||
return JSON.stringify(
|
||||
{
|
||||
name: "section-name",
|
||||
text: "Section Name",
|
||||
links: [
|
||||
{
|
||||
name: "admin-revamp",
|
||||
route: "admin-revamp",
|
||||
routeModels: [123],
|
||||
text: "Revamp",
|
||||
href: "https://forum.site.com/t/123",
|
||||
icon: "rocket",
|
||||
},
|
||||
],
|
||||
},
|
||||
null,
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
@action
|
||||
loadDefaultNavConfig() {
|
||||
const savedConfig = this.adminSidebarStateManager.navConfig;
|
||||
this.editedNavConfig = savedConfig
|
||||
? JSON.stringify(savedConfig, null, 2)
|
||||
: this.defaultAdminNav;
|
||||
}
|
||||
|
||||
@action
|
||||
resetToDefault() {
|
||||
this.editedNavConfig = this.defaultAdminNav;
|
||||
this.#saveConfig(ADMIN_NAV_MAP);
|
||||
}
|
||||
|
||||
@action
|
||||
applyConfig() {
|
||||
let config = null;
|
||||
try {
|
||||
config = JSON.parse(this.editedNavConfig);
|
||||
} catch {
|
||||
this.toasts.error({
|
||||
duration: 3000,
|
||||
data: {
|
||||
message: "There was an error, make sure the structure is valid JSON.",
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
let invalidRoutes = [];
|
||||
config.forEach((section) => {
|
||||
section.links.forEach((link) => {
|
||||
if (!link.route) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.validRouteNames.has(link.route)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Using the private `_routerMicrolib` is not ideal, but Ember doesn't provide
|
||||
// any other way for us to easily check for route validity.
|
||||
try {
|
||||
// eslint-disable-next-line ember/no-private-routing-service
|
||||
this.router._router._routerMicrolib.recognizer.handlersFor(
|
||||
link.route
|
||||
);
|
||||
this.validRouteNames.add(link.route);
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.debug("[AdminSidebarExperiment]", err);
|
||||
invalidRoutes.push(link.route);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (invalidRoutes.length) {
|
||||
this.toasts.error({
|
||||
duration: 3000,
|
||||
data: {
|
||||
message: `There was an error with one or more of the routes provided: ${invalidRoutes.join(
|
||||
", "
|
||||
)}`,
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.#saveConfig(config);
|
||||
}
|
||||
|
||||
#saveConfig(config) {
|
||||
this.adminSidebarStateManager.navConfig = config;
|
||||
resetPanelSections(
|
||||
ADMIN_PANEL,
|
||||
useAdminNavConfig(config),
|
||||
buildAdminSidebar
|
||||
);
|
||||
this.toasts.success({
|
||||
duration: 3000,
|
||||
data: { message: "Sidebar navigation applied successfully!" },
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
import Component from "@glimmer/component";
|
||||
|
||||
export default class AdminConfigAreasAbout extends Component {
|
||||
cards = [1, 2, 3];
|
||||
|
||||
<template>
|
||||
<div class="admin-config-area">
|
||||
<div class="admin-config-area__primary-content">
|
||||
{{#each this.cards as |card|}}
|
||||
<div>{{card}}</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
import Controller from "@ember/controller";
|
||||
import { service } from "@ember/service";
|
||||
import { dasherize } from "@ember/string";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default class AdminRevampController extends Controller {
|
||||
@service router;
|
||||
|
||||
@discourseComputed("router._router.currentPath")
|
||||
adminContentsClassName(currentPath) {
|
||||
let cssClasses = currentPath
|
||||
.split(".")
|
||||
.filter((segment) => {
|
||||
return (
|
||||
segment !== "index" &&
|
||||
segment !== "loading" &&
|
||||
segment !== "show" &&
|
||||
segment !== "admin"
|
||||
);
|
||||
})
|
||||
.map(dasherize)
|
||||
.join(" ");
|
||||
|
||||
// this is done to avoid breaking css customizations
|
||||
if (cssClasses.includes("dashboard")) {
|
||||
cssClasses = `${cssClasses} dashboard-next`;
|
||||
}
|
||||
|
||||
return cssClasses;
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
import Route from "@ember/routing/route";
|
||||
import { service } from "@ember/service";
|
||||
import { dasherize } from "@ember/string";
|
||||
import AdminConfigAreaSidebarExperiment from "admin/components/admin-config-area-sidebar-experiment";
|
||||
|
||||
const CONFIG_AREA_COMPONENT_MAP = {
|
||||
"sidebar-experiment": AdminConfigAreaSidebarExperiment,
|
||||
};
|
||||
|
||||
export default class AdminRevampConfigAreaRoute extends Route {
|
||||
@service router;
|
||||
|
||||
async model(params) {
|
||||
return {
|
||||
area: params.area,
|
||||
configAreaComponent: CONFIG_AREA_COMPONENT_MAP[dasherize(params.area)],
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
import Route from "@ember/routing/route";
|
||||
import { service } from "@ember/service";
|
||||
|
||||
export default class AdminRevampConfigRoute extends Route {
|
||||
@service router;
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
import Route from "@ember/routing/route";
|
||||
import { service } from "@ember/service";
|
||||
|
||||
export default class AdminRevampLobbyRoute extends Route {
|
||||
@service router;
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
import { service } from "@ember/service";
|
||||
import { MAIN_PANEL } from "discourse/lib/sidebar/panels";
|
||||
import DiscourseURL from "discourse/lib/url";
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import I18n from "discourse-i18n";
|
||||
|
||||
// DEPRECATED: (martin) This route is deprecated and will be removed in the near future.
|
||||
export default class AdminRoute extends DiscourseRoute {
|
||||
@service siteSettings;
|
||||
@service currentUser;
|
||||
@service sidebarState;
|
||||
@service adminSidebarStateManager;
|
||||
|
||||
titleToken() {
|
||||
return I18n.t("admin_title");
|
||||
}
|
||||
|
||||
activate() {
|
||||
if (!this.currentUser.use_admin_sidebar) {
|
||||
return DiscourseURL.redirectTo("/admin");
|
||||
}
|
||||
|
||||
this.adminSidebarStateManager.maybeForceAdminSidebar({
|
||||
onlyIfAlreadyActive: false,
|
||||
});
|
||||
|
||||
this.controllerFor("application").setProperties({
|
||||
showTop: false,
|
||||
});
|
||||
}
|
||||
|
||||
deactivate(transition) {
|
||||
this.controllerFor("application").set("showTop", true);
|
||||
if (this.adminSidebarStateManager.currentUserUsingAdminSidebar) {
|
||||
if (!transition?.to.name.startsWith("admin")) {
|
||||
this.sidebarState.setPanel(MAIN_PANEL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -210,10 +210,14 @@ export default function () {
|
|||
);
|
||||
|
||||
this.route(
|
||||
"adminConfigFlags",
|
||||
{ path: "/config/flags", resetNamespace: true },
|
||||
"adminConfig",
|
||||
{ path: "/config", resetNamespace: true },
|
||||
function () {
|
||||
this.route("index", { path: "/" });
|
||||
this.route("flags", function () {
|
||||
this.route("index", { path: "/" });
|
||||
});
|
||||
|
||||
this.route("about");
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -233,14 +237,4 @@ export default function () {
|
|||
resetNamespace: true,
|
||||
});
|
||||
});
|
||||
|
||||
// EXPERIMENTAL: These admin routes are hidden behind an `admin_sidebar_enabled_groups`
|
||||
// site setting and are subject to constant change.
|
||||
this.route("admin-revamp", { resetNamespace: true }, function () {
|
||||
this.route("lobby", { path: "/" }, function () {});
|
||||
|
||||
this.route("config", function () {
|
||||
this.route("area", { path: "/:area" });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
<div class="admin-revamp__config-area">
|
||||
{{#if @model.configAreaComponent}}
|
||||
<@model.configAreaComponent />
|
||||
{{/if}}
|
||||
</div>
|
|
@ -1,3 +0,0 @@
|
|||
<div class="admin-revamp__config">
|
||||
{{outlet}}
|
||||
</div>
|
|
@ -1 +0,0 @@
|
|||
Admin Revamp Lobby
|
|
@ -1,13 +0,0 @@
|
|||
{{hide-application-footer}}
|
||||
{{html-class "admin-area"}}
|
||||
{{body-class "admin-interface"}}
|
||||
|
||||
<div class="row">
|
||||
<div class="full-width">
|
||||
<div class="boxed white admin-content">
|
||||
<div class="admin-contents {{this.adminContentsClassName}}">
|
||||
{{outlet}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1 @@
|
|||
<AdminConfigAreas::About />
|
|
@ -112,7 +112,7 @@ export const ADMIN_NAV_MAP = [
|
|||
},
|
||||
{
|
||||
name: "admin_moderation_flags",
|
||||
route: "adminConfigFlags",
|
||||
route: "adminConfig.flags",
|
||||
label: "admin.community.sidebar_link.moderation_flags",
|
||||
icon: "flag",
|
||||
},
|
||||
|
|
|
@ -12,7 +12,6 @@ import {
|
|||
secondaryCustomSectionLinks,
|
||||
} from "discourse/lib/sidebar/custom-community-section-links";
|
||||
import SectionLink from "discourse/lib/sidebar/section-link";
|
||||
import AdminRevampSectionLink from "discourse/lib/sidebar/user/community-section/admin-revamp-section-link";
|
||||
import AdminSectionLink from "discourse/lib/sidebar/user/community-section/admin-section-link";
|
||||
import MyPostsSectionLink from "discourse/lib/sidebar/user/community-section/my-posts-section-link";
|
||||
import ReviewSectionLink from "discourse/lib/sidebar/user/community-section/review-section-link";
|
||||
|
@ -26,7 +25,6 @@ const SPECIAL_LINKS_MAP = {
|
|||
"/review": ReviewSectionLink,
|
||||
"/badges": BadgesSectionLink,
|
||||
"/admin": AdminSectionLink,
|
||||
"/admin-revamp": AdminRevampSectionLink,
|
||||
"/g": GroupsSectionLink,
|
||||
};
|
||||
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
import { service } from "@ember/service";
|
||||
import BaseSectionLink from "discourse/lib/sidebar/base-community-section-link";
|
||||
import I18n from "discourse-i18n";
|
||||
|
||||
export default class AdminRevampSectionLink extends BaseSectionLink {
|
||||
@service siteSettings;
|
||||
|
||||
get name() {
|
||||
return "admin-revamp";
|
||||
}
|
||||
|
||||
get route() {
|
||||
return "admin-revamp";
|
||||
}
|
||||
|
||||
get title() {
|
||||
return I18n.t("sidebar.sections.community.links.admin.content");
|
||||
}
|
||||
|
||||
get text() {
|
||||
return I18n.t(
|
||||
`sidebar.sections.community.links.${this.overridenName.toLowerCase()}.content`,
|
||||
{ defaultValue: this.overridenName }
|
||||
);
|
||||
}
|
||||
|
||||
get shouldDisplay() {
|
||||
if (!this.currentUser) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.currentUser.use_admin_sidebar;
|
||||
}
|
||||
|
||||
get defaultPrefixValue() {
|
||||
return "star";
|
||||
}
|
||||
}
|
|
@ -1065,6 +1065,7 @@ a.inline-editable-field {
|
|||
@import "common/admin/api";
|
||||
@import "common/admin/backups";
|
||||
@import "common/admin/plugins";
|
||||
@import "common/admin/admin_config_area";
|
||||
@import "common/admin/admin_reports";
|
||||
@import "common/admin/admin_report";
|
||||
@import "common/admin/admin_report_counters";
|
||||
|
@ -1078,6 +1079,3 @@ a.inline-editable-field {
|
|||
@import "common/admin/mini_profiler";
|
||||
@import "common/admin/schema_theme_setting_editor";
|
||||
@import "common/admin/customize_themes_show_schema";
|
||||
|
||||
// EXPERIMENTAL: Revamped admin styles, probably can be split up later down the line.
|
||||
@import "common/admin/admin_revamp";
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
.admin-config-area {
|
||||
display: grid;
|
||||
grid-template-columns: 2fr 1fr;
|
||||
column-gap: 1em;
|
||||
|
||||
&__primary-content {
|
||||
background: red;
|
||||
}
|
||||
&__help-inset {
|
||||
background: green;
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
.admin-revamp {
|
||||
&__config-area {
|
||||
padding: 1em;
|
||||
margin: 1em 0;
|
||||
background-color: var(--primary-very-low);
|
||||
}
|
||||
}
|
||||
|
||||
.admin-config-area-sidebar-experiment {
|
||||
&__editor {
|
||||
margin-top: 1em;
|
||||
|
||||
.ace-wrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: calc(100vh);
|
||||
min-height: 500px;
|
||||
.ace_editor {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.admin-area .sidebar-wrapper .admin-panel {
|
||||
background-color: var(--d-sidebar-admin-background);
|
||||
.sidebar-section-header-text {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Admin::Config::AboutController < Admin::AdminController
|
||||
def index
|
||||
end
|
||||
|
||||
def update
|
||||
end
|
||||
end
|
|
@ -803,9 +803,7 @@ class ApplicationController < ActionController::Base
|
|||
def check_xhr
|
||||
# bypass xhr check on PUT / POST / DELETE provided api key is there, otherwise calling api is annoying
|
||||
return if !request.get? && (is_api? || is_user_api?)
|
||||
unless ((request.format && request.format.json?) || request.xhr?)
|
||||
raise ApplicationController::RenderEmpty.new
|
||||
end
|
||||
raise ApplicationController::RenderEmpty.new if !request.format&.json? && !request.xhr?
|
||||
end
|
||||
|
||||
def apply_cdn_headers
|
||||
|
|
|
@ -98,14 +98,6 @@ Discourse::Application.routes.draw do
|
|||
get "wizard/steps/:id" => "wizard#index"
|
||||
put "wizard/steps/:id" => "steps#update"
|
||||
|
||||
namespace :admin_revamp,
|
||||
path: "admin-revamp",
|
||||
module: "admin",
|
||||
constraints: StaffConstraint.new do
|
||||
get "" => "admin#index"
|
||||
get "config/:area" => "admin#index"
|
||||
end
|
||||
|
||||
namespace :admin, constraints: StaffConstraint.new do
|
||||
get "" => "admin#index"
|
||||
|
||||
|
@ -397,6 +389,10 @@ Discourse::Application.routes.draw do
|
|||
resources :flags, only: %i[index] do
|
||||
put "toggle"
|
||||
end
|
||||
|
||||
resources :about, constraints: AdminConstraint.new, only: %i[index] do
|
||||
collection { put "/" => "about#update" }
|
||||
end
|
||||
end
|
||||
end # admin namespace
|
||||
|
||||
|
|
Loading…
Reference in New Issue