From 7dda252b7cfc97b8885864056e9417ce99aa142e Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 8 Mar 2025 18:43:37 -0600 Subject: [PATCH] feat(services): add bulk delete functionality for services - Implement bulk delete feature for applications, compose, and various database services - Add delete mutation endpoints for each service type - Provide user-friendly bulk delete action with error handling and success notifications - Integrate Trash2 icon for delete action in bulk service management --- .../pages/dashboard/project/[projectId].tsx | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/apps/dokploy/pages/dashboard/project/[projectId].tsx b/apps/dokploy/pages/dashboard/project/[projectId].tsx index 2f550dba..cf0a5f99 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId].tsx @@ -65,6 +65,7 @@ import { PlusIcon, Search, X, + Trash2, } from "lucide-react"; import type { GetServerSidePropsContext, @@ -276,30 +277,37 @@ const Project = ( start: api.compose.start.useMutation(), stop: api.compose.stop.useMutation(), move: api.compose.move.useMutation(), + delete: api.compose.delete.useMutation(), }; const applicationActions = { move: api.application.move.useMutation(), + delete: api.application.delete.useMutation(), }; const postgresActions = { move: api.postgres.move.useMutation(), + delete: api.postgres.remove.useMutation(), }; const mysqlActions = { move: api.mysql.move.useMutation(), + delete: api.mysql.remove.useMutation(), }; const mariadbActions = { move: api.mariadb.move.useMutation(), + delete: api.mariadb.remove.useMutation(), }; const redisActions = { move: api.redis.move.useMutation(), + delete: api.redis.remove.useMutation(), }; const mongoActions = { move: api.mongo.move.useMutation(), + delete: api.mongo.remove.useMutation(), }; const handleBulkStart = async () => { @@ -416,6 +424,68 @@ const Project = ( setIsBulkActionLoading(false); }; + const handleBulkDelete = async () => { + let success = 0; + setIsBulkActionLoading(true); + for (const serviceId of selectedServices) { + try { + const service = filteredServices.find((s) => s.id === serviceId); + if (!service) continue; + + switch (service.type) { + case "application": + await applicationActions.delete.mutateAsync({ + applicationId: serviceId, + }); + break; + case "compose": + await composeActions.delete.mutateAsync({ + composeId: serviceId, + deleteVolumes: false, + }); + break; + case "postgres": + await postgresActions.delete.mutateAsync({ + postgresId: serviceId, + }); + break; + case "mysql": + await mysqlActions.delete.mutateAsync({ + mysqlId: serviceId, + }); + break; + case "mariadb": + await mariadbActions.delete.mutateAsync({ + mariadbId: serviceId, + }); + break; + case "redis": + await redisActions.delete.mutateAsync({ + redisId: serviceId, + }); + break; + case "mongo": + await mongoActions.delete.mutateAsync({ + mongoId: serviceId, + }); + break; + } + success++; + } catch (error) { + toast.error( + `Error deleting service ${serviceId}: ${error instanceof Error ? error.message : "Unknown error"}`, + ); + } + } + if (success > 0) { + toast.success(`${success} services deleted successfully`); + refetch(); + } + setSelectedServices([]); + setIsDropdownOpen(false); + setIsBulkActionLoading(false); + }; + const filteredServices = useMemo(() => { if (!applications) return []; return applications.filter( @@ -565,6 +635,20 @@ const Project = ( Stop + + +