diff --git a/apps/dokploy/components/dashboard/settings/users/add-permissions.tsx b/apps/dokploy/components/dashboard/settings/users/add-permissions.tsx index d3f8af31c..6fff4e80c 100644 --- a/apps/dokploy/components/dashboard/settings/users/add-permissions.tsx +++ b/apps/dokploy/components/dashboard/settings/users/add-permissions.tsx @@ -28,8 +28,12 @@ import { import { Switch } from "@/components/ui/switch"; import { api, type RouterOutputs } from "@/utils/api"; -type Project = RouterOutputs["project"]["all"][number]; -type Environment = Project["environments"][number]; +/** Shape returned by project.allForPermissions (admin only). Used for the permissions UI. */ +type ProjectForPermissions = RouterOutputs["project"]["allForPermissions"][number]; +type EnvironmentForPermissions = ProjectForPermissions["environments"][number]; + +type Project = ProjectForPermissions; +type Environment = EnvironmentForPermissions; export type Services = { appName: string; @@ -173,7 +177,9 @@ interface Props { export const AddUserPermissions = ({ userId }: Props) => { const [isOpen, setIsOpen] = useState(false); - const { data: projects } = api.project.all.useQuery(); + const { data: projects } = api.project.allForPermissions.useQuery(undefined, { + enabled: isOpen, + }); const { data, refetch } = api.user.one.useQuery( { diff --git a/apps/dokploy/server/api/routers/project.ts b/apps/dokploy/server/api/routers/project.ts index 3c9cc23cc..395530c43 100644 --- a/apps/dokploy/server/api/routers/project.ts +++ b/apps/dokploy/server/api/routers/project.ts @@ -37,7 +37,11 @@ import { TRPCError } from "@trpc/server"; import { and, desc, eq, ilike, or, sql } from "drizzle-orm"; import type { AnyPgColumn } from "drizzle-orm/pg-core"; import { z } from "zod"; -import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc"; +import { + adminProcedure, + createTRPCRouter, + protectedProcedure, +} from "@/server/api/trpc"; import { apiCreateProject, apiFindOneProject, @@ -332,6 +336,106 @@ export const projectRouter = createTRPCRouter({ }); }), + /** All projects with full environments and services for the admin permissions UI. Admin only. */ + allForPermissions: adminProcedure.query(async ({ ctx }) => { + return await db.query.projects.findMany({ + where: eq(projects.organizationId, ctx.session.activeOrganizationId), + orderBy: desc(projects.createdAt), + columns: { + projectId: true, + name: true, + }, + with: { + environments: { + columns: { + environmentId: true, + name: true, + isDefault: true, + }, + with: { + applications: { + columns: { + applicationId: true, + appName: true, + name: true, + createdAt: true, + applicationStatus: true, + description: true, + serverId: true, + }, + }, + mariadb: { + columns: { + mariadbId: true, + appName: true, + name: true, + createdAt: true, + applicationStatus: true, + description: true, + serverId: true, + }, + }, + postgres: { + columns: { + postgresId: true, + appName: true, + name: true, + createdAt: true, + applicationStatus: true, + description: true, + serverId: true, + }, + }, + mysql: { + columns: { + mysqlId: true, + appName: true, + name: true, + createdAt: true, + applicationStatus: true, + description: true, + serverId: true, + }, + }, + mongo: { + columns: { + mongoId: true, + appName: true, + name: true, + createdAt: true, + applicationStatus: true, + description: true, + serverId: true, + }, + }, + redis: { + columns: { + redisId: true, + appName: true, + name: true, + createdAt: true, + applicationStatus: true, + description: true, + serverId: true, + }, + }, + compose: { + columns: { + composeId: true, + appName: true, + name: true, + createdAt: true, + composeStatus: true, + description: true, + serverId: true, + }, + }, + }, + }, + }, + }); + }), + search: protectedProcedure .input( z.object({