feat: delete backup schedule

This commit is contained in:
Nicolas Meienberger
2025-11-02 16:52:25 +01:00
parent 44917f3513
commit c2041932b5
2 changed files with 84 additions and 4 deletions

View File

@@ -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 (
<div className="space-y-4">
<Card>
@@ -72,6 +98,16 @@ export const ScheduleSummary = (props: Props) => {
<Pencil className="h-4 w-4 mr-2" />
Edit schedule
</Button>
<Button
variant="outline"
size="sm"
onClick={() => setShowDeleteConfirm(true)}
disabled={isDeleting}
className="text-destructive hover:text-destructive"
>
<Trash2 className="h-4 w-4 mr-2" />
Delete
</Button>
</div>
</CardHeader>
<CardContent className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
@@ -107,6 +143,27 @@ export const ScheduleSummary = (props: Props) => {
</CardContent>
</Card>
<AlertDialog open={showDeleteConfirm} onOpenChange={setShowDeleteConfirm}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Delete backup schedule?</AlertDialogTitle>
<AlertDialogDescription>
Are you sure you want to delete this backup schedule for <strong>{volume.name}</strong>? This action
cannot be undone. Existing snapshots will not be deleted.
</AlertDialogDescription>
</AlertDialogHeader>
<div className="flex gap-3 justify-end">
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction
onClick={handleConfirmDelete}
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
>
Delete schedule
</AlertDialogAction>
</div>
</AlertDialogContent>
</AlertDialog>
<Card className="p-0 gap-0">
<CardHeader className="p-4 bg-card-header">
<div className="flex flex-col lg:flex-row items-stretch lg:items-center gap-4 justify-between">

View File

@@ -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 (
<div className="container mx-auto p-4 sm:p-8">
@@ -130,10 +151,12 @@ export default function ScheduleDetailsPage() {
<ScheduleSummary
handleToggleEnabled={handleToggleEnabled}
handleRunBackupNow={handleRunBackupNow}
handleDeleteSchedule={handleDeleteSchedule}
repository={schedule.repository}
setIsEditMode={setIsEditMode}
schedule={schedule}
volume={schedule.volume}
isDeleting={deleteSchedule.isPending}
/>
);
}