import type { findEnvironmentsByProjectId } from "@dokploy/server"; import { ChevronDownIcon, PencilIcon, PlusIcon, TrashIcon } from "lucide-react"; import { useRouter } from "next/router"; import { useState } from "react"; import { toast } from "sonner"; import { AlertBlock } from "@/components/shared/alert-block"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { api } from "@/utils/api"; type Environment = Awaited< ReturnType >[number]; interface AdvancedEnvironmentSelectorProps { projectId: string; currentEnvironmentId?: string; } export const AdvancedEnvironmentSelector = ({ projectId, currentEnvironmentId, }: AdvancedEnvironmentSelectorProps) => { const router = useRouter(); const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false); const [isEditDialogOpen, setIsEditDialogOpen] = useState(false); const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false); const [selectedEnvironment, setSelectedEnvironment] = useState(null); const { data: environments } = api.environment.byProjectId.useQuery( { projectId: projectId }, { enabled: !!projectId, }, ); // Form states const [name, setName] = useState(""); const [description, setDescription] = useState(""); // Get current user's permissions const { data: permissions } = api.user.getPermissions.useQuery(); // Check if user can create environments const canCreateEnvironments = !!permissions?.environment.create; // Check if user can delete environments const canDeleteEnvironments = !!permissions?.environment.delete; const haveServices = selectedEnvironment && ((selectedEnvironment?.mariadb?.length || 0) > 0 || (selectedEnvironment?.mongo?.length || 0) > 0 || (selectedEnvironment?.mysql?.length || 0) > 0 || (selectedEnvironment?.postgres?.length || 0) > 0 || (selectedEnvironment?.redis?.length || 0) > 0 || (selectedEnvironment?.applications?.length || 0) > 0 || (selectedEnvironment?.compose?.length || 0) > 0); const createEnvironment = api.environment.create.useMutation(); const updateEnvironment = api.environment.update.useMutation(); const deleteEnvironment = api.environment.remove.useMutation(); const duplicateEnvironment = api.environment.duplicate.useMutation(); // Refetch project data const utils = api.useUtils(); const handleCreateEnvironment = async () => { try { await createEnvironment.mutateAsync({ projectId, name: name.trim(), description: description.trim() || undefined, }); toast.success("Environment created successfully"); utils.environment.byProjectId.invalidate({ projectId }); // Invalidate the project query to refresh the project data for the advance-breadcrumb utils.project.all.invalidate(); setIsCreateDialogOpen(false); setName(""); setDescription(""); } catch (error) { toast.error( `Failed to create environment: ${error instanceof Error ? error.message : error}`, ); } }; const handleUpdateEnvironment = async () => { if (!selectedEnvironment) return; try { await updateEnvironment.mutateAsync({ environmentId: selectedEnvironment.environmentId, name: name.trim(), description: description.trim() || undefined, }); toast.success("Environment updated successfully"); utils.environment.byProjectId.invalidate({ projectId }); setIsEditDialogOpen(false); setSelectedEnvironment(null); setName(""); setDescription(""); } catch (error) { toast.error( `Failed to update environment: ${error instanceof Error ? error.message : error}`, ); } }; const handleDeleteEnvironment = async () => { if (!selectedEnvironment) return; try { await deleteEnvironment.mutateAsync({ environmentId: selectedEnvironment.environmentId, }); toast.success("Environment deleted successfully"); utils.environment.byProjectId.invalidate({ projectId }); setIsDeleteDialogOpen(false); setSelectedEnvironment(null); // Redirect to first available environment if we deleted the current environment if (selectedEnvironment.environmentId === currentEnvironmentId) { const firstEnv = environments?.find( (env) => env.environmentId !== selectedEnvironment.environmentId, ); if (firstEnv) { router.push( `/dashboard/project/${projectId}/environment/${firstEnv.environmentId}`, ); } else { // No other environments, redirect to project page router.push(`/dashboard/project/${projectId}`); } } } catch (error) { toast.error("Failed to delete environment"); } }; const handleDuplicateEnvironment = async (environment: Environment) => { try { const result = await duplicateEnvironment.mutateAsync({ environmentId: environment.environmentId, name: `${environment.name}-copy`, description: environment.description || undefined, }); toast.success("Environment duplicated successfully"); utils.project.one.invalidate({ projectId }); // Navigate to the new duplicated environment router.push( `/dashboard/project/${projectId}/environment/${result.environmentId}`, ); } catch (error) { toast.error("Failed to duplicate environment"); } }; const openEditDialog = (environment: Environment) => { setSelectedEnvironment(environment); setName(environment.name); setDescription(environment.description || ""); setIsEditDialogOpen(true); }; const openDeleteDialog = (environment: Environment) => { setSelectedEnvironment(environment); setIsDeleteDialogOpen(true); }; const currentEnv = environments?.find( (env) => env.environmentId === currentEnvironmentId, ); return ( <> Environments {environments?.map((environment) => { const servicesCount = environment.mariadb.length + environment.mongo.length + environment.mysql.length + environment.postgres.length + environment.redis.length + environment.applications.length + environment.compose.length; return (
{ router.push( `/dashboard/project/${projectId}/environment/${environment.environmentId}`, ); }} >
{environment.name} ({servicesCount}) {environment.environmentId === currentEnvironmentId && (
)}
{!environment.isDefault && ( )} {canDeleteEnvironments && !environment.isDefault && ( )}
); })} {canCreateEnvironments && ( setIsCreateDialogOpen(true)} > Create Environment )} Create Environment Create a new environment for your project.
setName(e.target.value)} placeholder="Environment name" />