Move admin screens (users/groups/roles/oauth2-clients) into a drop-in example plugin; add the ctx.system capability surface
This commit is contained in:
+17
-5
@@ -15,6 +15,18 @@ const scheduling: Plugin = {
|
||||
};
|
||||
// A plugin with a public nav node (reachable by anyone, signed in or not).
|
||||
const portal: Plugin = { apiVersion: "1.0.0", id: "portal", nav: [{ href: "/portal", id: "portal", label: "Portal", public: true }] };
|
||||
// A gated section fragment like the admin plugin's nav: the header carries the permission, so
|
||||
// composeNav drops the whole subtree for a non-holder (the admin screens ship as a drop-in plugin).
|
||||
const adminLike: Plugin = {
|
||||
apiVersion: "1.0.0", id: "admin",
|
||||
nav: [{
|
||||
children: [
|
||||
{ href: "/admin/users", id: "users", label: "Users" },
|
||||
{ href: "/admin/groups", id: "groups", label: "Groups" },
|
||||
],
|
||||
icon: "i-shield", id: "admin", label: "Admin", permission: "admin",
|
||||
}],
|
||||
};
|
||||
|
||||
const labels = (nodes: NavNode[]): string[] => nodes.map((n) => n.label);
|
||||
|
||||
@@ -23,8 +35,8 @@ test("anonymous: brand from menu, Guest user; the gated Dashboard link is hidden
|
||||
assert.equal(chrome.brand.name, DEFAULT_MENU.branding.name);
|
||||
assert.equal(chrome.user.name, "Guest");
|
||||
// Dashboard points at the gated /dashboard — showing it to an anonymous visitor only dead-ends them
|
||||
// at /login, so it's dropped. Scheduling's only child is gated (dropped), admin gated (dropped);
|
||||
// the explicitly public Portal node remains.
|
||||
// at /login, so it's dropped. Scheduling's only child is gated (dropped); the explicitly public
|
||||
// Portal node remains.
|
||||
assert.deepEqual(labels(chrome.nav), ["Portal"]);
|
||||
});
|
||||
|
||||
@@ -45,12 +57,12 @@ test("a permission holder sees the Dashboard link + plugin nav; current path ope
|
||||
assert.equal(chrome.user.name, "ada"); // email local part
|
||||
});
|
||||
|
||||
test("an admin sees the gated admin section; a sub-path marks its base leaf current", () => {
|
||||
const chrome = buildPluginChrome({ currentPath: "/admin/users/new", menu: DEFAULT_MENU, user: { email: "a@b.c", id: "u1", roles: ["admin"] } });
|
||||
test("a gated section (like the admin plugin) shows to a holder; a sub-path marks its base leaf current", () => {
|
||||
const chrome = buildPluginChrome({ currentPath: "/admin/users/new", menu: DEFAULT_MENU, plugins: [adminLike], user: { email: "a@b.c", id: "u1", roles: ["admin"] } });
|
||||
const admin = chrome.nav.find((n) => n.label === "Admin")!;
|
||||
assert.ok(admin); // gated section visible to an admin
|
||||
assert.equal(admin.open, true); // ancestor of the current leaf opened
|
||||
// /admin/users/new is under the Users base (/admin/users) → that leaf is current, not Groups/Roles.
|
||||
// /admin/users/new is under the Users base (/admin/users) → that leaf is current, not Groups.
|
||||
assert.equal(admin.children!.find((c) => c.label === "Users")!.current, true);
|
||||
assert.equal(admin.children!.find((c) => c.label === "Groups")!.current, undefined);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user