DEV: Add dedicated admin groups page (#32377)

Previously, clicking "Groups" on the admin dashboard would bring you to the public groups page. Historically, the public and admin actions have been mixed together on that page.

This is a bit of a frustrating experience when working on the admin dashboard, and also prevented us from adding a "Settings" tab for group-related site settings.

This PR adds an "admin groups" page, which is just an exact copy of the public groups index for now. This allows us to add the "Settings" tab, and lets us gradually work un disentangling the public- and admin parts of groups.
This commit is contained in:
Ted Johansson
2025-04-22 11:23:25 +08:00
committed by GitHub
parent 8cfb6d62d4
commit 1d7b08f2e1
13 changed files with 152 additions and 1 deletions
@@ -0,0 +1,27 @@
import Controller from "@ember/controller";
import { action } from "@ember/object";
import discourseDebounce from "discourse/lib/debounce";
import { INPUT_DELAY } from "discourse/lib/environment";
export default class AdminGroupsIndexController extends Controller {
queryParams = ["order", "asc", "filter", "type"];
order = null;
asc = null;
filter = "";
type = null;
groups = null;
@action
onTypeChanged(type) {
this.set("type", type);
}
@action
onFilterChanged(filter) {
discourseDebounce(this, this._debouncedFilter, filter, INPUT_DELAY);
}
_debouncedFilter(filter) {
this.set("filter", filter);
}
}
@@ -0,0 +1,3 @@
import AdminAreaSettingsBaseController from "admin/controllers/admin-area-settings-base";
export default class AdminGroupsSettingsController extends AdminAreaSettingsBaseController {}
@@ -0,0 +1,3 @@
import Controller from "@ember/controller";
export default class AdminGroupsController extends Controller {}
@@ -0,0 +1,26 @@
import DiscourseRoute from "discourse/routes/discourse";
import { i18n } from "discourse-i18n";
export default class AdminGroupsRoute extends DiscourseRoute {
queryParams = {
order: { refreshModel: true, replace: true },
asc: { refreshModel: true, replace: true },
filter: { refreshModel: true },
type: { refreshModel: true, replace: true },
username: { refreshModel: true },
};
titleToken() {
return i18n("admin.config.groups.title");
}
async model(params) {
const groups = await this.store.findAll("group", params);
return { groups };
}
setupController(controller, model) {
super.setupController(controller, model);
controller.set("groups", model.groups);
}
}
@@ -0,0 +1,8 @@
import DiscourseRoute from "discourse/routes/discourse";
import { i18n } from "discourse-i18n";
export default class AdminGroupsSettingsRoute extends DiscourseRoute {
titleToken() {
return i18n("settings");
}
}
@@ -0,0 +1,3 @@
import DiscourseRoute from "discourse/routes/discourse";
export default class AdminGroupsRoute extends DiscourseRoute {}
@@ -219,6 +219,14 @@ export default function () {
}
);
this.route(
"adminGroups",
{ path: "/groups", resetNamespace: true },
function () {
this.route("settings");
}
);
this.route(
"adminConfig",
{ path: "/config", resetNamespace: true },
@@ -0,0 +1,14 @@
import RouteTemplate from "ember-route-template";
import GroupList from "discourse/components/group-list";
export default RouteTemplate(
<template>
<GroupList
@groups={{@model.groups}}
@type={{@controller.type}}
@filter={{@controller.filter}}
@onTypeChanged={{@controller.onTypeChanged}}
@onFilterChanged={{@controller.onFilterChanged}}
/>
</template>
);
@@ -0,0 +1,13 @@
import RouteTemplate from "ember-route-template";
import AdminAreaSettings from "admin/components/admin-area-settings";
export default RouteTemplate(
<template>
<AdminAreaSettings
@categories="groups"
@path="/admin/groups/settings"
@filter={{@controller.filter}}
@adminSettingsFilterChangedCallback={{@controller.adminSettingsFilterChangedCallback}}
/>
</template>
);
@@ -0,0 +1,39 @@
import RouteTemplate from "ember-route-template";
import DBreadcrumbsItem from "discourse/components/d-breadcrumbs-item";
import DPageHeader from "discourse/components/d-page-header";
import NavItem from "discourse/components/nav-item";
import { i18n } from "discourse-i18n";
export default RouteTemplate(
<template>
<DPageHeader
@titleLabel={{i18n "admin.config.groups.title"}}
@descriptionLabel={{i18n "admin.config.groups.header_description"}}
@hideTabs={{@controller.hideTabs}}
>
<:breadcrumbs>
<DBreadcrumbsItem @path="/admin" @label={{i18n "admin_title"}} />
<DBreadcrumbsItem
@path="/admin/groups"
@label={{i18n "admin.config.groups.title"}}
/>
</:breadcrumbs>
<:tabs>
<NavItem
@route="adminGroups.settings"
@label="settings"
class="admin-groups-tabs__settings"
/>
<NavItem
@route="adminGroups.index"
@label="admin.config.groups.title"
class="admin-groups-tabs__index"
/>
</:tabs>
</DPageHeader>
<div class="admin-container admin-config-page__main-area">
{{outlet}}
</div>
</template>
);
@@ -30,7 +30,7 @@ export const ADMIN_NAV_MAP = [
},
{
name: "admin_groups",
route: "groups",
route: "adminGroups",
label: "admin.config.groups.title",
description: "admin.config.groups.header_description",
icon: "user-group",
@@ -3,6 +3,9 @@
class Admin::GroupsController < Admin::StaffController
MAX_AUTO_MEMBERSHIP_DOMAINS_LOOKUP = 10
def index
end
def create
guardian.ensure_can_create_group!
+4
View File
@@ -396,6 +396,10 @@ Discourse::Application.routes.draw do
end
end
resources :groups, only: %i[index], constants: AdminConstraint.new do
collection { get "settings" => "site_settings#index" }
end
get "search/all" => "search#index"
namespace :config, constraints: StaffConstraint.new do