diff --git a/apps/client/app/modules/backups/components/schedule-summary.tsx b/apps/client/app/modules/backups/components/schedule-summary.tsx index ad41b49..d0899e9 100644 --- a/apps/client/app/modules/backups/components/schedule-summary.tsx +++ b/apps/client/app/modules/backups/components/schedule-summary.tsx @@ -1,12 +1,21 @@ import { useQuery } from "@tanstack/react-query"; -import { Database, Pencil, Play } from "lucide-react"; -import { useMemo } from "react"; +import { Database, Pencil, Play, Trash2 } from "lucide-react"; +import { useMemo, useState } from "react"; import { listSnapshotsOptions } from "~/api-client/@tanstack/react-query.gen"; import { ByteSize } from "~/components/bytes-size"; import { OnOff } from "~/components/onoff"; import { SnapshotsTable } from "~/components/snapshots-table"; import { Button } from "~/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/components/ui/card"; +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogHeader, + AlertDialogTitle, +} from "~/components/ui/alert-dialog"; import type { BackupSchedule, Repository, Volume } from "~/lib/types"; type Props = { @@ -15,11 +24,23 @@ type Props = { repository: Repository; handleToggleEnabled: (enabled: boolean) => void; handleRunBackupNow: () => void; + handleDeleteSchedule: () => void; setIsEditMode: (isEdit: boolean) => void; + isDeleting?: boolean; }; export const ScheduleSummary = (props: Props) => { - const { volume, schedule, repository, handleToggleEnabled, handleRunBackupNow, setIsEditMode } = props; + const { + volume, + schedule, + repository, + handleToggleEnabled, + handleRunBackupNow, + handleDeleteSchedule, + setIsEditMode, + isDeleting, + } = props; + const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); const { data: snapshots, isLoading: loadingSnapshots } = useQuery({ ...listSnapshotsOptions({ @@ -52,6 +73,11 @@ export const ScheduleSummary = (props: Props) => { }; }, [schedule, volume.name]); + const handleConfirmDelete = () => { + setShowDeleteConfirm(false); + handleDeleteSchedule(); + }; + return (
@@ -72,6 +98,16 @@ export const ScheduleSummary = (props: Props) => { Edit schedule +
@@ -107,6 +143,27 @@ export const ScheduleSummary = (props: Props) => { + + + + Delete backup schedule? + + Are you sure you want to delete this backup schedule for {volume.name}? This action + cannot be undone. Existing snapshots will not be deleted. + + +
+ Cancel + + Delete schedule + +
+
+
+
diff --git a/apps/client/app/modules/backups/routes/backup-details.tsx b/apps/client/app/modules/backups/routes/backup-details.tsx index 182c7a0..f610409 100644 --- a/apps/client/app/modules/backups/routes/backup-details.tsx +++ b/apps/client/app/modules/backups/routes/backup-details.tsx @@ -1,6 +1,6 @@ import { useId, useState } from "react"; import { useQuery, useMutation } from "@tanstack/react-query"; -import { Link, useParams } from "react-router"; +import { Link, useParams, useNavigate } from "react-router"; import { toast } from "sonner"; import { Button } from "~/components/ui/button"; import { Card, CardContent } from "~/components/ui/card"; @@ -8,6 +8,7 @@ import { upsertBackupScheduleMutation, getBackupScheduleOptions, runBackupNowMutation, + deleteBackupScheduleMutation, } from "~/api-client/@tanstack/react-query.gen"; import { parseError } from "~/lib/errors"; import { getCronExpression } from "~/utils/utils"; @@ -15,6 +16,7 @@ import { CreateScheduleForm, type BackupScheduleFormValues } from "../components import { ScheduleSummary } from "../components/schedule-summary"; export default function ScheduleDetailsPage() { + const navigate = useNavigate(); const { id } = useParams<{ id: string }>(); const [isEditMode, setIsEditMode] = useState(false); const formId = useId(); @@ -52,6 +54,19 @@ export default function ScheduleDetailsPage() { }, }); + const deleteSchedule = useMutation({ + ...deleteBackupScheduleMutation(), + onSuccess: () => { + toast.success("Backup schedule deleted successfully"); + navigate("/backups"); + }, + onError: (error) => { + toast.error("Failed to delete backup schedule", { + description: parseError(error)?.message, + }); + }, + }); + const handleSubmit = (formValues: BackupScheduleFormValues) => { if (!schedule) return; @@ -100,6 +115,12 @@ export default function ScheduleDetailsPage() { }); }; + const handleDeleteSchedule = () => { + if (!schedule) return; + + deleteSchedule.mutate({ path: { scheduleId: schedule.id.toString() } }); + }; + if (loadingSchedule && !schedule) { return (
@@ -130,10 +151,12 @@ export default function ScheduleDetailsPage() { ); }