From d78e634cb047bdb0932d0cf56b66b3c81e394a0e Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 12 Jul 2025 23:45:06 -0600 Subject: [PATCH] refactor(sidebar): clean up unused types and improve menu structure - Removed legacy comments and unused type definitions from the sidebar component for better clarity. - Added role information to user queries in the user router to enhance permission handling. - Introduced a new schedule access permission in the RBAC schema and updated role permissions accordingly. - Enhanced error messages in role management functions for improved user feedback. --- apps/dokploy/components/layouts/side.tsx | 70 +----------------------- apps/dokploy/server/api/routers/user.ts | 1 + packages/server/src/db/schema/rbac.ts | 8 +++ packages/server/src/services/role.ts | 6 +- 4 files changed, 15 insertions(+), 70 deletions(-) diff --git a/apps/dokploy/components/layouts/side.tsx b/apps/dokploy/components/layouts/side.tsx index 8d180967e..bca25803b 100644 --- a/apps/dokploy/components/layouts/side.tsx +++ b/apps/dokploy/components/layouts/side.tsx @@ -88,7 +88,6 @@ import { Button } from "../ui/button"; import { UpdateServerButton } from "./update-server"; import { UserNav } from "./user-nav"; -// The types of the queries we are going to use type AuthQueryOutput = inferRouterOutputs["user"]["get"]; type SingleNavItem = { @@ -102,10 +101,6 @@ type SingleNavItem = { }) => boolean; }; -// NavItem type -// Consists of a single item or a group of items -// If `isSingle` is true or undefined, the item is a single item -// If `isSingle` is false, the item is a group of items type NavItem = | SingleNavItem | { @@ -119,8 +114,6 @@ type NavItem = }) => boolean; }; -// ExternalLink type -// Represents an external link item (used for the help section) type ExternalLink = { name: string; url: string; @@ -131,18 +124,12 @@ type ExternalLink = { }) => boolean; }; -// Menu type -// Consists of home, settings, and help items type Menu = { home: NavItem[]; settings: NavItem[]; help: ExternalLink[]; }; -// Menu items -// Consists of unfiltered home, settings, and help items -// The items are filtered based on the user's role and permissions -// The `isEnabled` function is called to determine if the item should be displayed const MENU: Menu = { home: [ { @@ -206,62 +193,6 @@ const MENU: Menu = { isEnabled: ({ auth, isCloud }) => !!((auth?.role === "owner" || auth?.canAccessToDocker) && !isCloud), }, - - // Legacy unused menu, adjusted to the new structure - // { - // isSingle: true, - // title: "Projects", - // url: "/dashboard/projects", - // icon: Folder, - // }, - // { - // isSingle: true, - // title: "Monitoring", - // icon: BarChartHorizontalBigIcon, - // url: "/dashboard/settings/monitoring", - // }, - // { - // isSingle: false, - // title: "Settings", - // icon: Settings2, - // items: [ - // { - // title: "Profile", - // url: "/dashboard/settings/profile", - // }, - // { - // title: "Users", - // url: "/dashboard/settings/users", - // }, - // { - // title: "SSH Key", - // url: "/dashboard/settings/ssh-keys", - // }, - // { - // title: "Git", - // url: "/dashboard/settings/git-providers", - // }, - // ], - // }, - // { - // isSingle: false, - // title: "Integrations", - // icon: BlocksIcon, - // items: [ - // { - // title: "S3 Destinations", - // url: "/dashboard/settings/destinations", - // }, - // { - // title: "Registry", - // url: "/dashboard/settings/registry", - // }, - // { - // title: "Notifications", - // url: "/dashboard/settings/notifications", - // }, - // ], - // }, ], settings: [ @@ -505,6 +436,7 @@ function SidebarLogo() { const { state } = useSidebar(); const { data: isCloud } = api.settings.isCloud.useQuery(); const { data: user } = api.user.get.useQuery(); + console.log(user); const { data: session } = authClient.useSession(); const { diff --git a/apps/dokploy/server/api/routers/user.ts b/apps/dokploy/server/api/routers/user.ts index 0c6fe3956..35fcbf87b 100644 --- a/apps/dokploy/server/api/routers/user.ts +++ b/apps/dokploy/server/api/routers/user.ts @@ -102,6 +102,7 @@ export const userRouter = createTRPCRouter({ eq(member.organizationId, ctx.session?.activeOrganizationId || ""), ), with: { + role: true, user: { with: { apiKeys: true, diff --git a/packages/server/src/db/schema/rbac.ts b/packages/server/src/db/schema/rbac.ts index 8ccc7d0b7..cd0d49c8c 100644 --- a/packages/server/src/db/schema/rbac.ts +++ b/packages/server/src/db/schema/rbac.ts @@ -52,6 +52,12 @@ export const PERMISSIONS = { description: "Access API", }, }, + SCHEDULES: { + ACCESS: { + name: "schedules:access", + description: "Access schedules", + }, + }, } as const; export const ownerPermissions = [ @@ -62,6 +68,7 @@ export const ownerPermissions = [ PERMISSIONS.SERVICE.CREATE, PERMISSIONS.SERVICE.DELETE, PERMISSIONS.TRAEFIK.ACCESS, + PERMISSIONS.SCHEDULES.ACCESS, ] as const; export const adminPermissions = [ @@ -74,6 +81,7 @@ export const adminPermissions = [ PERMISSIONS.TRAEFIK.ACCESS, PERMISSIONS.DOCKER.VIEW, PERMISSIONS.API.ACCESS, + PERMISSIONS.SCHEDULES.ACCESS, ] as const; export const memberPermissions = [ diff --git a/packages/server/src/services/role.ts b/packages/server/src/services/role.ts index aefb1be59..943c47f3d 100644 --- a/packages/server/src/services/role.ts +++ b/packages/server/src/services/role.ts @@ -59,7 +59,7 @@ export const removeRoleById = async (roleId: string) => { }); if (members.length > 0) { - throw new Error("Cannot delete role with members"); + throw new Error("Cannot delete role with assigned members"); } await db.delete(role).where(eq(role.roleId, roleId)); @@ -77,6 +77,10 @@ export const updateRoleById = async ( throw new Error("Role not found"); } + if (currentRole.isSystem) { + throw new Error("Cannot update system role"); + } + await db.update(role).set(input).where(eq(role.roleId, roleId)); return currentRole;