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})
+
+
+
+ )}
+ />
+ ))}
+
+
+
+ )}
+ />
+ ) : (
+
+
+
+ )}