diff --git a/apps/dokploy/components/dashboard/application/deployments/show-deployment.tsx b/apps/dokploy/components/dashboard/application/deployments/show-deployment.tsx index 380b22d93..c67d1ba60 100644 --- a/apps/dokploy/components/dashboard/application/deployments/show-deployment.tsx +++ b/apps/dokploy/components/dashboard/application/deployments/show-deployment.tsx @@ -1,3 +1,4 @@ +import { Badge } from "@/components/ui/badge"; import { Dialog, DialogContent, @@ -5,11 +6,10 @@ import { DialogHeader, DialogTitle, } from "@/components/ui/dialog"; +import { Loader2 } from "lucide-react"; import { useEffect, useRef, useState } from "react"; import { TerminalLine } from "../../docker/logs/terminal-line"; -import { LogLine, parseLogs } from "../../docker/logs/utils"; -import { Badge } from "@/components/ui/badge"; -import { Loader2 } from "lucide-react"; +import { type LogLine, parseLogs } from "../../docker/logs/utils"; interface Props { logPath: string | null; @@ -24,21 +24,20 @@ export const ShowDeployment = ({ logPath, open, onClose, serverId }: Props) => { const [autoScroll, setAutoScroll] = useState(true); const scrollRef = useRef(null); - const scrollToBottom = () => { if (autoScroll && scrollRef.current) { - scrollRef.current.scrollTop = scrollRef.current.scrollHeight; + scrollRef.current.scrollTop = scrollRef.current.scrollHeight; } - }; - + }; + const handleScroll = () => { if (!scrollRef.current) return; - + const { scrollTop, scrollHeight, clientHeight } = scrollRef.current; const isAtBottom = Math.abs(scrollHeight - scrollTop - clientHeight) < 10; setAutoScroll(isAtBottom); - }; - + }; + useEffect(() => { if (!open || !logPath) return; @@ -69,7 +68,6 @@ export const ShowDeployment = ({ logPath, open, onClose, serverId }: Props) => { }; }, [logPath, open]); - useEffect(() => { const logs = parseLogs(data); setFilteredLogs(logs); @@ -77,12 +75,11 @@ export const ShowDeployment = ({ logPath, open, onClose, serverId }: Props) => { useEffect(() => { scrollToBottom(); - + if (autoScroll && scrollRef.current) { - scrollRef.current.scrollTop = scrollRef.current.scrollHeight; + scrollRef.current.scrollTop = scrollRef.current.scrollHeight; } - }, [filteredLogs, autoScroll]); - + }, [filteredLogs, autoScroll]); return ( { Deployment - See all the details of this deployment | {filteredLogs.length} lines + See all the details of this deployment |{" "} + + {filteredLogs.length} lines + -
{ - filteredLogs.length > 0 ? filteredLogs.map((log: LogLine, index: number) => ( - - )) : - ( -
- -
- )} + > + {" "} + {filteredLogs.length > 0 ? ( + filteredLogs.map((log: LogLine, index: number) => ( + + )) + ) : ( +
+ +
+ )}
diff --git a/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-builds.tsx b/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-builds.tsx index bff6c9290..154510c3b 100644 --- a/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-builds.tsx +++ b/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-builds.tsx @@ -26,7 +26,9 @@ export const ShowPreviewBuilds = ({ deployments, serverId }: Props) => { return ( - + diff --git a/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-deployments.tsx b/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-deployments.tsx index 898d412a0..c2d712c3b 100644 --- a/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-deployments.tsx +++ b/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-deployments.tsx @@ -1,237 +1,237 @@ -import React from "react"; +import { DateTooltip } from "@/components/shared/date-tooltip"; +import { DialogAction } from "@/components/shared/dialog-action"; +import { StatusTooltip } from "@/components/shared/status-tooltip"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; import { Separator } from "@/components/ui/separator"; +import { api } from "@/utils/api"; import { - Clock, - GitBranch, - GitPullRequest, - Pencil, - RocketIcon, + Clock, + GitBranch, + GitPullRequest, + Pencil, + RocketIcon, } from "lucide-react"; import Link from "next/link"; -import { ShowModalLogs } from "../../settings/web-server/show-modal-logs"; -import { DialogAction } from "@/components/shared/dialog-action"; -import { api } from "@/utils/api"; -import { ShowPreviewBuilds } from "./show-preview-builds"; -import { DateTooltip } from "@/components/shared/date-tooltip"; +import React from "react"; import { toast } from "sonner"; -import { StatusTooltip } from "@/components/shared/status-tooltip"; +import { ShowModalLogs } from "../../settings/web-server/show-modal-logs"; import { AddPreviewDomain } from "./add-preview-domain"; -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from "@/components/ui/card"; +import { ShowPreviewBuilds } from "./show-preview-builds"; import { ShowPreviewSettings } from "./show-preview-settings"; interface Props { - applicationId: string; + applicationId: string; } export const ShowPreviewDeployments = ({ applicationId }: Props) => { - const { data } = api.application.one.useQuery({ applicationId }); + const { data } = api.application.one.useQuery({ applicationId }); - const { mutateAsync: deletePreviewDeployment, isLoading } = - api.previewDeployment.delete.useMutation(); + const { mutateAsync: deletePreviewDeployment, isLoading } = + api.previewDeployment.delete.useMutation(); - const { data: previewDeployments, refetch: refetchPreviewDeployments } = - api.previewDeployment.all.useQuery( - { applicationId }, - { - enabled: !!applicationId, - } - ); + const { data: previewDeployments, refetch: refetchPreviewDeployments } = + api.previewDeployment.all.useQuery( + { applicationId }, + { + enabled: !!applicationId, + }, + ); - const handleDeletePreviewDeployment = async (previewDeploymentId: string) => { - deletePreviewDeployment({ - previewDeploymentId: previewDeploymentId, - }) - .then(() => { - refetchPreviewDeployments(); - toast.success("Preview deployment deleted"); - }) - .catch((error) => { - toast.error(error.message); - }); - }; + const handleDeletePreviewDeployment = async (previewDeploymentId: string) => { + deletePreviewDeployment({ + previewDeploymentId: previewDeploymentId, + }) + .then(() => { + refetchPreviewDeployments(); + toast.success("Preview deployment deleted"); + }) + .catch((error) => { + toast.error(error.message); + }); + }; - return ( - - -
- Preview Deployments - See all the preview deployments -
- {data?.isPreviewDeploymentsActive && ( - - )} -
- - {data?.isPreviewDeploymentsActive ? ( - <> -
- - Preview deployments are a way to test your application before it - is deployed to production. It will create a new deployment for - each pull request you create. - -
- {!previewDeployments?.length ? ( -
- - - No preview deployments found - -
- ) : ( -
- {previewDeployments.map((previewDeployment) => ( -
-
- - {previewDeployment.pullRequestTitle} - - - - {previewDeployment.previewStatus - ?.replace("running", "Running") - .replace("done", "Done") - .replace("error", "Error") - .replace("idle", "Idle") || "Idle"} - -
+ return ( + + +
+ Preview Deployments + See all the preview deployments +
+ {data?.isPreviewDeploymentsActive && ( + + )} +
+ + {data?.isPreviewDeploymentsActive ? ( + <> +
+ + Preview deployments are a way to test your application before it + is deployed to production. It will create a new deployment for + each pull request you create. + +
+ {!previewDeployments?.length ? ( +
+ + + No preview deployments found + +
+ ) : ( +
+ {previewDeployments.map((previewDeployment) => ( +
+
+ + {previewDeployment.pullRequestTitle} + + + + {previewDeployment.previewStatus + ?.replace("running", "Running") + .replace("done", "Done") + .replace("error", "Error") + .replace("idle", "Idle") || "Idle"} + +
-
-
- - {previewDeployment.domain?.host} - +
+
+ + {previewDeployment.domain?.host} + - - - -
+ + + +
-
-
- - Branch: - - {previewDeployment.branch} - -
-
- - Deployed: - - - -
-
+
+
+ + Branch: + + {previewDeployment.branch} + +
+
+ + Deployed: + + + +
+
- + -
-

- Pull Request -

-
- - - {previewDeployment.pullRequestTitle} - -
-
-
+
+

+ Pull Request +

+
+ + + {previewDeployment.pullRequestTitle} + +
+
+
-
-
- - - +
+
+ + + - + - - handleDeletePreviewDeployment( - previewDeployment.previewDeploymentId - ) - } - > - - -
-
-
- ))} -
- )} - - ) : ( -
- - - Preview deployments are disabled for this application, please - enable it - - -
- )} - - - ); + + handleDeletePreviewDeployment( + previewDeployment.previewDeploymentId, + ) + } + > + + +
+
+
+ ))} +
+ )} + + ) : ( +
+ + + Preview deployments are disabled for this application, please + enable it + + +
+ )} +
+
+ ); }; diff --git a/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-settings.tsx b/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-settings.tsx index 6e56bbdd0..0e4231eb4 100644 --- a/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-settings.tsx +++ b/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-settings.tsx @@ -1,5 +1,3 @@ -import { api } from "@/utils/api"; -import { useEffect, useState } from "react"; import { Button } from "@/components/ui/button"; import { Dialog, @@ -20,12 +18,7 @@ import { FormMessage, } from "@/components/ui/form"; import { Input, NumberInput } from "@/components/ui/input"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { useForm } from "react-hook-form"; -import { z } from "zod"; import { Secrets } from "@/components/ui/secrets"; -import { toast } from "sonner"; -import { Switch } from "@/components/ui/switch"; import { Select, SelectContent, @@ -33,6 +26,13 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; +import { Switch } from "@/components/ui/switch"; +import { api } from "@/utils/api"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; +import { toast } from "sonner"; +import { z } from "zod"; const schema = z.object({ env: z.string(), diff --git a/apps/dokploy/components/dashboard/compose/delete-compose.tsx b/apps/dokploy/components/dashboard/compose/delete-compose.tsx index 3bdcc6bfa..f263bc7fa 100644 --- a/apps/dokploy/components/dashboard/compose/delete-compose.tsx +++ b/apps/dokploy/components/dashboard/compose/delete-compose.tsx @@ -1,5 +1,6 @@ import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; +import { Checkbox } from "@/components/ui/checkbox"; import { Dialog, DialogContent, @@ -12,6 +13,7 @@ import { import { Form, FormControl, + FormDescription, FormField, FormItem, FormLabel, @@ -32,6 +34,7 @@ const deleteComposeSchema = z.object({ projectName: z.string().min(1, { message: "Compose name is required", }), + deleteVolumes: z.boolean(), }); type DeleteCompose = z.infer; @@ -51,6 +54,7 @@ export const DeleteCompose = ({ composeId }: Props) => { const form = useForm({ defaultValues: { projectName: "", + deleteVolumes: false, }, resolver: zodResolver(deleteComposeSchema), }); @@ -58,7 +62,8 @@ export const DeleteCompose = ({ composeId }: Props) => { const onSubmit = async (formData: DeleteCompose) => { const expectedName = `${data?.name}/${data?.appName}`; if (formData.projectName === expectedName) { - await mutateAsync({ composeId }) + const { deleteVolumes } = formData; + await mutateAsync({ composeId, deleteVolumes }) .then((result) => { push(`/dashboard/project/${result?.projectId}`); toast.success("Compose deleted successfully"); @@ -133,6 +138,27 @@ export const DeleteCompose = ({ composeId }: Props) => { )} /> + ( + +
+ + + + + + Delete volumes associated with this compose + +
+ +
+ )} + /> diff --git a/apps/dokploy/components/dashboard/compose/deployments/show-deployment-compose.tsx b/apps/dokploy/components/dashboard/compose/deployments/show-deployment-compose.tsx index 4a45fb204..d683d4ab4 100644 --- a/apps/dokploy/components/dashboard/compose/deployments/show-deployment-compose.tsx +++ b/apps/dokploy/components/dashboard/compose/deployments/show-deployment-compose.tsx @@ -1,3 +1,4 @@ +import { Badge } from "@/components/ui/badge"; import { Dialog, DialogContent, @@ -5,12 +6,10 @@ import { DialogHeader, DialogTitle, } from "@/components/ui/dialog"; +import { Loader2 } from "lucide-react"; import { useEffect, useRef, useState } from "react"; import { TerminalLine } from "../../docker/logs/terminal-line"; -import { LogLine, parseLogs } from "../../docker/logs/utils"; -import { Badge } from "@/components/ui/badge"; -import { Loader2 } from "lucide-react"; - +import { type LogLine, parseLogs } from "../../docker/logs/utils"; interface Props { logPath: string | null; @@ -32,19 +31,18 @@ export const ShowDeploymentCompose = ({ const scrollToBottom = () => { if (autoScroll && scrollRef.current) { - scrollRef.current.scrollTop = scrollRef.current.scrollHeight; + scrollRef.current.scrollTop = scrollRef.current.scrollHeight; } - }; - + }; + const handleScroll = () => { if (!scrollRef.current) return; - + const { scrollTop, scrollHeight, clientHeight } = scrollRef.current; const isAtBottom = Math.abs(scrollHeight - scrollTop - clientHeight) < 10; setAutoScroll(isAtBottom); - }; - - + }; + useEffect(() => { if (!open || !logPath) return; @@ -76,7 +74,6 @@ export const ShowDeploymentCompose = ({ }; }, [logPath, open]); - useEffect(() => { const logs = parseLogs(data); setFilteredLogs(logs); @@ -84,11 +81,11 @@ export const ShowDeploymentCompose = ({ useEffect(() => { scrollToBottom(); - + if (autoScroll && scrollRef.current) { - scrollRef.current.scrollTop = scrollRef.current.scrollHeight; + scrollRef.current.scrollTop = scrollRef.current.scrollHeight; } - }, [filteredLogs, autoScroll]); + }, [filteredLogs, autoScroll]); return ( Deployment - See all the details of this deployment | {filteredLogs.length} lines + See all the details of this deployment |{" "} + + {filteredLogs.length} lines +
-
- - - { - filteredLogs.length > 0 ? filteredLogs.map((log: LogLine, index: number) => ( - - )) : - ( + {filteredLogs.length > 0 ? ( + filteredLogs.map((log: LogLine, index: number) => ( + + )) + ) : (
- ) - } + )}
diff --git a/apps/dokploy/components/dashboard/compose/general/deploy-compose.tsx b/apps/dokploy/components/dashboard/compose/general/deploy-compose.tsx index c02a78028..25b59cc73 100644 --- a/apps/dokploy/components/dashboard/compose/general/deploy-compose.tsx +++ b/apps/dokploy/components/dashboard/compose/general/deploy-compose.tsx @@ -53,7 +53,7 @@ export const DeployCompose = ({ composeId }: Props) => { }) .then(async () => { router.push( - `/dashboard/project/${data?.project.projectId}/services/compose/${composeId}?tab=deployments` + `/dashboard/project/${data?.project.projectId}/services/compose/${composeId}?tab=deployments`, ); }) .catch(() => { diff --git a/apps/dokploy/components/dashboard/docker/terminal/docker-terminal-modal.tsx b/apps/dokploy/components/dashboard/docker/terminal/docker-terminal-modal.tsx index e7301b0aa..90aa2b406 100644 --- a/apps/dokploy/components/dashboard/docker/terminal/docker-terminal-modal.tsx +++ b/apps/dokploy/components/dashboard/docker/terminal/docker-terminal-modal.tsx @@ -59,7 +59,7 @@ export const DockerTerminalModal = ({ {children} - event.preventDefault()} > diff --git a/apps/dokploy/components/dashboard/projects/show.tsx b/apps/dokploy/components/dashboard/projects/show.tsx index d05bbba2c..d4d9ac553 100644 --- a/apps/dokploy/components/dashboard/projects/show.tsx +++ b/apps/dokploy/components/dashboard/projects/show.tsx @@ -1,35 +1,35 @@ import { DateTooltip } from "@/components/shared/date-tooltip"; import { - AlertDialog, - AlertDialogAction, - AlertDialogCancel, - AlertDialogContent, - AlertDialogDescription, - AlertDialogFooter, - AlertDialogHeader, - AlertDialogTitle, - AlertDialogTrigger, + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, } from "@/components/ui/alert-dialog"; import { Button } from "@/components/ui/button"; import { Card, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuGroup, - DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuSeparator, - DropdownMenuTrigger, + DropdownMenu, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { api } from "@/utils/api"; import { - AlertTriangle, - BookIcon, - ExternalLink, - ExternalLinkIcon, - FolderInput, - MoreHorizontalIcon, - TrashIcon, + AlertTriangle, + BookIcon, + ExternalLink, + ExternalLinkIcon, + FolderInput, + MoreHorizontalIcon, + TrashIcon, } from "lucide-react"; import Link from "next/link"; import { Fragment } from "react"; @@ -38,257 +38,257 @@ import { ProjectEnviroment } from "./project-enviroment"; import { UpdateProject } from "./update"; export const ShowProjects = () => { - const utils = api.useUtils(); - const { data } = api.project.all.useQuery(); - const { data: auth } = api.auth.get.useQuery(); - const { data: user } = api.user.byAuthId.useQuery( - { - authId: auth?.id || "", - }, - { - enabled: !!auth?.id && auth?.rol === "user", - } - ); - const { mutateAsync } = api.project.remove.useMutation(); + const utils = api.useUtils(); + const { data } = api.project.all.useQuery(); + const { data: auth } = api.auth.get.useQuery(); + const { data: user } = api.user.byAuthId.useQuery( + { + authId: auth?.id || "", + }, + { + enabled: !!auth?.id && auth?.rol === "user", + }, + ); + const { mutateAsync } = api.project.remove.useMutation(); - return ( - <> - {data?.length === 0 && ( -
- - - No projects added yet. Click on Create project. - -
- )} -
- {data?.map((project) => { - const emptyServices = - project?.mariadb.length === 0 && - project?.mongo.length === 0 && - project?.mysql.length === 0 && - project?.postgres.length === 0 && - project?.redis.length === 0 && - project?.applications.length === 0 && - project?.compose.length === 0; + return ( + <> + {data?.length === 0 && ( +
+ + + No projects added yet. Click on Create project. + +
+ )} +
+ {data?.map((project) => { + const emptyServices = + project?.mariadb.length === 0 && + project?.mongo.length === 0 && + project?.mysql.length === 0 && + project?.postgres.length === 0 && + project?.redis.length === 0 && + project?.applications.length === 0 && + project?.compose.length === 0; - const totalServices = - project?.mariadb.length + - project?.mongo.length + - project?.mysql.length + - project?.postgres.length + - project?.redis.length + - project?.applications.length + - project?.compose.length; + const totalServices = + project?.mariadb.length + + project?.mongo.length + + project?.mysql.length + + project?.postgres.length + + project?.redis.length + + project?.applications.length + + project?.compose.length; - const flattedDomains = [ - ...project.applications.flatMap((a) => a.domains), - ...project.compose.flatMap((a) => a.domains), - ]; + const flattedDomains = [ + ...project.applications.flatMap((a) => a.domains), + ...project.compose.flatMap((a) => a.domains), + ]; - const renderDomainsDropdown = ( - item: typeof project.compose | typeof project.applications - ) => - item[0] ? ( - - - {"applicationId" in item[0] ? "Applications" : "Compose"} - - {item.map((a) => ( - - - - - {a.name} - - - {a.domains.map((domain) => ( - - - {domain.host} - - - - ))} - - - ))} - - ) : null; + const renderDomainsDropdown = ( + item: typeof project.compose | typeof project.applications, + ) => + item[0] ? ( + + + {"applicationId" in item[0] ? "Applications" : "Compose"} + + {item.map((a) => ( + + + + + {a.name} + + + {a.domains.map((domain) => ( + + + {domain.host} + + + + ))} + + + ))} + + ) : null; - return ( -
- - - {flattedDomains.length > 1 ? ( - - - - - e.stopPropagation()} - > - {renderDomainsDropdown(project.applications)} - {renderDomainsDropdown(project.compose)} - - - ) : flattedDomains[0] ? ( - - ) : null} + return ( +
+ + + {flattedDomains.length > 1 ? ( + + + + + e.stopPropagation()} + > + {renderDomainsDropdown(project.applications)} + {renderDomainsDropdown(project.compose)} + + + ) : flattedDomains[0] ? ( + + ) : null} - - - -
- - - {project.name} - -
+ + + +
+ + + {project.name} + +
- - {project.description} - -
-
- - - - - - - Actions - -
e.stopPropagation()}> - -
-
e.stopPropagation()}> - -
+ + {project.description} + + +
+ + + + + + + Actions + +
e.stopPropagation()}> + +
+
e.stopPropagation()}> + +
-
e.stopPropagation()}> - {(auth?.rol === "admin" || - user?.canDeleteProjects) && ( - - - e.preventDefault()} - > - - Delete - - - - - - Are you sure to delete this project? - - {!emptyServices ? ( -
- - - You have active services, please - delete them first - -
- ) : ( - - This action cannot be undone - - )} -
- - - Cancel - - { - await mutateAsync({ - projectId: project.projectId, - }) - .then(() => { - toast.success( - "Project delete succesfully" - ); - }) - .catch(() => { - toast.error( - "Error to delete this project" - ); - }) - .finally(() => { - utils.project.all.invalidate(); - }); - }} - > - Delete - - -
-
- )} -
-
-
-
- - - -
- - Created - - - {totalServices}{" "} - {totalServices === 1 ? "service" : "services"} - -
-
- - -
- ); - })} -
- - ); +
e.stopPropagation()}> + {(auth?.rol === "admin" || + user?.canDeleteProjects) && ( + + + e.preventDefault()} + > + + Delete + + + + + + Are you sure to delete this project? + + {!emptyServices ? ( +
+ + + You have active services, please + delete them first + +
+ ) : ( + + This action cannot be undone + + )} +
+ + + Cancel + + { + await mutateAsync({ + projectId: project.projectId, + }) + .then(() => { + toast.success( + "Project delete succesfully", + ); + }) + .catch(() => { + toast.error( + "Error to delete this project", + ); + }) + .finally(() => { + utils.project.all.invalidate(); + }); + }} + > + Delete + + +
+
+ )} +
+ + +
+ + + +
+ + Created + + + {totalServices}{" "} + {totalServices === 1 ? "service" : "services"} + +
+
+ + +
+ ); + })} +
+ + ); }; diff --git a/apps/dokploy/components/dashboard/search-command.tsx b/apps/dokploy/components/dashboard/search-command.tsx index 8afea6720..4d3c75f98 100644 --- a/apps/dokploy/components/dashboard/search-command.tsx +++ b/apps/dokploy/components/dashboard/search-command.tsx @@ -1,189 +1,189 @@ "use client"; -import React from "react"; import { - Command, - CommandEmpty, - CommandList, - CommandGroup, - CommandInput, - CommandItem, - CommandDialog, - CommandSeparator, + MariadbIcon, + MongodbIcon, + MysqlIcon, + PostgresqlIcon, + RedisIcon, +} from "@/components/icons/data-tools-icons"; +import { Badge } from "@/components/ui/badge"; +import { + Command, + CommandDialog, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList, + CommandSeparator, } from "@/components/ui/command"; -import { useRouter } from "next/router"; import { - extractServices, - type Services, + type Services, + extractServices, } from "@/pages/dashboard/project/[projectId]"; +import { api } from "@/utils/api"; import type { findProjectById } from "@dokploy/server/services/project"; import { BookIcon, CircuitBoard, GlobeIcon } from "lucide-react"; -import { - MariadbIcon, - MongodbIcon, - MysqlIcon, - PostgresqlIcon, - RedisIcon, -} from "@/components/icons/data-tools-icons"; -import { api } from "@/utils/api"; -import { Badge } from "@/components/ui/badge"; +import { useRouter } from "next/router"; +import React from "react"; import { StatusTooltip } from "../shared/status-tooltip"; type Project = Awaited>; export const SearchCommand = () => { - const router = useRouter(); - const [open, setOpen] = React.useState(false); - const [search, setSearch] = React.useState(""); + const router = useRouter(); + const [open, setOpen] = React.useState(false); + const [search, setSearch] = React.useState(""); - const { data } = api.project.all.useQuery(); - const { data: isCloud, isLoading } = api.settings.isCloud.useQuery(); + const { data } = api.project.all.useQuery(); + const { data: isCloud, isLoading } = api.settings.isCloud.useQuery(); - React.useEffect(() => { - const down = (e: KeyboardEvent) => { - if (e.key === "j" && (e.metaKey || e.ctrlKey)) { - e.preventDefault(); - setOpen((open) => !open); - } - }; + React.useEffect(() => { + const down = (e: KeyboardEvent) => { + if (e.key === "j" && (e.metaKey || e.ctrlKey)) { + e.preventDefault(); + setOpen((open) => !open); + } + }; - document.addEventListener("keydown", down); - return () => document.removeEventListener("keydown", down); - }, []); + document.addEventListener("keydown", down); + return () => document.removeEventListener("keydown", down); + }, []); - return ( -
- - - - - No projects added yet. Click on Create project. - - - - {data?.map((project) => ( - { - router.push(`/dashboard/project/${project.projectId}`); - setOpen(false); - }} - > - - {project.name} - - ))} - - - - - - {data?.map((project) => { - const applications: Services[] = extractServices(project); - return applications.map((application) => ( - { - router.push( - `/dashboard/project/${project.projectId}/services/${application.type}/${application.id}` - ); - setOpen(false); - }} - > - {application.type === "postgres" && ( - - )} - {application.type === "redis" && ( - - )} - {application.type === "mariadb" && ( - - )} - {application.type === "mongo" && ( - - )} - {application.type === "mysql" && ( - - )} - {application.type === "application" && ( - - )} - {application.type === "compose" && ( - - )} - - {project.name} / {application.name}{" "} -
{application.id}
-
-
- -
-
- )); - })} -
-
- - -
-
-
- ); + return ( +
+ + + + + No projects added yet. Click on Create project. + + + + {data?.map((project) => ( + { + router.push(`/dashboard/project/${project.projectId}`); + setOpen(false); + }} + > + + {project.name} + + ))} + + + + + + {data?.map((project) => { + const applications: Services[] = extractServices(project); + return applications.map((application) => ( + { + router.push( + `/dashboard/project/${project.projectId}/services/${application.type}/${application.id}`, + ); + setOpen(false); + }} + > + {application.type === "postgres" && ( + + )} + {application.type === "redis" && ( + + )} + {application.type === "mariadb" && ( + + )} + {application.type === "mongo" && ( + + )} + {application.type === "mysql" && ( + + )} + {application.type === "application" && ( + + )} + {application.type === "compose" && ( + + )} + + {project.name} / {application.name}{" "} +
{application.id}
+
+
+ +
+
+ )); + })} +
+
+ + +
+
+
+ ); }; diff --git a/apps/dokploy/components/dashboard/settings/notifications/delete-notification.tsx b/apps/dokploy/components/dashboard/settings/notifications/delete-notification.tsx index 4bb197b29..02c95d8b3 100644 --- a/apps/dokploy/components/dashboard/settings/notifications/delete-notification.tsx +++ b/apps/dokploy/components/dashboard/settings/notifications/delete-notification.tsx @@ -24,12 +24,12 @@ export const DeleteNotification = ({ notificationId }: Props) => { return ( - diff --git a/apps/dokploy/components/dashboard/settings/notifications/show-notifications.tsx b/apps/dokploy/components/dashboard/settings/notifications/show-notifications.tsx index 2b5d02e0e..8a45bbf31 100644 --- a/apps/dokploy/components/dashboard/settings/notifications/show-notifications.tsx +++ b/apps/dokploy/components/dashboard/settings/notifications/show-notifications.tsx @@ -40,58 +40,60 @@ export const ShowNotifications = () => { ) : (
-
- {data?.map((notification, index) => ( -
-
- {notification.notificationType === "slack" && ( -
- -
- )} - {notification.notificationType === "telegram" && ( -
- -
- )} - {notification.notificationType === "discord" && ( -
- -
- )} - {notification.notificationType === "email" && ( -
- -
- )} -
- - {notification.name} - - - {notification.notificationType?.[0]?.toUpperCase() + notification.notificationType?.slice(1)} notification - -
-
-
- - -
+
+ {data?.map((notification, index) => ( +
+
+ {notification.notificationType === "slack" && ( +
+ +
+ )} + {notification.notificationType === "telegram" && ( +
+ +
+ )} + {notification.notificationType === "discord" && ( +
+ +
+ )} + {notification.notificationType === "email" && ( +
+ +
+ )} +
+ + {notification.name} + + + {notification.notificationType?.[0]?.toUpperCase() + + notification.notificationType?.slice(1)}{" "} + notification + +
+
+
+ + +
+
+ ))} +
+ +
+
- ))} -
- -
-
-
)} diff --git a/apps/dokploy/components/dashboard/settings/notifications/update-notification.tsx b/apps/dokploy/components/dashboard/settings/notifications/update-notification.tsx index 5c594dc49..41306385d 100644 --- a/apps/dokploy/components/dashboard/settings/notifications/update-notification.tsx +++ b/apps/dokploy/components/dashboard/settings/notifications/update-notification.tsx @@ -218,9 +218,11 @@ export const UpdateNotification = ({ notificationId }: Props) => { return ( - diff --git a/apps/dokploy/components/dashboard/settings/profile/profile-form.tsx b/apps/dokploy/components/dashboard/settings/profile/profile-form.tsx index 1141397f9..191c1936d 100644 --- a/apps/dokploy/components/dashboard/settings/profile/profile-form.tsx +++ b/apps/dokploy/components/dashboard/settings/profile/profile-form.tsx @@ -1,3 +1,4 @@ +import { AlertBlock } from "@/components/shared/alert-block"; import { Button } from "@/components/ui/button"; import { Card, @@ -26,7 +27,6 @@ import { toast } from "sonner"; import { z } from "zod"; import { Disable2FA } from "./disable-2fa"; import { Enable2FA } from "./enable-2fa"; -import { AlertBlock } from "@/components/shared/alert-block"; const profileSchema = z.object({ email: z.string(), diff --git a/apps/dokploy/components/dashboard/settings/profile/remove-self-account.tsx b/apps/dokploy/components/dashboard/settings/profile/remove-self-account.tsx index f4f4680bc..3fc554522 100644 --- a/apps/dokploy/components/dashboard/settings/profile/remove-self-account.tsx +++ b/apps/dokploy/components/dashboard/settings/profile/remove-self-account.tsx @@ -1,3 +1,5 @@ +import { AlertBlock } from "@/components/shared/alert-block"; +import { DialogAction } from "@/components/shared/dialog-action"; import { Button } from "@/components/ui/button"; import { Card, @@ -18,13 +20,11 @@ import { Input } from "@/components/ui/input"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; import { useTranslation } from "next-i18next"; +import { useRouter } from "next/router"; import { useEffect } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { z } from "zod"; -import { DialogAction } from "@/components/shared/dialog-action"; -import { AlertBlock } from "@/components/shared/alert-block"; -import { useRouter } from "next/router"; const profileSchema = z.object({ password: z.string().min(1, { diff --git a/apps/dokploy/components/dashboard/settings/servers/actions/show-traefik-actions.tsx b/apps/dokploy/components/dashboard/settings/servers/actions/show-traefik-actions.tsx index 546069c5b..72854f930 100644 --- a/apps/dokploy/components/dashboard/settings/servers/actions/show-traefik-actions.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/actions/show-traefik-actions.tsx @@ -25,8 +25,8 @@ import { toast } from "sonner"; import { cn } from "@/lib/utils"; import { useTranslation } from "next-i18next"; import { EditTraefikEnv } from "../../web-server/edit-traefik-env"; -import { ShowModalLogs } from "../../web-server/show-modal-logs"; import { ManageTraefikPorts } from "../../web-server/manage-traefik-ports"; +import { ShowModalLogs } from "../../web-server/show-modal-logs"; interface Props { serverId?: string; diff --git a/apps/dokploy/components/dashboard/settings/servers/edit-script.tsx b/apps/dokploy/components/dashboard/settings/servers/edit-script.tsx index faaecb1fa..0a22220ed 100644 --- a/apps/dokploy/components/dashboard/settings/servers/edit-script.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/edit-script.tsx @@ -108,7 +108,8 @@ export const EditScript = ({ serverId }: Props) => { - We recommend not modifying this script unless you know what you are doing. + We recommend not modifying this script unless you know what you are + doing.
diff --git a/apps/dokploy/components/dashboard/settings/servers/setup-server.tsx b/apps/dokploy/components/dashboard/settings/servers/setup-server.tsx index 7c1814591..252ca16c5 100644 --- a/apps/dokploy/components/dashboard/settings/servers/setup-server.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/setup-server.tsx @@ -34,8 +34,8 @@ import { toast } from "sonner"; import { ShowDeployment } from "../../application/deployments/show-deployment"; import { EditScript } from "./edit-script"; import { GPUSupport } from "./gpu-support"; -import { ValidateServer } from "./validate-server"; import { SecurityAudit } from "./security-audit"; +import { ValidateServer } from "./validate-server"; interface Props { serverId: string; diff --git a/apps/dokploy/components/dashboard/settings/servers/show-servers.tsx b/apps/dokploy/components/dashboard/settings/servers/show-servers.tsx index d476fb15f..d45a3b77d 100644 --- a/apps/dokploy/components/dashboard/settings/servers/show-servers.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/show-servers.tsx @@ -23,17 +23,17 @@ import { api } from "@/utils/api"; import { format } from "date-fns"; import { KeyIcon, MoreHorizontal, ServerIcon } from "lucide-react"; import Link from "next/link"; +import { useRouter } from "next/router"; import { toast } from "sonner"; import { TerminalModal } from "../web-server/terminal-modal"; import { ShowServerActions } from "./actions/show-server-actions"; import { AddServer } from "./add-server"; import { SetupServer } from "./setup-server"; import { ShowDockerContainersModal } from "./show-docker-containers-modal"; +import { ShowSwarmOverviewModal } from "./show-swarm-overview-modal"; import { ShowTraefikFileSystemModal } from "./show-traefik-file-system-modal"; import { UpdateServer } from "./update-server"; -import { useRouter } from "next/router"; import { WelcomeSuscription } from "./welcome-stripe/welcome-suscription"; -import { ShowSwarmOverviewModal } from "./show-swarm-overview-modal"; export const ShowServers = () => { const router = useRouter(); diff --git a/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/create-ssh-key.tsx b/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/create-ssh-key.tsx index 740f79607..37f8e0176 100644 --- a/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/create-ssh-key.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/create-ssh-key.tsx @@ -1,12 +1,12 @@ +import { CodeEditor } from "@/components/shared/code-editor"; import { Card, CardContent } from "@/components/ui/card"; import { api } from "@/utils/api"; -import { ExternalLinkIcon, Loader2 } from "lucide-react"; import copy from "copy-to-clipboard"; +import { ExternalLinkIcon, Loader2 } from "lucide-react"; import { CopyIcon } from "lucide-react"; +import Link from "next/link"; import { useEffect, useRef } from "react"; import { toast } from "sonner"; -import { CodeEditor } from "@/components/shared/code-editor"; -import Link from "next/link"; export const CreateSSHKey = () => { const { data, refetch } = api.sshKey.all.useQuery(); diff --git a/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/setup.tsx b/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/setup.tsx index 39179de83..be7a8e48b 100644 --- a/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/setup.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/setup.tsx @@ -5,26 +5,26 @@ import { StatusTooltip } from "@/components/shared/status-tooltip"; import { Button } from "@/components/ui/button"; import { Card, + CardContent, + CardDescription, CardHeader, CardTitle, - CardDescription, - CardContent, } from "@/components/ui/card"; -import { RocketIcon } from "lucide-react"; -import { toast } from "sonner"; -import { EditScript } from "../edit-script"; -import { api } from "@/utils/api"; -import { useState } from "react"; import { Label } from "@/components/ui/label"; import { Select, - SelectTrigger, - SelectValue, SelectContent, SelectGroup, SelectItem, SelectLabel, + SelectTrigger, + SelectValue, } from "@/components/ui/select"; +import { api } from "@/utils/api"; +import { RocketIcon } from "lucide-react"; +import { useState } from "react"; +import { toast } from "sonner"; +import { EditScript } from "../edit-script"; export const Setup = () => { const { data: servers } = api.server.all.useQuery(); diff --git a/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/verify.tsx b/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/verify.tsx index 3d6cfa7df..fe8c36c2c 100644 --- a/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/verify.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/verify.tsx @@ -1,27 +1,27 @@ import { Button } from "@/components/ui/button"; import { Card, + CardContent, + CardDescription, CardHeader, CardTitle, - CardDescription, - CardContent, } from "@/components/ui/card"; -import { Loader2, PcCase, RefreshCw } from "lucide-react"; +import { Label } from "@/components/ui/label"; import { api } from "@/utils/api"; +import { Loader2, PcCase, RefreshCw } from "lucide-react"; import { useState } from "react"; -import { Label } from "@/components/ui/label"; +import { AlertBlock } from "@/components/shared/alert-block"; import { Select, - SelectTrigger, - SelectValue, SelectContent, SelectGroup, SelectItem, SelectLabel, + SelectTrigger, + SelectValue, } from "@/components/ui/select"; import { StatusRow } from "../gpu-support"; -import { AlertBlock } from "@/components/shared/alert-block"; export const Verify = () => { const { data: servers } = api.server.all.useQuery(); diff --git a/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/welcome-suscription.tsx b/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/welcome-suscription.tsx index e9de05232..bab930478 100644 --- a/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/welcome-suscription.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/welcome-suscription.tsx @@ -1,3 +1,5 @@ +import { GithubIcon } from "@/components/icons/data-tools-icons"; +import { AlertBlock } from "@/components/shared/alert-block"; import { Button } from "@/components/ui/button"; import { Dialog, @@ -7,21 +9,19 @@ import { DialogHeader, DialogTitle, } from "@/components/ui/dialog"; +import { Separator } from "@/components/ui/separator"; +import { defineStepper } from "@stepperize/react"; import { BookIcon, Puzzle } from "lucide-react"; +import { Code2, Database, GitMerge, Globe, Plug, Users } from "lucide-react"; +import Link from "next/link"; import { useRouter } from "next/router"; import { useEffect, useState } from "react"; -import { defineStepper } from "@stepperize/react"; import React from "react"; -import { Separator } from "@/components/ui/separator"; -import { AlertBlock } from "@/components/shared/alert-block"; +import ConfettiExplosion from "react-confetti-explosion"; import { CreateServer } from "./create-server"; import { CreateSSHKey } from "./create-ssh-key"; import { Setup } from "./setup"; import { Verify } from "./verify"; -import { Database, Globe, GitMerge, Users, Code2, Plug } from "lucide-react"; -import ConfettiExplosion from "react-confetti-explosion"; -import Link from "next/link"; -import { GithubIcon } from "@/components/icons/data-tools-icons"; export const { useStepper, steps, Scoped } = defineStepper( { diff --git a/apps/dokploy/components/dashboard/settings/web-server/docker-terminal-modal.tsx b/apps/dokploy/components/dashboard/settings/web-server/docker-terminal-modal.tsx index f5b6b2a9e..fa9f1a41d 100644 --- a/apps/dokploy/components/dashboard/settings/web-server/docker-terminal-modal.tsx +++ b/apps/dokploy/components/dashboard/settings/web-server/docker-terminal-modal.tsx @@ -80,7 +80,7 @@ export const DockerTerminalModal = ({ children, appName, serverId }: Props) => { return ( {children} - event.preventDefault()} > diff --git a/apps/dokploy/components/dashboard/settings/web-server/manage-traefik-ports.tsx b/apps/dokploy/components/dashboard/settings/web-server/manage-traefik-ports.tsx index 965948ca0..180b2fcbb 100644 --- a/apps/dokploy/components/dashboard/settings/web-server/manage-traefik-ports.tsx +++ b/apps/dokploy/components/dashboard/settings/web-server/manage-traefik-ports.tsx @@ -6,6 +6,7 @@ import { DialogHeader, DialogTitle, } from "@/components/ui/dialog"; +import { Label } from "@/components/ui/label"; import { Select, SelectContent, @@ -13,7 +14,6 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; -import { Label } from "@/components/ui/label"; import { api } from "@/utils/api"; import { useTranslation } from "next-i18next"; import type React from "react"; diff --git a/apps/dokploy/pages/api/deploy/github.ts b/apps/dokploy/pages/api/deploy/github.ts index 0e0a6c829..459237620 100644 --- a/apps/dokploy/pages/api/deploy/github.ts +++ b/apps/dokploy/pages/api/deploy/github.ts @@ -3,19 +3,19 @@ import { applications, compose, github } from "@/server/db/schema"; import type { DeploymentJob } from "@/server/queues/queue-types"; import { myQueue } from "@/server/queues/queueSetup"; import { deploy } from "@/server/utils/deploy"; +import { generateRandomDomain } from "@/templates/utils"; import { - createPreviewDeployment, type Domain, + IS_CLOUD, + createPreviewDeployment, findPreviewDeploymentByApplicationId, findPreviewDeploymentsByPullRequestId, - IS_CLOUD, removePreviewDeployment, } from "@dokploy/server"; import { Webhooks } from "@octokit/webhooks"; import { and, eq } from "drizzle-orm"; import type { NextApiRequest, NextApiResponse } from "next"; import { extractCommitMessage, extractHash } from "./[refreshToken]"; -import { generateRandomDomain } from "@/templates/utils"; export default async function handler( req: NextApiRequest, diff --git a/apps/dokploy/public/locales/it/common.json b/apps/dokploy/public/locales/it/common.json index 9e26dfeeb..0967ef424 100644 --- a/apps/dokploy/public/locales/it/common.json +++ b/apps/dokploy/public/locales/it/common.json @@ -1 +1 @@ -{} \ No newline at end of file +{} diff --git a/apps/dokploy/public/locales/it/settings.json b/apps/dokploy/public/locales/it/settings.json index f4c2cc068..6280e44eb 100644 --- a/apps/dokploy/public/locales/it/settings.json +++ b/apps/dokploy/public/locales/it/settings.json @@ -1,44 +1,44 @@ -{ - "settings.common.save": "Salva", - "settings.server.domain.title": "Dominio del server", - "settings.server.domain.description": "Aggiungi un dominio alla tua applicazione server.", - "settings.server.domain.form.domain": "Dominio", - "settings.server.domain.form.letsEncryptEmail": "Email di Let's Encrypt", - "settings.server.domain.form.certificate.label": "Certificato", - "settings.server.domain.form.certificate.placeholder": "Seleziona un certificato", - "settings.server.domain.form.certificateOptions.none": "Nessuno", - "settings.server.domain.form.certificateOptions.letsencrypt": "Let's Encrypt (Predefinito)", - - "settings.server.webServer.title": "Server Web", - "settings.server.webServer.description": "Ricarica o pulisci il server web.", - "settings.server.webServer.actions": "Azioni", - "settings.server.webServer.reload": "Ricarica", - "settings.server.webServer.watchLogs": "Guarda i log", - "settings.server.webServer.updateServerIp": "Aggiorna IP del server", - "settings.server.webServer.server.label": "Server", - "settings.server.webServer.traefik.label": "Traefik", - "settings.server.webServer.traefik.modifyEnv": "Modifica Env", - "settings.server.webServer.storage.label": "Spazio", - "settings.server.webServer.storage.cleanUnusedImages": "Pulisci immagini inutilizzate", - "settings.server.webServer.storage.cleanUnusedVolumes": "Pulisci volumi inutilizzati", - "settings.server.webServer.storage.cleanStoppedContainers": "Pulisci container fermati", - "settings.server.webServer.storage.cleanDockerBuilder": "Pulisci Docker Builder e sistema", - "settings.server.webServer.storage.cleanMonitoring": "Pulisci monitoraggio", - "settings.server.webServer.storage.cleanAll": "Pulisci tutto", - - "settings.profile.title": "Account", - "settings.profile.description": "Modifica i dettagli del tuo profilo qui.", - "settings.profile.email": "Email", - "settings.profile.password": "Password", - "settings.profile.avatar": "Avatar", - - "settings.appearance.title": "Aspetto", - "settings.appearance.description": "Personalizza il tema della tua dashboard.", - "settings.appearance.theme": "Tema", - "settings.appearance.themeDescription": "Seleziona un tema per la tua dashboard", - "settings.appearance.themes.light": "Chiaro", - "settings.appearance.themes.dark": "Scuro", - "settings.appearance.themes.system": "Sistema", - "settings.appearance.language": "Lingua", - "settings.appearance.languageDescription": "Seleziona una lingua per la tua dashboard" -} \ No newline at end of file +{ + "settings.common.save": "Salva", + "settings.server.domain.title": "Dominio del server", + "settings.server.domain.description": "Aggiungi un dominio alla tua applicazione server.", + "settings.server.domain.form.domain": "Dominio", + "settings.server.domain.form.letsEncryptEmail": "Email di Let's Encrypt", + "settings.server.domain.form.certificate.label": "Certificato", + "settings.server.domain.form.certificate.placeholder": "Seleziona un certificato", + "settings.server.domain.form.certificateOptions.none": "Nessuno", + "settings.server.domain.form.certificateOptions.letsencrypt": "Let's Encrypt (Predefinito)", + + "settings.server.webServer.title": "Server Web", + "settings.server.webServer.description": "Ricarica o pulisci il server web.", + "settings.server.webServer.actions": "Azioni", + "settings.server.webServer.reload": "Ricarica", + "settings.server.webServer.watchLogs": "Guarda i log", + "settings.server.webServer.updateServerIp": "Aggiorna IP del server", + "settings.server.webServer.server.label": "Server", + "settings.server.webServer.traefik.label": "Traefik", + "settings.server.webServer.traefik.modifyEnv": "Modifica Env", + "settings.server.webServer.storage.label": "Spazio", + "settings.server.webServer.storage.cleanUnusedImages": "Pulisci immagini inutilizzate", + "settings.server.webServer.storage.cleanUnusedVolumes": "Pulisci volumi inutilizzati", + "settings.server.webServer.storage.cleanStoppedContainers": "Pulisci container fermati", + "settings.server.webServer.storage.cleanDockerBuilder": "Pulisci Docker Builder e sistema", + "settings.server.webServer.storage.cleanMonitoring": "Pulisci monitoraggio", + "settings.server.webServer.storage.cleanAll": "Pulisci tutto", + + "settings.profile.title": "Account", + "settings.profile.description": "Modifica i dettagli del tuo profilo qui.", + "settings.profile.email": "Email", + "settings.profile.password": "Password", + "settings.profile.avatar": "Avatar", + + "settings.appearance.title": "Aspetto", + "settings.appearance.description": "Personalizza il tema della tua dashboard.", + "settings.appearance.theme": "Tema", + "settings.appearance.themeDescription": "Seleziona un tema per la tua dashboard", + "settings.appearance.themes.light": "Chiaro", + "settings.appearance.themes.dark": "Scuro", + "settings.appearance.themes.system": "Sistema", + "settings.appearance.language": "Lingua", + "settings.appearance.languageDescription": "Seleziona una lingua per la tua dashboard" +} diff --git a/apps/dokploy/server/api/routers/compose.ts b/apps/dokploy/server/api/routers/compose.ts index 6d04e815f..5f53752b5 100644 --- a/apps/dokploy/server/api/routers/compose.ts +++ b/apps/dokploy/server/api/routers/compose.ts @@ -3,6 +3,7 @@ import { db } from "@/server/db"; import { apiCreateCompose, apiCreateComposeByTemplate, + apiDeleteCompose, apiFetchServices, apiFindCompose, apiRandomizeCompose, @@ -117,7 +118,7 @@ export const composeRouter = createTRPCRouter({ return updateCompose(input.composeId, input); }), delete: protectedProcedure - .input(apiFindCompose) + .input(apiDeleteCompose) .mutation(async ({ input, ctx }) => { if (ctx.user.rol === "user") { await checkServiceAccess(ctx.user.authId, input.composeId, "delete"); @@ -138,7 +139,7 @@ export const composeRouter = createTRPCRouter({ .returning(); const cleanupOperations = [ - async () => await removeCompose(composeResult), + async () => await removeCompose(composeResult, input.deleteVolumes), async () => await removeDeploymentsByComposeId(composeResult), async () => await removeComposeDirectory(composeResult.appName), ]; diff --git a/apps/dokploy/templates/onedev/index.ts b/apps/dokploy/templates/onedev/index.ts index 5dad17282..8017c3514 100644 --- a/apps/dokploy/templates/onedev/index.ts +++ b/apps/dokploy/templates/onedev/index.ts @@ -1,22 +1,22 @@ import { - type DomainSchema, - type Schema, - type Template, - generateRandomDomain, + type DomainSchema, + type Schema, + type Template, + generateRandomDomain, } from "../utils"; export function generate(schema: Schema): Template { - const randomDomain = generateRandomDomain(schema); + const randomDomain = generateRandomDomain(schema); - const domains: DomainSchema[] = [ - { - host: randomDomain, - port: 6610, - serviceName: "onedev", - }, - ]; + const domains: DomainSchema[] = [ + { + host: randomDomain, + port: 6610, + serviceName: "onedev", + }, + ]; - return { - domains, - }; + return { + domains, + }; } diff --git a/apps/dokploy/templates/unsend/index.ts b/apps/dokploy/templates/unsend/index.ts index a383b771f..1c4c9c715 100644 --- a/apps/dokploy/templates/unsend/index.ts +++ b/apps/dokploy/templates/unsend/index.ts @@ -1,44 +1,44 @@ import { - generateHash, - generateRandomDomain, - generateBase64, - type Template, - type Schema, - type DomainSchema, + type DomainSchema, + type Schema, + type Template, + generateBase64, + generateHash, + generateRandomDomain, } from "../utils"; export function generate(schema: Schema): Template { - const mainDomain = generateRandomDomain(schema); - const secretBase = generateBase64(64); + const mainDomain = generateRandomDomain(schema); + const secretBase = generateBase64(64); - const domains: DomainSchema[] = [ - { - host: mainDomain, - port: 3000, - serviceName: "unsend", - }, - ]; + const domains: DomainSchema[] = [ + { + host: mainDomain, + port: 3000, + serviceName: "unsend", + }, + ]; - const envs = [ - "REDIS_URL=redis://unsend-redis-prod:6379", - "POSTGRES_USER=postgres", - "POSTGRES_PASSWORD=postgres", - "POSTGRES_DB=unsend", - "DATABASE_URL=postgresql://postgres:postgres@unsend-db-prod:5432/unsend", - "NEXTAUTH_URL=http://localhost:3000", - `NEXTAUTH_SECRET=${secretBase}`, - "GITHUB_ID='Fill'", - "GITHUB_SECRET='Fill'", - "AWS_DEFAULT_REGION=us-east-1", - "AWS_SECRET_KEY='Fill'", - "AWS_ACCESS_KEY='Fill'", - "DOCKER_OUTPUT=1", - "API_RATE_LIMIT=1", - "DISCORD_WEBHOOK_URL=", - ]; + const envs = [ + "REDIS_URL=redis://unsend-redis-prod:6379", + "POSTGRES_USER=postgres", + "POSTGRES_PASSWORD=postgres", + "POSTGRES_DB=unsend", + "DATABASE_URL=postgresql://postgres:postgres@unsend-db-prod:5432/unsend", + "NEXTAUTH_URL=http://localhost:3000", + `NEXTAUTH_SECRET=${secretBase}`, + "GITHUB_ID='Fill'", + "GITHUB_SECRET='Fill'", + "AWS_DEFAULT_REGION=us-east-1", + "AWS_SECRET_KEY='Fill'", + "AWS_ACCESS_KEY='Fill'", + "DOCKER_OUTPUT=1", + "API_RATE_LIMIT=1", + "DISCORD_WEBHOOK_URL=", + ]; - return { - envs, - domains, - }; + return { + envs, + domains, + }; } diff --git a/packages/server/src/db/schema/application.ts b/packages/server/src/db/schema/application.ts index d9b1a5df4..0f6aaed31 100644 --- a/packages/server/src/db/schema/application.ts +++ b/packages/server/src/db/schema/application.ts @@ -17,6 +17,7 @@ import { github } from "./github"; import { gitlab } from "./gitlab"; import { mounts } from "./mount"; import { ports } from "./port"; +import { previewDeployments } from "./preview-deployments"; import { projects } from "./project"; import { redirects } from "./redirects"; import { registry } from "./registry"; @@ -25,7 +26,6 @@ import { server } from "./server"; import { applicationStatus, certificateType } from "./shared"; import { sshKeys } from "./ssh-key"; import { generateAppName } from "./utils"; -import { previewDeployments } from "./preview-deployments"; export const sourceType = pgEnum("sourceType", [ "docker", diff --git a/packages/server/src/db/schema/compose.ts b/packages/server/src/db/schema/compose.ts index 02bac7813..e0c4863b5 100644 --- a/packages/server/src/db/schema/compose.ts +++ b/packages/server/src/db/schema/compose.ts @@ -155,6 +155,11 @@ export const apiFindCompose = z.object({ composeId: z.string().min(1), }); +export const apiDeleteCompose = z.object({ + composeId: z.string().min(1), + deleteVolumes: z.boolean(), +}); + export const apiFetchServices = z.object({ composeId: z.string().min(1), type: z.enum(["fetch", "cache"]).optional().default("cache"), diff --git a/packages/server/src/db/schema/deployment.ts b/packages/server/src/db/schema/deployment.ts index f79b48ee9..ccaf64661 100644 --- a/packages/server/src/db/schema/deployment.ts +++ b/packages/server/src/db/schema/deployment.ts @@ -11,8 +11,8 @@ import { nanoid } from "nanoid"; import { z } from "zod"; import { applications } from "./application"; import { compose } from "./compose"; -import { server } from "./server"; import { previewDeployments } from "./preview-deployments"; +import { server } from "./server"; export const deploymentStatus = pgEnum("deploymentStatus", [ "running", diff --git a/packages/server/src/db/schema/domain.ts b/packages/server/src/db/schema/domain.ts index f115ce667..5c34d455d 100644 --- a/packages/server/src/db/schema/domain.ts +++ b/packages/server/src/db/schema/domain.ts @@ -14,8 +14,8 @@ import { z } from "zod"; import { domain } from "../validations/domain"; import { applications } from "./application"; import { compose } from "./compose"; -import { certificateType } from "./shared"; import { previewDeployments } from "./preview-deployments"; +import { certificateType } from "./shared"; export const domainType = pgEnum("domainType", [ "compose", diff --git a/packages/server/src/db/schema/index.ts b/packages/server/src/db/schema/index.ts index f07a18707..9c7a079c5 100644 --- a/packages/server/src/db/schema/index.ts +++ b/packages/server/src/db/schema/index.ts @@ -29,4 +29,4 @@ export * from "./github"; export * from "./gitlab"; export * from "./server"; export * from "./utils"; -export * from "./preview-deployments"; \ No newline at end of file +export * from "./preview-deployments"; diff --git a/packages/server/src/db/schema/preview-deployments.ts b/packages/server/src/db/schema/preview-deployments.ts index 5d0671e8d..3bdab2c25 100644 --- a/packages/server/src/db/schema/preview-deployments.ts +++ b/packages/server/src/db/schema/preview-deployments.ts @@ -1,13 +1,13 @@ import { relations } from "drizzle-orm"; import { pgTable, text } from "drizzle-orm/pg-core"; +import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; +import { z } from "zod"; import { applications } from "./application"; -import { domains } from "./domain"; import { deployments } from "./deployment"; -import { createInsertSchema } from "drizzle-zod"; -import { z } from "zod"; -import { generateAppName } from "./utils"; +import { domains } from "./domain"; import { applicationStatus } from "./shared"; +import { generateAppName } from "./utils"; export const previewDeployments = pgTable("preview_deployments", { previewDeploymentId: text("previewDeploymentId") diff --git a/packages/server/src/services/compose.ts b/packages/server/src/services/compose.ts index 5e5c68978..ff6603515 100644 --- a/packages/server/src/services/compose.ts +++ b/packages/server/src/services/compose.ts @@ -206,7 +206,9 @@ export const deployCompose = async ({ descriptionLog: string; }) => { const compose = await findComposeById(composeId); - const buildLink = `${await getDokployUrl()}/dashboard/project/${compose.projectId}/services/compose/${compose.composeId}?tab=deployments`; + const buildLink = `${await getDokployUrl()}/dashboard/project/${ + compose.projectId + }/services/compose/${compose.composeId}?tab=deployments`; const deployment = await createDeploymentCompose({ composeId: composeId, title: titleLog, @@ -308,7 +310,9 @@ export const deployRemoteCompose = async ({ descriptionLog: string; }) => { const compose = await findComposeById(composeId); - const buildLink = `${await getDokployUrl()}/dashboard/project/${compose.projectId}/services/compose/${compose.composeId}?tab=deployments`; + const buildLink = `${await getDokployUrl()}/dashboard/project/${ + compose.projectId + }/services/compose/${compose.composeId}?tab=deployments`; const deployment = await createDeploymentCompose({ composeId: composeId, title: titleLog, @@ -437,13 +441,17 @@ export const rebuildRemoteCompose = async ({ return true; }; -export const removeCompose = async (compose: Compose) => { +export const removeCompose = async ( + compose: Compose, + deleteVolumes: boolean, +) => { try { const { COMPOSE_PATH } = paths(!!compose.serverId); const projectPath = join(COMPOSE_PATH, compose.appName); if (compose.composeType === "stack") { const command = `cd ${projectPath} && docker stack rm ${compose.appName} && rm -rf ${projectPath}`; + if (compose.serverId) { await execAsyncRemote(compose.serverId, command); } else { @@ -453,7 +461,13 @@ export const removeCompose = async (compose: Compose) => { cwd: projectPath, }); } else { - const command = `cd ${projectPath} && docker compose -p ${compose.appName} down && rm -rf ${projectPath}`; + let command: string; + if (deleteVolumes) { + command = `cd ${projectPath} && docker compose -p ${compose.appName} down --volumes && rm -rf ${projectPath}`; + } else { + command = `cd ${projectPath} && docker compose -p ${compose.appName} down && rm -rf ${projectPath}`; + } + if (compose.serverId) { await execAsyncRemote(compose.serverId, command); } else { @@ -477,7 +491,11 @@ export const startCompose = async (composeId: string) => { if (compose.serverId) { await execAsyncRemote( compose.serverId, - `cd ${join(COMPOSE_PATH, compose.appName, "code")} && docker compose -p ${compose.appName} up -d`, + `cd ${join( + COMPOSE_PATH, + compose.appName, + "code", + )} && docker compose -p ${compose.appName} up -d`, ); } else { await execAsync(`docker compose -p ${compose.appName} up -d`, { @@ -507,7 +525,9 @@ export const stopCompose = async (composeId: string) => { if (compose.serverId) { await execAsyncRemote( compose.serverId, - `cd ${join(COMPOSE_PATH, compose.appName)} && docker compose -p ${compose.appName} stop`, + `cd ${join(COMPOSE_PATH, compose.appName)} && docker compose -p ${ + compose.appName + } stop`, ); } else { await execAsync(`docker compose -p ${compose.appName} stop`, { diff --git a/packages/server/src/utils/backups/index.ts b/packages/server/src/utils/backups/index.ts index 797feb383..6fec7a319 100644 --- a/packages/server/src/utils/backups/index.ts +++ b/packages/server/src/utils/backups/index.ts @@ -7,12 +7,12 @@ import { cleanUpSystemPrune, cleanUpUnusedImages, } from "../docker/utils"; +import { sendDatabaseBackupNotifications } from "../notifications/database-backup"; +import { sendDockerCleanupNotifications } from "../notifications/docker-cleanup"; import { runMariadbBackup } from "./mariadb"; import { runMongoBackup } from "./mongo"; import { runMySqlBackup } from "./mysql"; import { runPostgresBackup } from "./postgres"; -import { sendDockerCleanupNotifications } from "../notifications/docker-cleanup"; -import { sendDatabaseBackupNotifications } from "../notifications/database-backup"; export const initCronJobs = async () => { console.log("Setting up cron jobs...."); diff --git a/packages/server/src/utils/builders/index.ts b/packages/server/src/utils/builders/index.ts index ce10413ac..df85d98f9 100644 --- a/packages/server/src/utils/builders/index.ts +++ b/packages/server/src/utils/builders/index.ts @@ -2,6 +2,7 @@ import { createWriteStream } from "node:fs"; import { join } from "node:path"; import type { InferResultType } from "@dokploy/server/types/with"; import type { CreateServiceOptions } from "dockerode"; +import { nanoid } from "nanoid"; import { uploadImage, uploadImageRemoteCommand } from "../cluster/upload"; import { calculateResources, @@ -17,7 +18,6 @@ import { buildHeroku, getHerokuCommand } from "./heroku"; import { buildNixpacks, getNixpacksCommand } from "./nixpacks"; import { buildPaketo, getPaketoCommand } from "./paketo"; import { buildStatic, getStaticCommand } from "./static"; -import { nanoid } from "nanoid"; // NIXPACKS codeDirectory = where is the path of the code directory // HEROKU codeDirectory = where is the path of the code directory diff --git a/packages/server/src/utils/docker/utils.ts b/packages/server/src/utils/docker/utils.ts index 216ee8671..a14602e93 100644 --- a/packages/server/src/utils/docker/utils.ts +++ b/packages/server/src/utils/docker/utils.ts @@ -238,9 +238,11 @@ export const startServiceRemote = async (serverId: string, appName: string) => { export const removeService = async ( appName: string, serverId?: string | null, + deleteVolumes = false, ) => { try { const command = `docker service rm ${appName}`; + if (serverId) { await execAsyncRemote(serverId, command); } else {