diff --git a/apps/dokploy/components/dashboard/project/add-compose.tsx b/apps/dokploy/components/dashboard/project/add-compose.tsx index 815c58ca82..0d6d7a7bc2 100644 --- a/apps/dokploy/components/dashboard/project/add-compose.tsx +++ b/apps/dokploy/components/dashboard/project/add-compose.tsx @@ -79,7 +79,7 @@ export const AddCompose = ({ environmentId, projectName }: Props) => { api.compose.create.useMutation(); // Get environment data to extract projectId - const { data: environment } = api.environment.one.useQuery({ environmentId }); + // const { data: environment } = api.environment.one.useQuery({ environmentId }); const hasServers = servers && servers.length > 0; // Show dropdown logic based on cloud environment @@ -117,6 +117,8 @@ export const AddCompose = ({ environmentId, projectName }: Props) => { await utils.environment.one.invalidate({ environmentId, }); + // Invalidate the project query to refresh the project data for the advance-breadcrumb + await utils.project.all.invalidate(); }) .catch(() => { toast.error("Error creating the compose"); diff --git a/apps/dokploy/components/dashboard/project/add-template.tsx b/apps/dokploy/components/dashboard/project/add-template.tsx index ef9a88e6f7..fd37e6a0c0 100644 --- a/apps/dokploy/components/dashboard/project/add-template.tsx +++ b/apps/dokploy/components/dashboard/project/add-template.tsx @@ -332,6 +332,7 @@ export const AddTemplate = ({ environmentId, baseUrl }: Props) => { viewMode === "detailed" && "border-b", )} > + {/** biome-ignore lint/performance/noImgElement: this is a valid use for img tag */} { return ( <> + {!isCloud && ( +
+ +
+ )} @@ -429,7 +434,7 @@ export const ShowProjects = () => { -
+
Created diff --git a/apps/dokploy/components/dashboard/settings/certificates/utils.ts b/apps/dokploy/components/dashboard/settings/certificates/utils.ts index e2aa59ef3a..79b763a970 100644 --- a/apps/dokploy/components/dashboard/settings/certificates/utils.ts +++ b/apps/dokploy/components/dashboard/settings/certificates/utils.ts @@ -14,13 +14,13 @@ export const extractExpirationDate = (certData: string): Date | null => { // Helper: read ASN.1 length field function readLength(pos: number): { length: number; offset: number } { - // biome-ignore lint/style/noParameterAssign: + // biome-ignore lint/style/noParameterAssign: this is for dynamic length calculation let len = der[pos++]; if (len & 0x80) { const bytes = len & 0x7f; len = 0; for (let i = 0; i < bytes; i++) { - // biome-ignore lint/style/noParameterAssign: + // biome-ignore lint/style/noParameterAssign: this is for dynamic length calculation len = (len << 8) + der[pos++]; } } diff --git a/apps/dokploy/components/layouts/side.tsx b/apps/dokploy/components/layouts/side.tsx index 6a0f9de19a..eb8d2789de 100644 --- a/apps/dokploy/components/layouts/side.tsx +++ b/apps/dokploy/components/layouts/side.tsx @@ -908,6 +908,7 @@ export default function Page({ children }: Props) { onOpenChange={(open) => { setDefaultOpen(open); + // biome-ignore lint/suspicious/noDocumentCookie: this sets the cookie to keep the sidebar state. document.cookie = `${SIDEBAR_COOKIE_NAME}=${open}`; }} style={ diff --git a/apps/dokploy/components/shared/advance-breadcrumb.tsx b/apps/dokploy/components/shared/advance-breadcrumb.tsx new file mode 100644 index 0000000000..52401482fa --- /dev/null +++ b/apps/dokploy/components/shared/advance-breadcrumb.tsx @@ -0,0 +1,628 @@ +import type { ServiceType } from "@dokploy/server/db/schema"; +import { + Check, + ChevronDown, + ChevronRight, + CircuitBoard, + FolderInput, + GlobeIcon, + X, +} from "lucide-react"; +import { useRouter } from "next/router"; +import { type ComponentType, useEffect, useMemo, useState } from "react"; +import { + MariadbIcon, + MongodbIcon, + MysqlIcon, + PostgresqlIcon, + RedisIcon, +} from "@/components/icons/data-tools-icons"; +import { Button } from "@/components/ui/button"; +import { + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList, +} from "@/components/ui/command"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; +import { ScrollArea } from "@/components/ui/scroll-area"; +import { Separator } from "@/components/ui/separator"; +import { SidebarTrigger } from "@/components/ui/sidebar"; +import { api, type RouterOutputs } from "@/utils/api"; + +type ProjectItem = RouterOutputs["project"]["all"][number]; +type ProjectEnvironment = ProjectItem["environments"][number]; +type EnvironmentDetails = RouterOutputs["environment"]["one"]; + +type ServiceItem = { + id: string; + name: string; + type: ServiceType; +}; + +type NamedService = { + name: string; +}; + +type EnvironmentServiceCollections = { + applications: (NamedService & { applicationId: string })[]; + compose: (NamedService & { composeId: string })[]; + postgres: (NamedService & { postgresId: string })[]; + mysql: (NamedService & { mysqlId: string })[]; + mariadb: (NamedService & { mariadbId: string })[]; + redis: (NamedService & { redisId: string })[]; + mongo: (NamedService & { mongoId: string })[]; +}; + +type ServiceCollections = Pick< + ProjectEnvironment, + | "applications" + | "compose" + | "postgres" + | "mysql" + | "mariadb" + | "redis" + | "mongo" +>; + +const SERVICE_COLLECTION_KEYS = [ + "applications", + "compose", + "postgres", + "mysql", + "mariadb", + "redis", + "mongo", +] as const satisfies ReadonlyArray; + +const SERVICE_QUERY_KEYS = [ + "applicationId", + "composeId", + "postgresId", + "mysqlId", + "mariadbId", + "redisId", + "mongoId", +] as const; + +const SERVICE_ICONS: Record< + ServiceType, + ComponentType<{ className?: string }> +> = { + application: GlobeIcon, + compose: CircuitBoard, + postgres: PostgresqlIcon, + mysql: MysqlIcon, + mariadb: MariadbIcon, + redis: RedisIcon, + mongo: MongodbIcon, +}; + +const getStringQueryParam = (value: string | string[] | undefined) => + typeof value === "string" ? value : null; + +const includesSearch = (value: string | null | undefined, search: string) => + value?.toLowerCase().includes(search.toLowerCase()) ?? false; + +const getServiceIcon = (type: ServiceType, className = "size-4") => { + const Icon = SERVICE_ICONS[type]; + return ; +}; + +const countEnvironmentServices = (environment: ServiceCollections): number => + SERVICE_COLLECTION_KEYS.reduce( + (total, key) => total + environment[key].length, + 0, + ); + +const mapServices = ( + items: readonly T[], + getId: (item: T) => string, + type: ServiceType, +): ServiceItem[] => + items.map((item) => ({ + id: getId(item), + name: item.name, + type, + })); + +const extractServicesFromEnvironment = ( + environment: EnvironmentDetails | null | undefined, +): ServiceItem[] => { + if (!environment) return []; + + const servicesByType = + environment as unknown as EnvironmentServiceCollections; + + return [ + ...mapServices( + servicesByType.applications, + (item) => item.applicationId, + "application", + ), + ...mapServices(servicesByType.compose, (item) => item.composeId, "compose"), + ...mapServices( + servicesByType.postgres, + (item) => item.postgresId, + "postgres", + ), + ...mapServices(servicesByType.mysql, (item) => item.mysqlId, "mysql"), + ...mapServices(servicesByType.mariadb, (item) => item.mariadbId, "mariadb"), + ...mapServices(servicesByType.redis, (item) => item.redisId, "redis"), + ...mapServices(servicesByType.mongo, (item) => item.mongoId, "mongo"), + ]; +}; + +const getTargetEnvironmentId = ( + project: ProjectItem, + selectedEnvironmentId?: string, +) => { + if (selectedEnvironmentId) return selectedEnvironmentId; + + const productionEnvironment = project.environments.find( + (environment) => environment.name === "production", + ); + + return ( + productionEnvironment?.environmentId ?? + project.environments[0]?.environmentId + ); +}; + +export const AdvanceBreadcrumb = () => { + const router = useRouter(); + const { query } = router; + + // Read IDs from URL (dynamic route segments) + const projectId = getStringQueryParam(query.projectId); + const environmentId = getStringQueryParam(query.environmentId); + const serviceId = + SERVICE_QUERY_KEYS.map((key) => getStringQueryParam(query[key])).find( + (value): value is string => !!value, + ) ?? null; + + const [projectOpen, setProjectOpen] = useState(false); + const [serviceOpen, setServiceOpen] = useState(false); + const [environmentOpen, setEnvironmentOpen] = useState(false); + const [projectSearch, setProjectSearch] = useState(""); + const [serviceSearch, setServiceSearch] = useState(""); + const [environmentSearch, setEnvironmentSearch] = useState(""); + const [expandedProjectId, setExpandedProjectId] = useState( + null, + ); + + // Fetch all projects + const { data: allProjects } = api.project.all.useQuery(); + + // Fetch current project data + const { data: currentProject } = api.project.one.useQuery( + { projectId: projectId ?? "" }, + { enabled: !!projectId }, + ); + + // Fetch current environment + const { data: currentEnvironment } = api.environment.one.useQuery( + { environmentId: environmentId ?? "" }, + { enabled: !!environmentId }, + ); + + // Fetch environments for current project + const { data: projectEnvironments } = api.environment.byProjectId.useQuery( + { projectId: projectId ?? "" }, + { enabled: !!projectId }, + ); + + // Close dropdowns on escape key + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === "Escape") { + setProjectOpen(false); + setServiceOpen(false); + setEnvironmentOpen(false); + } + }; + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, []); + + const services = useMemo( + () => extractServicesFromEnvironment(currentEnvironment), + [currentEnvironment], + ); + + const currentService = useMemo( + () => services.find((service) => service.id === serviceId), + [serviceId, services], + ); + + // Navigate to project's default environment + const handleProjectSelect = ( + selectedProjectId: string, + selectedEnvironmentId?: string, + ) => { + const project = allProjects?.find((p) => p.projectId === selectedProjectId); + if (project) { + const targetEnvironmentId = getTargetEnvironmentId( + project, + selectedEnvironmentId, + ); + + if (targetEnvironmentId) { + router.push( + `/dashboard/project/${selectedProjectId}/environment/${targetEnvironmentId}`, + ); + } + } + setProjectOpen(false); + setExpandedProjectId(null); + }; + + // Navigate to environment + const handleEnvironmentSelect = (envId: string) => { + router.push(`/dashboard/project/${projectId}/environment/${envId}`); + setEnvironmentOpen(false); + }; + + // Navigate to service + const handleServiceSelect = (service: ServiceItem) => { + if (!environmentId) return; + + router.push( + `/dashboard/project/${projectId}/environment/${environmentId}/services/${service.type}/${service.id}`, + ); + setServiceOpen(false); + }; + + const filteredProjects = useMemo( + () => + (allProjects ?? []).filter( + (project) => + includesSearch(project.name, projectSearch) || + includesSearch(project.description, projectSearch), + ), + [allProjects, projectSearch], + ); + + const filteredServices = useMemo( + () => + services.filter((service) => includesSearch(service.name, serviceSearch)), + [serviceSearch, services], + ); + + const filteredEnvironments = useMemo( + () => + (projectEnvironments ?? []).filter((environment) => + includesSearch(environment.name, environmentSearch), + ), + [environmentSearch, projectEnvironments], + ); + + // If we're just on the projects page, show simple breadcrumb + if (!projectId) { + return ( +
+
+ + +
+ + Projects +
+
+
+ ); + } + + return ( +
+
+ + + +
+ {/* Project Selector */} + + + + + + +
+ + + Esc + +
+ + No projects found. + + + {filteredProjects.map((project) => { + const totalServices = project.environments.reduce( + (total, env) => total + countEnvironmentServices(env), + 0, + ); + const isSelected = project.projectId === projectId; + const isExpanded = + expandedProjectId === project.projectId; + + return ( +
+ { + if (project.environments.length > 1) { + setExpandedProjectId( + isExpanded ? null : project.projectId, + ); + } else { + handleProjectSelect(project.projectId); + } + }} + className="flex items-center justify-between py-3 px-2 cursor-pointer" + > +
+
+ {project.name.slice(0, 2)} +
+
+ + {project.name} + + + {project.environments.length} env + {project.environments.length !== 1 + ? "s" + : ""}{" "} + ยท {totalServices} service + {totalServices !== 1 ? "s" : ""} + +
+
+
+ {isSelected && ( + + )} + {project.environments.length > 1 && ( + + )} +
+
+ + {/* Expanded environments */} + {isExpanded && ( +
+ {project.environments.map((env) => { + const envServices = + countEnvironmentServices(env); + const isEnvSelected = + env.environmentId === environmentId; + + return ( + + handleProjectSelect( + project.projectId, + env.environmentId, + ) + } + className="flex items-center justify-between py-2 px-2 cursor-pointer text-sm" + > +
+

{env.name}

+ + {envServices} service + {envServices !== 1 ? "s" : ""} + +
+ {isEnvSelected && ( + + )} +
+ ); + })} +
+ )} +
+ ); + })} +
+
+
+
+
+
+ + {/* Environment Selector */} + {projectEnvironments && projectEnvironments.length > 1 && ( + + + + + + +
+ + + Esc + +
+ + No environments found. + + + {filteredEnvironments.map((env) => { + const isSelected = + env.environmentId === environmentId; + return ( + + handleEnvironmentSelect(env.environmentId) + } + className="flex items-center justify-between py-2 cursor-pointer" + > + {env.name} + {isSelected && ( + + )} + + ); + })} + + + +
+
+
+ )} + + {projectEnvironments && projectEnvironments.length === 1 && ( +

+ {currentEnvironment?.name || "production"} +

+ )} + + {/* Service Selector - only show when viewing a service */} + {serviceId && currentService && ( + <> + + + + + + + + +
+ + + Esc + +
+ + No services found. + + + {filteredServices.map((service) => { + const isSelected = service.id === serviceId; + return ( + handleServiceSelect(service)} + className="flex items-center justify-between py-2 cursor-pointer" + > +
+
+ {getServiceIcon(service.type)} +
+
+ + {service.name} + + + {service.type} + +
+
+ {isSelected && ( + + )} +
+ ); + })} +
+
+
+
+
+
+ + {/* Close button to go back to environment */} + + + )} +
+
+
+ ); +}; diff --git a/apps/dokploy/components/shared/logo.tsx b/apps/dokploy/components/shared/logo.tsx index a1c3acb7e1..2c316e22f3 100644 --- a/apps/dokploy/components/shared/logo.tsx +++ b/apps/dokploy/components/shared/logo.tsx @@ -8,6 +8,7 @@ interface Props { export const Logo = ({ className = "size-14", logoUrl }: Props) => { if (logoUrl) { return ( + // biome-ignore lint/performance/noImgElement: this is for dynamic logo loading Organization Logo { `/dashboard/settings/git-providers?error=${encodeURIComponent(error)}`, ); }; + +export default findGitea; diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId].tsx index d7ac393def..c13fe559fe 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId].tsx @@ -44,8 +44,8 @@ import { RedisIcon, } from "@/components/icons/data-tools-icons"; import { DashboardLayout } from "@/components/layouts/dashboard-layout"; +import { AdvanceBreadcrumb } from "@/components/shared/advance-breadcrumb"; import { AlertBlock } from "@/components/shared/alert-block"; -import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar"; import { DateTooltip } from "@/components/shared/date-tooltip"; import { DialogAction } from "@/components/shared/dialog-action"; import { FocusShortcutInput } from "@/components/shared/focus-shortcut-input"; @@ -861,18 +861,7 @@ const EnvironmentPage = ( return (
- + Environment: {currentEnvironment.name} | {projectData?.name} |{" "} diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/application/[applicationId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/application/[applicationId].tsx index ba27920f17..df2c22179d 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/application/[applicationId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/application/[applicationId].tsx @@ -35,7 +35,7 @@ import { DeleteService } from "@/components/dashboard/compose/delete-service"; import { ContainerFreeMonitoring } from "@/components/dashboard/monitoring/free/container/show-free-container-monitoring"; import { ContainerPaidMonitoring } from "@/components/dashboard/monitoring/paid/container/show-paid-container-monitoring"; import { DashboardLayout } from "@/components/layouts/dashboard-layout"; -import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar"; +import { AdvanceBreadcrumb } from "@/components/shared/advance-breadcrumb"; import { StatusTooltip } from "@/components/shared/status-tooltip"; import { Badge } from "@/components/ui/badge"; import { @@ -108,22 +108,7 @@ const Service = ( return ( <div className="pb-10"> <UseKeyboardNav forPage="application" /> - <BreadcrumbSidebar - list={[ - { name: "Projects", href: "/dashboard/projects" }, - { - name: data?.environment?.project?.name || "", - href: `/dashboard/project/${projectId}/environment/${environmentId}`, - }, - { - name: data?.environment?.name || "", - dropdownItems: environmentDropdownItems, - }, - { - name: data?.name || "", - }, - ]} - /> + <AdvanceBreadcrumb /> <Head> <title> Application: {data?.name} - {data?.environment.project.name} |{" "} diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/compose/[composeId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/compose/[composeId].tsx index 9056e186dd..078bf5b6b9 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/compose/[composeId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/compose/[composeId].tsx @@ -31,7 +31,7 @@ import { ShowBackups } from "@/components/dashboard/database/backups/show-backup import { ComposeFreeMonitoring } from "@/components/dashboard/monitoring/free/container/show-free-compose-monitoring"; import { ComposePaidMonitoring } from "@/components/dashboard/monitoring/paid/container/show-paid-compose-monitoring"; import { DashboardLayout } from "@/components/layouts/dashboard-layout"; -import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar"; +import { AdvanceBreadcrumb } from "@/components/shared/advance-breadcrumb"; import { StatusTooltip } from "@/components/shared/status-tooltip"; import { Badge } from "@/components/ui/badge"; import { @@ -97,22 +97,7 @@ const Service = ( return ( <div className="pb-10"> <UseKeyboardNav forPage="compose" /> - <BreadcrumbSidebar - list={[ - { name: "Projects", href: "/dashboard/projects" }, - { - name: data?.environment?.project?.name || "", - href: `/dashboard/project/${projectId}/environment/${environmentId}`, - }, - { - name: data?.environment?.name || "", - dropdownItems: environmentDropdownItems, - }, - { - name: data?.name || "", - }, - ]} - /> + <AdvanceBreadcrumb /> <Head> <title> Compose: {data?.name} - {data?.environment?.project?.name} | {appName} diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/mariadb/[mariadbId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/mariadb/[mariadbId].tsx index 8e210c92b0..3e3a7d7def 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/mariadb/[mariadbId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/mariadb/[mariadbId].tsx @@ -23,7 +23,7 @@ import { ContainerPaidMonitoring } from "@/components/dashboard/monitoring/paid/ import { ShowDatabaseAdvancedSettings } from "@/components/dashboard/shared/show-database-advanced-settings"; import { MariadbIcon } from "@/components/icons/data-tools-icons"; import { DashboardLayout } from "@/components/layouts/dashboard-layout"; -import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar"; +import { AdvanceBreadcrumb } from "@/components/shared/advance-breadcrumb"; import { StatusTooltip } from "@/components/shared/status-tooltip"; import { Badge } from "@/components/ui/badge"; import { @@ -78,22 +78,7 @@ const Mariadb = ( return ( <div className="pb-10"> <UseKeyboardNav forPage="mariadb" /> - <BreadcrumbSidebar - list={[ - { name: "Projects", href: "/dashboard/projects" }, - { - name: data?.environment?.project?.name || "", - href: `/dashboard/project/${projectId}/environment/${environmentId}`, - }, - { - name: data?.environment?.name || "", - dropdownItems: environmentDropdownItems, - }, - { - name: data?.name || "", - }, - ]} - /> + <AdvanceBreadcrumb /> <div className="flex flex-col gap-4"> <Head> <title> diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/mongo/[mongoId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/mongo/[mongoId].tsx index 3d72601d5d..ea64834994 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/mongo/[mongoId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/mongo/[mongoId].tsx @@ -23,7 +23,7 @@ import { ContainerPaidMonitoring } from "@/components/dashboard/monitoring/paid/ import { ShowDatabaseAdvancedSettings } from "@/components/dashboard/shared/show-database-advanced-settings"; import { MongodbIcon } from "@/components/icons/data-tools-icons"; import { DashboardLayout } from "@/components/layouts/dashboard-layout"; -import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar"; +import { AdvanceBreadcrumb } from "@/components/shared/advance-breadcrumb"; import { StatusTooltip } from "@/components/shared/status-tooltip"; import { Badge } from "@/components/ui/badge"; import { @@ -77,22 +77,7 @@ const Mongo = ( return ( <div className="pb-10"> <UseKeyboardNav forPage="mongodb" /> - <BreadcrumbSidebar - list={[ - { name: "Projects", href: "/dashboard/projects" }, - { - name: data?.environment?.project?.name || "", - href: `/dashboard/project/${projectId}/environment/${environmentId}`, - }, - { - name: data?.environment?.name || "", - dropdownItems: environmentDropdownItems, - }, - { - name: data?.name || "", - }, - ]} - /> + <AdvanceBreadcrumb /> <Head> <title> Database: {data?.name} - {data?.environment?.project?.name} |{" "} diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/mysql/[mysqlId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/mysql/[mysqlId].tsx index c04b689d77..ff45c06943 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/mysql/[mysqlId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/mysql/[mysqlId].tsx @@ -23,7 +23,7 @@ import { UpdateMysql } from "@/components/dashboard/mysql/update-mysql"; import { ShowDatabaseAdvancedSettings } from "@/components/dashboard/shared/show-database-advanced-settings"; import { MysqlIcon } from "@/components/icons/data-tools-icons"; import { DashboardLayout } from "@/components/layouts/dashboard-layout"; -import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar"; +import { AdvanceBreadcrumb } from "@/components/shared/advance-breadcrumb"; import { StatusTooltip } from "@/components/shared/status-tooltip"; import { Badge } from "@/components/ui/badge"; import { @@ -76,22 +76,7 @@ const MySql = ( return ( <div className="pb-10"> <UseKeyboardNav forPage="mysql" /> - <BreadcrumbSidebar - list={[ - { name: "Projects", href: "/dashboard/projects" }, - { - name: data?.environment?.project?.name || "", - href: `/dashboard/project/${projectId}/environment/${environmentId}`, - }, - { - name: data?.environment?.name || "", - dropdownItems: environmentDropdownItems, - }, - { - name: data?.name || "", - }, - ]} - /> + <AdvanceBreadcrumb /> <div className="flex flex-col gap-4"> <Head> <title> diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/postgres/[postgresId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/postgres/[postgresId].tsx index d697496e20..15e91a0bd7 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/postgres/[postgresId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/postgres/[postgresId].tsx @@ -23,7 +23,7 @@ import { UpdatePostgres } from "@/components/dashboard/postgres/update-postgres" import { ShowDatabaseAdvancedSettings } from "@/components/dashboard/shared/show-database-advanced-settings"; import { PostgresqlIcon } from "@/components/icons/data-tools-icons"; import { DashboardLayout } from "@/components/layouts/dashboard-layout"; -import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar"; +import { AdvanceBreadcrumb } from "@/components/shared/advance-breadcrumb"; import { StatusTooltip } from "@/components/shared/status-tooltip"; import { Badge } from "@/components/ui/badge"; import { @@ -76,22 +76,7 @@ const Postgresql = ( return ( <div className="pb-10"> <UseKeyboardNav forPage="postgres" /> - <BreadcrumbSidebar - list={[ - { name: "Projects", href: "/dashboard/projects" }, - { - name: data?.environment?.project?.name || "", - href: `/dashboard/project/${projectId}/environment/${environmentId}`, - }, - { - name: data?.environment?.name || "", - dropdownItems: environmentDropdownItems, - }, - { - name: data?.name || "", - }, - ]} - /> + <AdvanceBreadcrumb /> <Head> <title> Database: {data?.name} - {data?.environment?.project?.name} |{" "} diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/redis/[redisId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/redis/[redisId].tsx index b41337d16a..05a9e0c910 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/redis/[redisId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/redis/[redisId].tsx @@ -22,7 +22,7 @@ import { UpdateRedis } from "@/components/dashboard/redis/update-redis"; import { ShowDatabaseAdvancedSettings } from "@/components/dashboard/shared/show-database-advanced-settings"; import { RedisIcon } from "@/components/icons/data-tools-icons"; import { DashboardLayout } from "@/components/layouts/dashboard-layout"; -import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar"; +import { AdvanceBreadcrumb } from "@/components/shared/advance-breadcrumb"; import { StatusTooltip } from "@/components/shared/status-tooltip"; import { Badge } from "@/components/ui/badge"; import { @@ -76,22 +76,7 @@ const Redis = ( return ( <div className="pb-10"> <UseKeyboardNav forPage="redis" /> - <BreadcrumbSidebar - list={[ - { name: "Projects", href: "/dashboard/projects" }, - { - name: data?.environment?.project?.name || "", - href: `/dashboard/project/${projectId}/environment/${environmentId}`, - }, - { - name: data?.environment?.name || "", - dropdownItems: environmentDropdownItems, - }, - { - name: data?.name || "", - }, - ]} - /> + <AdvanceBreadcrumb /> <Head> <title> Database: {data?.name} - {data?.environment?.project?.name} |{" "} diff --git a/apps/dokploy/server/api/root.ts b/apps/dokploy/server/api/root.ts index 5f44e8446c..c9a782e037 100644 --- a/apps/dokploy/server/api/root.ts +++ b/apps/dokploy/server/api/root.ts @@ -23,15 +23,15 @@ import { mysqlRouter } from "./routers/mysql"; import { notificationRouter } from "./routers/notification"; import { organizationRouter } from "./routers/organization"; import { patchRouter } from "./routers/patch"; +import { portRouter } from "./routers/port"; +import { postgresRouter } from "./routers/postgres"; +import { previewDeploymentRouter } from "./routers/preview-deployment"; +import { projectRouter } from "./routers/project"; import { auditLogRouter } from "./routers/proprietary/audit-log"; import { customRoleRouter } from "./routers/proprietary/custom-role"; import { licenseKeyRouter } from "./routers/proprietary/license-key"; import { ssoRouter } from "./routers/proprietary/sso"; import { whitelabelingRouter } from "./routers/proprietary/whitelabeling"; -import { portRouter } from "./routers/port"; -import { postgresRouter } from "./routers/postgres"; -import { previewDeploymentRouter } from "./routers/preview-deployment"; -import { projectRouter } from "./routers/project"; import { redirectsRouter } from "./routers/redirects"; import { redisRouter } from "./routers/redis"; import { registryRouter } from "./routers/registry"; diff --git a/apps/dokploy/setup.ts b/apps/dokploy/setup.ts index dc0c0847f0..0f993e14a9 100644 --- a/apps/dokploy/setup.ts +++ b/apps/dokploy/setup.ts @@ -1,8 +1,9 @@ -import { exit } from "node:process"; import { exec } from "node:child_process"; +import { exit } from "node:process"; import { promisify } from "node:util"; const execAsync = promisify(exec); + import { setupDirectories } from "@dokploy/server/setup/config-paths"; import { initializePostgres } from "@dokploy/server/setup/postgres-setup"; import { initializeRedis } from "@dokploy/server/setup/redis-setup"; diff --git a/openapi.json b/openapi.json index 9a9df431f8..bab2a33471 100644 --- a/openapi.json +++ b/openapi.json @@ -48973,4 +48973,4 @@ "apiKey": [] } ] -} \ No newline at end of file +} diff --git a/packages/server/src/services/domain.ts b/packages/server/src/services/domain.ts index bc88ce1b64..e1460fd482 100644 --- a/packages/server/src/services/domain.ts +++ b/packages/server/src/services/domain.ts @@ -45,7 +45,7 @@ export const createDomain = async (input: z.infer<typeof apiCreateDomain>) => { export const generateTraefikMeDomain = async ( appName: string, - userId: string, + _userId: string, serverId?: string, ) => { if (serverId) { diff --git a/packages/server/src/services/preview-deployment.ts b/packages/server/src/services/preview-deployment.ts index 199345828f..b21a53a5c3 100644 --- a/packages/server/src/services/preview-deployment.ts +++ b/packages/server/src/services/preview-deployment.ts @@ -236,7 +236,7 @@ const generateWildcardDomain = async ( baseDomain: string, appName: string, serverIp: string, - userId: string, + _userId: string, ): Promise<string> => { if (!baseDomain.startsWith("*.")) { throw new Error('The base domain must start with "*."');