// Built-in Groups admin screen: list / create / delete Keto groups and manage membership. // A group is a Keto subject set `Group:#members`; a member is a user or a nested group (see // parseSubject). Writes go only to Keto (README "stateless"). Keto has no "create object" — a group // exists exactly while it has ≥1 member, so create writes its first-member tuple and delete removes // every member tuple. Pure builders turn tuples + the request URL into view models; `handleAdminGroups` // is the imperative shell app.ts dispatches to — gated admin-only, CSRF-guarded, mapping each action // to a RouteResult. import { ADMIN_GROUPS_BASE, buildConfirmModel, guardedForm, requireAdmin } from "./admin-nav.ts"; import type { FieldConfig } from "./admin-users.ts"; import type { RequestContext, User } from "./context.ts"; import type { KetoClient, RelationQuery, RelationTuple, SubjectSet } from "./keto-client.ts"; import type { KratosAdmin } from "./kratos-admin.ts"; import { parseListQuery } from "./list-query.ts"; import { DEFAULT_MENU, type MenuConfig } from "./menu-config.ts"; import type { NavNode } from "./nav.ts"; import { paginate } from "./paginate.ts"; import type { RouteResult } from "./plugin.ts"; import { buildShellContext } from "./shell-context.ts"; const GROUP_NS = "Group"; const MEMBERS = "members"; const DEFAULT_PAGE_SIZE = 25; const PAGE_SIZES = [25, 50, 100]; // One Keto page of candidate users is fetched for the member pickers (mirrors admin-users). const LIST_FETCH_SIZE = 250; const GROUP_NAME = /^[a-z0-9][a-z0-9_-]*$/; // URL-safe; doubles as the path segment const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; // a Kratos identity id export interface GroupView { memberCount: number; name: string; } // A member's view model: a user (label = email) or a nested group (label = group name). `subject` // is the form value that round-trips it — `user:` or `group:` (see parseSubject). export interface MemberView { kind: "group" | "user"; label: string; subject: string; } // One option in a member