feat(mod): tickets+team tabs; retire HK writes for live ACL
Co-authored-by: Cursor <[email protected]>
This commit is contained in:
1 parent
084cca6ea4
commit
75cace41ea
16 files changed
+735
-1002
No files matched your search
@@ -5,16 +5,20 @@ import { prisma } from "@/lib/prisma";
|
||||
import { fetchEmulatorRankSummaries } from "@/lib/services/permission-ranks";
|
||||
import { PermissionsList } from "./permissions-list";
|
||||
|
||||
export default async function PermissionsPage(_props: {
|
||||
export default async function PermissionsPage({
|
||||
searchParams,
|
||||
}: {
|
||||
params: Promise<{ locale: string }>;
|
||||
searchParams?: Promise<{ from?: string }>;
|
||||
}) {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (
|
||||
!canAccess(permissions, PERMS.PERMISSIONS_MANAGE, session.user.rank)
|
||||
) {
|
||||
if (!canAccess(permissions, PERMS.PERMISSIONS_MANAGE, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const sp = (await searchParams) ?? {};
|
||||
const fromHousekeeping = sp.from === "housekeeping";
|
||||
|
||||
const ranks = await fetchEmulatorRankSummaries(prisma);
|
||||
|
||||
// User counts per rank
|
||||
@@ -31,5 +35,10 @@ export default async function PermissionsPage(_props: {
|
||||
userCount: countMap[rank.id] ?? 0,
|
||||
}));
|
||||
|
||||
return <PermissionsList ranks={ranksWithCounts} />;
|
||||
return (
|
||||
<PermissionsList
|
||||
ranks={ranksWithCounts}
|
||||
fromHousekeeping={fromHousekeeping}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -42,6 +42,7 @@ interface RankSummary {
|
||||
|
||||
interface Props {
|
||||
ranks: RankSummary[];
|
||||
fromHousekeeping?: boolean;
|
||||
}
|
||||
|
||||
const RANK_ICONS: Record<number, React.ReactNode> = {
|
||||
@@ -58,7 +59,10 @@ const RANK_COLORS: Record<number, string> = {
|
||||
4: "border-[var(--admin-success-border)] bg-[var(--admin-success-subtle)]",
|
||||
};
|
||||
|
||||
export function PermissionsList({ ranks: initialRanks }: Props) {
|
||||
export function PermissionsList({
|
||||
ranks: initialRanks,
|
||||
fromHousekeeping = false,
|
||||
}: Props) {
|
||||
const { run, isPending } = useServerAction();
|
||||
const [ranks, setRanks] = useState(initialRanks);
|
||||
const [deleteTarget, setDeleteTarget] = useState<RankSummary | null>(null);
|
||||
@@ -98,14 +102,23 @@ export function PermissionsList({ ranks: initialRanks }: Props) {
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{fromHousekeeping ? (
|
||||
<div
|
||||
className="rounded-lg border border-[var(--admin-warning-border)] bg-[var(--admin-warning-subtle)] px-4 py-3 text-sm"
|
||||
role="status"
|
||||
>
|
||||
Housekeeping writes are retired. Edit live ACL ranks and permissions
|
||||
here.
|
||||
</div>
|
||||
) : null}
|
||||
<div
|
||||
className="rounded-lg border border-[var(--admin-info-border)] bg-[var(--admin-info-subtle)] px-4 py-3 text-sm text-[var(--admin-text)]"
|
||||
role="status"
|
||||
>
|
||||
<p className="m-0 font-semibold">Live ACL</p>
|
||||
<p className="m-0 mt-1 text-muted-foreground">
|
||||
Rank ACL here controls real admin access. The Housekeeping table is
|
||||
legacy reference only and does not gate routes.
|
||||
Rank ACL here controls real admin and mod access. The Housekeeping
|
||||
table is a read-only legacy archive with an ACL compare view.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in new issue
Block a user