import { useState } from "react"; import { useMutation, useQuery } from "@tanstack/react-query"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog"; import { FolderOpen, Trash2 } from "lucide-react"; import { apiRequest, queryClient } from "@/lib/queryClient"; import { useToast } from "@/hooks/use-toast"; export function BackupDestinationManager() { const { toast } = useToast(); const [path, setPath] = useState(""); const [deleteId, setDeleteId] = useState(null); // ============================== // Queries // ============================== const { data: destinations = [] } = useQuery({ queryKey: ["/db/destination"], queryFn: async () => { const res = await apiRequest( "GET", "/api/database-management/destination" ); return res.json(); }, }); // ============================== // Mutations // ============================== const saveMutation = useMutation({ mutationFn: async () => { const res = await apiRequest( "POST", "/api/database-management/destination", { path } ); if (!res.ok) throw new Error((await res.json()).error); }, onSuccess: () => { toast({ title: "Backup destination saved" }); setPath(""); queryClient.invalidateQueries({ queryKey: ["/db/destination"] }); }, }); const deleteMutation = useMutation({ mutationFn: async (id: number) => { await apiRequest("DELETE", `/api/database-management/destination/${id}`); }, onSuccess: () => { toast({ title: "Backup destination deleted" }); queryClient.invalidateQueries({ queryKey: ["/db/destination"] }); setDeleteId(null); }, }); // ============================== // Folder picker (browser limitation) // ============================== const openFolderPicker = async () => { // @ts-ignore if (!window.showDirectoryPicker) { toast({ title: "Not supported", description: "Your browser does not support folder picking", variant: "destructive", }); return; } try { // @ts-ignore const dirHandle = await window.showDirectoryPicker(); toast({ title: "Folder selected", description: `Selected folder: ${dirHandle.name}. Please enter the full path manually.`, }); } catch { // user cancelled } }; // ============================== // UI // ============================== return ( External Backup Destination
setPath(e.target.value)} />
{destinations.map((d: any) => (
{d.path}
))}
{/* Confirm delete dialog */} Delete backup destination? This will remove the destination and stop automatic backups. setDeleteId(null)}> Cancel deleteId && deleteMutation.mutate(deleteId)} > Delete
); }