feat: app permissions admin page

This commit is contained in:
2025-06-24 19:04:01 +02:00
parent 6d482c784f
commit 65f40d0897
2 changed files with 137 additions and 0 deletions

View File

@ -27,6 +27,7 @@ import VerifyAvatarPage from "./pages/Verify/Avatar";
import VerifyReviewPage from "./pages/Verify/Review";
import AdminUserSessionsPage from "./pages/Admin/UserSessions";
import AdminServiceSessionsPage from "./pages/Admin/ServiceSessions";
import AdminAppPermissionsPage from "./pages/Admin/AppPermissions";
const router = createBrowserRouter([
{
@ -93,6 +94,12 @@ const router = createBrowserRouter([
{ index: true, element: <AdminServiceSessionsPage /> },
],
},
{
path: "app-permissions",
children: [
{ index: true, element: <AdminAppPermissionsPage /> },
],
},
],
},
],

View File

@ -0,0 +1,130 @@
import { useEffect, type FC } from "react";
import Breadcrumbs from "@/components/ui/breadcrumbs";
import { usePermissions } from "@/store/admin/permissions";
interface DisplayPermission {
name: string;
description: string;
}
interface IPermissionGroupProps {
scope: string;
permissions?: DisplayPermission[] | null | undefined;
generatedPermissions?: DisplayPermission[] | null | undefined;
}
const PermissionGroup: FC<IPermissionGroupProps> = ({
scope,
permissions,
generatedPermissions,
}) => {
return (
<div className="border dark:border-gray-800 border-gray-300 p-4 rounded mb-4">
<h2 className="dark:text-gray-300 text-gray-800 text-lg font-semibold">
{scope}
</h2>
{(generatedPermissions?.length ?? 0) > 0 && (
<>
<p className="text-gray-500 text-sm mt-2 mb-4">Generated by Guard</p>
<ol
className={`grid gap-4 gap-y-3 grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 text-gray-800 dark:text-gray-300 font-medium mb-${permissions && permissions.length > 0 ? "6" : "2"}`}
>
{generatedPermissions!.map(({ name, description }) => (
<li className="before:w-2 before:h-2 before:block before:translate-y-2 before:bg-gray-400 dark:before:bg-gray-700 before:rounded-xs flex flex-row items-start gap-2">
<div className="flex flex-col gap-1">
<label>{name}</label>
<p className="text-xs text-gray-400 dark:text-gray-500">
{description}
</p>
</div>
</li>
))}
</ol>
</>
)}
{(permissions?.length ?? 0) > 0 && (
<>
<p className="text-gray-500 text-sm mt-2 mb-4">Manually Created</p>
<ol className="grid gap-4 gap-y-3 grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 text-gray-800 dark:text-gray-300 font-medium">
{permissions!.map(({ name, description }) => (
<li className="before:w-2 before:h-2 before:block before:translate-y-2 before:bg-gray-400 dark:before:bg-gray-700 before:rounded-xs flex flex-row items-start gap-2">
<div className="flex flex-col gap-1">
<label>{name}</label>
<p className="text-xs text-gray-400 dark:text-gray-500">
{description}
</p>
</div>
</li>
))}
</ol>
</>
)}
</div>
);
};
const AdminAppPermissionsPage: FC = () => {
const permissions = usePermissions((s) => s.permissions);
const fetch = usePermissions((s) => s.fetch);
useEffect(() => {
fetch();
}, [fetch]);
return (
<div className="relative flex flex-col items-stretch w-full">
<div className="p-4">
<Breadcrumbs
className="pb-2"
items={[
{
href: "/admin",
label: "Admin",
},
{
label: "App Permissions",
},
]}
/>
</div>
<div className="px-7">
{Object.keys(permissions).map((scope) => (
<PermissionGroup
scope={scope.toUpperCase()}
generatedPermissions={permissions[scope].map((p) => ({
name: p.name
.split("_")
.map((s) => s[0].toUpperCase() + s.slice(1))
.join(" "),
description: p.description,
}))}
/>
))}
{/* <PermissionGroup
scope="Open Chat"
generatedPermissions={["Access Open Chat"].map((name) => ({
name,
description: `You can ${name.toLowerCase()}`,
}))}
permissions={[
"Receive Messages",
"Send Messages",
"View Status",
"Post Status",
"Use Ghost Mode",
"Send Large Media",
].map((name) => ({
name,
description: `You can ${name.toLowerCase()}`,
}))}
/> */}
</div>
</div>
);
};
export default AdminAppPermissionsPage;