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..2827a9611 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, isPending: isToggling } = + 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,71 @@ 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/notifications/handle-notifications.tsx b/apps/dokploy/components/dashboard/settings/notifications/handle-notifications.tsx index 0617aa68d..37463fd62 100644 --- a/apps/dokploy/components/dashboard/settings/notifications/handle-notifications.tsx +++ b/apps/dokploy/components/dashboard/settings/notifications/handle-notifications.tsx @@ -54,6 +54,7 @@ const notificationBaseSchema = z.object({ appDeploy: z.boolean().default(false), appBuildError: z.boolean().default(false), databaseBackup: z.boolean().default(false), + dokployBackup: z.boolean().default(false), volumeBackup: z.boolean().default(false), dokployRestart: z.boolean().default(false), dockerCleanup: z.boolean().default(false), @@ -355,6 +356,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: notification.appDeploy, dokployRestart: notification.dokployRestart, databaseBackup: notification.databaseBackup, + dokployBackup: notification.dokployBackup, volumeBackup: notification.volumeBackup, dockerCleanup: notification.dockerCleanup, webhookUrl: notification.slack?.webhookUrl, @@ -369,6 +371,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: notification.appDeploy, dokployRestart: notification.dokployRestart, databaseBackup: notification.databaseBackup, + dokployBackup: notification.dokployBackup, volumeBackup: notification.volumeBackup, botToken: notification.telegram?.botToken, messageThreadId: notification.telegram?.messageThreadId || "", @@ -384,6 +387,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: notification.appDeploy, dokployRestart: notification.dokployRestart, databaseBackup: notification.databaseBackup, + dokployBackup: notification.dokployBackup, volumeBackup: notification.volumeBackup, type: notification.notificationType, webhookUrl: notification.discord?.webhookUrl, @@ -398,6 +402,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: notification.appDeploy, dokployRestart: notification.dokployRestart, databaseBackup: notification.databaseBackup, + dokployBackup: notification.dokployBackup, volumeBackup: notification.volumeBackup, type: notification.notificationType, smtpServer: notification.email?.smtpServer, @@ -416,6 +421,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: notification.appDeploy, dokployRestart: notification.dokployRestart, databaseBackup: notification.databaseBackup, + dokployBackup: notification.dokployBackup, volumeBackup: notification.volumeBackup, type: notification.notificationType, apiKey: notification.resend?.apiKey, @@ -431,6 +437,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: notification.appDeploy, dokployRestart: notification.dokployRestart, databaseBackup: notification.databaseBackup, + dokployBackup: notification.dokployBackup, volumeBackup: notification.volumeBackup, type: notification.notificationType, appToken: notification.gotify?.appToken, @@ -446,6 +453,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: notification.appDeploy, dokployRestart: notification.dokployRestart, databaseBackup: notification.databaseBackup, + dokployBackup: notification.dokployBackup, volumeBackup: notification.volumeBackup, type: notification.notificationType, accessToken: notification.ntfy?.accessToken || "", @@ -462,6 +470,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: notification.appDeploy, dokployRestart: notification.dokployRestart, databaseBackup: notification.databaseBackup, + dokployBackup: notification.dokployBackup, volumeBackup: notification.volumeBackup, type: notification.notificationType, webhookUrl: notification.mattermost?.webhookUrl, @@ -477,6 +486,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: notification.appDeploy, dokployRestart: notification.dokployRestart, databaseBackup: notification.databaseBackup, + dokployBackup: notification.dokployBackup, type: notification.notificationType, webhookUrl: notification.lark?.webhookUrl, name: notification.name, @@ -490,6 +500,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: notification.appDeploy, dokployRestart: notification.dokployRestart, databaseBackup: notification.databaseBackup, + dokployBackup: notification.dokployBackup, volumeBackup: notification.volumeBackup, type: notification.notificationType, webhookUrl: notification.teams?.webhookUrl, @@ -503,6 +514,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: notification.appDeploy, dokployRestart: notification.dokployRestart, databaseBackup: notification.databaseBackup, + dokployBackup: notification.dokployBackup, type: notification.notificationType, endpoint: notification.custom?.endpoint || "", headers: notification.custom?.headers @@ -524,6 +536,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: notification.appDeploy, dokployRestart: notification.dokployRestart, databaseBackup: notification.databaseBackup, + dokployBackup: notification.dokployBackup, volumeBackup: notification.volumeBackup, type: notification.notificationType, userKey: notification.pushover?.userKey, @@ -562,6 +575,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy, dokployRestart, databaseBackup, + dokployBackup, volumeBackup, dockerCleanup, serverThreshold, @@ -573,6 +587,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: appDeploy, dokployRestart: dokployRestart, databaseBackup: databaseBackup, + dokployBackup: dokployBackup, volumeBackup: volumeBackup, webhookUrl: data.webhookUrl, channel: data.channel, @@ -588,6 +603,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: appDeploy, dokployRestart: dokployRestart, databaseBackup: databaseBackup, + dokployBackup: dokployBackup, volumeBackup: volumeBackup, botToken: data.botToken, messageThreadId: data.messageThreadId || "", @@ -604,6 +620,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: appDeploy, dokployRestart: dokployRestart, databaseBackup: databaseBackup, + dokployBackup: dokployBackup, volumeBackup: volumeBackup, webhookUrl: data.webhookUrl, decoration: data.decoration, @@ -619,6 +636,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: appDeploy, dokployRestart: dokployRestart, databaseBackup: databaseBackup, + dokployBackup: dokployBackup, volumeBackup: volumeBackup, smtpServer: data.smtpServer, smtpPort: data.smtpPort, @@ -638,6 +656,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: appDeploy, dokployRestart: dokployRestart, databaseBackup: databaseBackup, + dokployBackup: dokployBackup, volumeBackup: volumeBackup, apiKey: data.apiKey, fromAddress: data.fromAddress, @@ -654,6 +673,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: appDeploy, dokployRestart: dokployRestart, databaseBackup: databaseBackup, + dokployBackup: dokployBackup, volumeBackup: volumeBackup, serverUrl: data.serverUrl, appToken: data.appToken, @@ -670,6 +690,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: appDeploy, dokployRestart: dokployRestart, databaseBackup: databaseBackup, + dokployBackup: dokployBackup, volumeBackup: volumeBackup, serverUrl: data.serverUrl, accessToken: data.accessToken || "", @@ -686,6 +707,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: appDeploy, dokployRestart: dokployRestart, databaseBackup: databaseBackup, + dokployBackup: dokployBackup, volumeBackup: volumeBackup, webhookUrl: data.webhookUrl, channel: data.channel || undefined, @@ -702,6 +724,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: appDeploy, dokployRestart: dokployRestart, databaseBackup: databaseBackup, + dokployBackup: dokployBackup, volumeBackup: volumeBackup, webhookUrl: data.webhookUrl, name: data.name, @@ -716,6 +739,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: appDeploy, dokployRestart: dokployRestart, databaseBackup: databaseBackup, + dokployBackup: dokployBackup, volumeBackup: volumeBackup, webhookUrl: data.webhookUrl, name: data.name, @@ -742,6 +766,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: appDeploy, dokployRestart: dokployRestart, databaseBackup: databaseBackup, + dokployBackup: dokployBackup, volumeBackup: volumeBackup, endpoint: data.endpoint, headers: headersRecord, @@ -761,6 +786,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: appDeploy, dokployRestart: dokployRestart, databaseBackup: databaseBackup, + dokployBackup: dokployBackup, volumeBackup: volumeBackup, userKey: data.userKey, apiToken: data.apiToken, @@ -1856,6 +1882,27 @@ export const HandleNotifications = ({ notificationId }: Props) => { )} /> + ( + +
+ Dokploy Backup + + Trigger the action when a dokploy backup is created. + +
+ + + +
+ )} + /> + { 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,78 @@ 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}) + +
+
+ )} + /> + ))} +
+ +
+ )} + /> + ) : ( +
+ +
+ )}