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
This commit is contained in:
Mauricio Siu 2025-03-08 18:43:37 -06:00
parent bf0668c319
commit 7dda252b7c

View File

@ -65,6 +65,7 @@ import {
PlusIcon, PlusIcon,
Search, Search,
X, X,
Trash2,
} from "lucide-react"; } from "lucide-react";
import type { import type {
GetServerSidePropsContext, GetServerSidePropsContext,
@ -276,30 +277,37 @@ const Project = (
start: api.compose.start.useMutation(), start: api.compose.start.useMutation(),
stop: api.compose.stop.useMutation(), stop: api.compose.stop.useMutation(),
move: api.compose.move.useMutation(), move: api.compose.move.useMutation(),
delete: api.compose.delete.useMutation(),
}; };
const applicationActions = { const applicationActions = {
move: api.application.move.useMutation(), move: api.application.move.useMutation(),
delete: api.application.delete.useMutation(),
}; };
const postgresActions = { const postgresActions = {
move: api.postgres.move.useMutation(), move: api.postgres.move.useMutation(),
delete: api.postgres.remove.useMutation(),
}; };
const mysqlActions = { const mysqlActions = {
move: api.mysql.move.useMutation(), move: api.mysql.move.useMutation(),
delete: api.mysql.remove.useMutation(),
}; };
const mariadbActions = { const mariadbActions = {
move: api.mariadb.move.useMutation(), move: api.mariadb.move.useMutation(),
delete: api.mariadb.remove.useMutation(),
}; };
const redisActions = { const redisActions = {
move: api.redis.move.useMutation(), move: api.redis.move.useMutation(),
delete: api.redis.remove.useMutation(),
}; };
const mongoActions = { const mongoActions = {
move: api.mongo.move.useMutation(), move: api.mongo.move.useMutation(),
delete: api.mongo.remove.useMutation(),
}; };
const handleBulkStart = async () => { const handleBulkStart = async () => {
@ -416,6 +424,68 @@ const Project = (
setIsBulkActionLoading(false); 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(() => { const filteredServices = useMemo(() => {
if (!applications) return []; if (!applications) return [];
return applications.filter( return applications.filter(
@ -565,6 +635,20 @@ const Project = (
Stop Stop
</Button> </Button>
</DialogAction> </DialogAction>
<DialogAction
title="Delete Services"
description={`Are you sure you want to delete ${selectedServices.length} services? This action cannot be undone.`}
type="destructive"
onClick={handleBulkDelete}
>
<Button
variant="ghost"
className="w-full justify-start text-destructive"
>
<Trash2 className="mr-2 h-4 w-4" />
Delete
</Button>
</DialogAction>
<Dialog <Dialog
open={isMoveDialogOpen} open={isMoveDialogOpen}
onOpenChange={setIsMoveDialogOpen} onOpenChange={setIsMoveDialogOpen}