import { groupAccessWindows, groups, userGroupMemberships, users } from "@minecraft-account-manager/database"; import { asc, count, desc } from "drizzle-orm"; import Link from "next/link"; import { AdminModalForm } from "@/components/admin-modal-form"; import { GroupPolicyControl } from "@/components/group-policy-control"; import { db } from "@/lib/database"; import { effectiveGroupMemberCount } from "@/lib/group-management"; import { groupScheduleStatus } from "@/lib/group-schedule"; import { createGroup, setGroupAccess, setGroupAnonymizedNetworkAccess } from "./actions"; const errors: Record = { "invalid-group": "Enter a group name and an optional description of no more than 500 characters.", "duplicate-group": "A group with that name already exists.", "create-failed": "The group could not be created.", "unknown-group": "That group no longer exists.", "invalid-delete": "Confirm the group deletion before continuing.", "protected-group": "The protected default group cannot be deleted.", }; const savedMessages: Record = { deleted: "Group deleted. Its former members now use the default group.", access: "Minecraft access policy updated.", "network-access": "VPN, proxy, and Tor policy updated.", }; export const dynamic = "force-dynamic"; export default async function GroupsPage({ searchParams }: { searchParams: Promise<{ error?: string; saved?: string }> }) { const query = await searchParams; const [allGroups, memberships, [registeredUsers], scheduleCounts] = await Promise.all([ db.select().from(groups).orderBy(desc(groups.isDefault), asc(groups.name)), db.select({ groupId: userGroupMemberships.groupId }).from(userGroupMemberships), db.select({ count: count() }).from(users), db.select({ groupId: groupAccessWindows.groupId, count: count() }) .from(groupAccessWindows) .groupBy(groupAccessWindows.groupId), ]); const scheduleCountByGroup = new Map(scheduleCounts.map((schedule) => [schedule.groupId, Number(schedule.count)])); return (

Admission policy

Access groups

One effective group controls Minecraft and VPN access. Every policy change asks for confirmation before it applies.