diff --git a/apps/dokploy/components/dashboard/settings/git/show-git-providers.tsx b/apps/dokploy/components/dashboard/settings/git/show-git-providers.tsx index a96bcf26c..e0806ec85 100644 --- a/apps/dokploy/components/dashboard/settings/git/show-git-providers.tsx +++ b/apps/dokploy/components/dashboard/settings/git/show-git-providers.tsx @@ -5,6 +5,7 @@ import { ImportIcon, Loader2, Trash2, + Users, } from "lucide-react"; import Link from "next/link"; import { toast } from "sonner"; @@ -24,6 +25,13 @@ import { CardHeader, CardTitle, } from "@/components/ui/card"; +import { Switch } from "@/components/ui/switch"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; import { api } from "@/utils/api"; import { useUrl } from "@/utils/hooks/use-url"; import { AddBitbucketProvider } from "./bitbucket/add-bitbucket-provider"; @@ -39,6 +47,8 @@ export const ShowGitProviders = () => { const { data, isPending, refetch } = api.gitProvider.getAll.useQuery(); const { mutateAsync, isPending: isRemoving } = api.gitProvider.remove.useMutation(); + const { mutateAsync: toggleShare } = + api.gitProvider.toggleShare.useMutation(); const url = useUrl(); const getGitlabUrl = ( @@ -154,10 +164,62 @@ export const ShowGitProviders = () => { )} + {!gitProvider.isOwner && ( + + + Shared + + )}
+ {gitProvider.isOwner && ( + + + +
+ + { + await toggleShare({ + gitProviderId: + gitProvider.gitProviderId, + sharedWithOrganization: + checked, + }) + .then(() => { + toast.success( + checked + ? "Provider shared with organization" + : "Provider unshared", + ); + refetch(); + }) + .catch(() => { + toast.error( + "Error updating sharing", + ); + }); + }} + /> +
+
+ + Share with entire organization + +
+
+ )} + {isBitbucket && gitProvider.bitbucket?.appPassword && !gitProvider.bitbucket?.apiToken ? ( @@ -222,62 +284,75 @@ export const ShowGitProviders = () => {
)} - {isGithub && haveGithubRequirements && ( - - )} + {gitProvider.isOwner && ( + <> + {isGithub && haveGithubRequirements && ( + + )} - {isGitlab && ( - - )} + {isGitlab && ( + + )} - {isBitbucket && ( - - )} + {isBitbucket && ( + + )} - {isGitea && ( - - )} + {isGitea && ( + + )} - { - await mutateAsync({ - gitProviderId: gitProvider.gitProviderId, - }) - .then(() => { - toast.success( - "Git Provider deleted successfully", - ); - refetch(); - }) - .catch(() => { - toast.error( - "Error deleting Git Provider", - ); - }); - }} - > - - + { + await mutateAsync({ + gitProviderId: + gitProvider.gitProviderId, + }) + .then(() => { + toast.success( + "Git Provider deleted successfully", + ); + refetch(); + }) + .catch(() => { + toast.error( + "Error deleting Git Provider", + ); + }); + }} + > + + + + )} diff --git a/apps/dokploy/components/dashboard/settings/users/add-permissions.tsx b/apps/dokploy/components/dashboard/settings/users/add-permissions.tsx index fdcf51ad7..5024e457f 100644 --- a/apps/dokploy/components/dashboard/settings/users/add-permissions.tsx +++ b/apps/dokploy/components/dashboard/settings/users/add-permissions.tsx @@ -26,6 +26,7 @@ import { FormMessage, } from "@/components/ui/form"; import { Switch } from "@/components/ui/switch"; +import { EnterpriseFeatureLocked } from "@/components/proprietary/enterprise-feature-gate"; import { api, type RouterOutputs } from "@/utils/api"; /** Shape returned by project.allForPermissions (admin only). Used for the permissions UI. */ @@ -170,6 +171,7 @@ const addPermissions = z.object({ accessedProjects: z.array(z.string()).optional(), accessedEnvironments: z.array(z.string()).optional(), accessedServices: z.array(z.string()).optional(), + accessedGitProviders: z.array(z.string()).optional(), canCreateProjects: z.boolean().optional().default(false), canCreateServices: z.boolean().optional().default(false), canDeleteProjects: z.boolean().optional().default(false), @@ -196,6 +198,15 @@ export const AddUserPermissions = ({ userId, role }: Props) => { const { data: projects } = api.project.allForPermissions.useQuery(undefined, { enabled: isOpen, }); + const { data: haveValidLicense } = + api.licenseKey.haveValidLicenseKey.useQuery(); + + const { data: gitProviders } = api.gitProvider.allForPermissions.useQuery( + undefined, + { + enabled: isOpen && !!haveValidLicense, + }, + ); const { data, refetch } = api.user.one.useQuery( { @@ -214,6 +225,7 @@ export const AddUserPermissions = ({ userId, role }: Props) => { accessedProjects: [], accessedEnvironments: [], accessedServices: [], + accessedGitProviders: [], canDeleteEnvironments: false, canCreateProjects: false, canCreateServices: false, @@ -235,6 +247,7 @@ export const AddUserPermissions = ({ userId, role }: Props) => { accessedProjects: data.accessedProjects || [], accessedEnvironments: data.accessedEnvironments || [], accessedServices: data.accessedServices || [], + accessedGitProviders: data.accessedGitProviders || [], canCreateProjects: data.canCreateProjects, canCreateServices: data.canCreateServices, canDeleteProjects: data.canDeleteProjects, @@ -262,6 +275,7 @@ export const AddUserPermissions = ({ userId, role }: Props) => { accessedProjects: data.accessedProjects || [], accessedEnvironments: data.accessedEnvironments || [], accessedServices: data.accessedServices || [], + accessedGitProviders: data.accessedGitProviders || [], canAccessToDocker: data.canAccessToDocker, canAccessToAPI: data.canAccessToAPI, canAccessToSSHKeys: data.canAccessToSSHKeys, @@ -870,6 +884,81 @@ export const AddUserPermissions = ({ userId, role }: Props) => { )} /> + {haveValidLicense ? ( + ( + +
+ + Git Providers + + + Select the Git Providers that the user can access + +
+ {gitProviders?.length === 0 && ( +

+ No git providers found +

+ )} +
+ {gitProviders?.map((provider) => ( + ( + + + { + if (checked) { + field.onChange([ + ...(field.value || []), + provider.gitProviderId, + ]); + } else { + field.onChange( + field.value?.filter( + (v) => + v !== provider.gitProviderId, + ), + ); + } + }} + /> + +
+ + {provider.name} + + + ({provider.providerType}) + +
+
+ )} + /> + ))} +
+ +
+ )} + /> + ) : ( +
+ +
+ )}