import { useMutation, useSuspenseQuery } from "@tanstack/react-query"; import { Database } from "lucide-react"; import { useState } from "react"; import { toast } from "sonner"; import { getRepositoryOptions, updateRepositoryMutation } from "~/client/api-client/@tanstack/react-query.gen"; import { CreateRepositoryForm, formSchema, type RepositoryFormValues, } from "~/client/modules/repositories/components/create-repository-form"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "~/client/components/ui/alert-dialog"; import { Button } from "~/client/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "~/client/components/ui/card"; import { parseError } from "~/client/lib/errors"; import { Alert, AlertDescription } from "~/client/components/ui/alert"; import type { RepositoryConfig } from "@zerobyte/core/restic"; import { useNavigate } from "@tanstack/react-router"; import { ManagedBadge } from "~/client/components/managed-badge"; const riskyLocationFieldsByBackend = { local: ["path"], s3: ["endpoint", "bucket"], r2: ["endpoint", "bucket"], gcs: ["bucket", "projectId"], azure: ["container", "accountName", "endpointSuffix"], rest: ["url", "path"], sftp: ["host", "port", "path", "user"], rclone: ["remote", "path"], } as const; const hasRiskyLocationChange = (initialConfig: RepositoryConfig, nextConfig: RepositoryConfig): boolean => { const fields = riskyLocationFieldsByBackend[initialConfig.backend] ?? []; return fields.some( (field) => initialConfig[field as keyof RepositoryConfig] !== nextConfig[field as keyof RepositoryConfig], ); }; export function EditRepositoryPage({ repositoryId }: { repositoryId: string }) { const navigate = useNavigate(); const [showRiskConfirm, setShowRiskConfirm] = useState(false); const [pendingValues, setPendingValues] = useState(null); const { data: repository } = useSuspenseQuery({ ...getRepositoryOptions({ path: { shortId: repositoryId } }), }); const updateRepository = useMutation({ ...updateRepositoryMutation(), onSuccess: async (data) => { toast.success("Repository updated successfully"); setShowRiskConfirm(false); setPendingValues(null); void navigate({ to: `/repositories/${data.shortId}` }); }, onError: (error) => { toast.error("Failed to update repository", { description: parseError(error)?.message, }); }, }); const initialConfig = repository.config as RepositoryConfig; const initialValues: RepositoryFormValues = { ...initialConfig, name: repository.name, compressionMode: repository.compressionMode ?? "auto", }; const submitUpdate = (values: RepositoryFormValues) => { const { name, compressionMode, ...config } = formSchema.parse(values); updateRepository.mutate({ path: { shortId: repositoryId }, body: { name, compressionMode, config, }, }); }; const handleSubmit = (values: RepositoryFormValues) => { const { name: _name, compressionMode: _compressionMode, ...nextConfig } = formSchema.parse(values); if (hasRiskyLocationChange(initialConfig, nextConfig)) { setPendingValues(values); setShowRiskConfirm(true); return; } submitUpdate(values); }; const handleSaveAnyway = () => { if (!pendingValues) { return; } submitUpdate(pendingValues); }; const handleRiskConfirmOpenChange = (open: boolean) => { setShowRiskConfirm(open); if (!open) { setPendingValues(null); } }; return ( <>
Edit Repository {repository.provisioningId && }
{updateRepository.isError && ( Failed to update repository:
{parseError(updateRepository.error)?.message}
)}
Repository location changed Changing endpoint, bucket, host, or path fields may point to a different repository location. Before saving, ensure the repository already exists at the new target. Cancel Save anyway ); }