mirror of
https://github.com/nicotsx/ironmount.git
synced 2025-12-10 12:10:51 +01:00
96 lines
2.6 KiB
TypeScript
96 lines
2.6 KiB
TypeScript
import { useMutation } from "@tanstack/react-query";
|
|
import { RotateCcw } from "lucide-react";
|
|
import { useId, useState } from "react";
|
|
import { toast } from "sonner";
|
|
import { restoreSnapshotMutation } from "~/api-client/@tanstack/react-query.gen";
|
|
import { parseError } from "~/lib/errors";
|
|
import { Button } from "~/components/ui/button";
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogFooter,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
DialogTrigger,
|
|
} from "~/components/ui/dialog";
|
|
import { ScrollArea } from "~/components/ui/scroll-area";
|
|
import { RestoreSnapshotForm, type RestoreSnapshotFormValues } from "./restore-snapshot-form";
|
|
|
|
type Props = {
|
|
name: string;
|
|
snapshotId: string;
|
|
};
|
|
|
|
export const RestoreSnapshotDialog = ({ name, snapshotId }: Props) => {
|
|
const [open, setOpen] = useState(false);
|
|
const formId = useId();
|
|
|
|
const restore = useMutation({
|
|
...restoreSnapshotMutation(),
|
|
onSuccess: (data) => {
|
|
toast.success("Snapshot restored successfully", {
|
|
description: `${data.filesRestored} files restored, ${data.filesSkipped} files skipped`,
|
|
});
|
|
setOpen(false);
|
|
},
|
|
onError: (error) => {
|
|
toast.error("Failed to restore snapshot", {
|
|
description: parseError(error)?.message,
|
|
});
|
|
},
|
|
});
|
|
|
|
const handleSubmit = (values: RestoreSnapshotFormValues) => {
|
|
const include = values.include
|
|
?.split(",")
|
|
.map((s) => s.trim())
|
|
.filter(Boolean);
|
|
|
|
const exclude = values.exclude
|
|
?.split(",")
|
|
.map((s) => s.trim())
|
|
.filter(Boolean);
|
|
|
|
restore.mutate({
|
|
path: { name },
|
|
body: {
|
|
snapshotId,
|
|
path: values.path || undefined,
|
|
include: include && include.length > 0 ? include : undefined,
|
|
exclude: exclude && exclude.length > 0 ? exclude : undefined,
|
|
},
|
|
});
|
|
};
|
|
|
|
return (
|
|
<Dialog open={open} onOpenChange={setOpen}>
|
|
<DialogTrigger asChild>
|
|
<Button>
|
|
<RotateCcw size={16} className="mr-2" />
|
|
Restore
|
|
</Button>
|
|
</DialogTrigger>
|
|
<DialogContent>
|
|
<ScrollArea className="max-h-[600px] p-4">
|
|
<DialogHeader>
|
|
<DialogTitle>Restore Snapshot</DialogTitle>
|
|
<DialogDescription>
|
|
Restore snapshot {snapshotId.substring(0, 8)} to a local filesystem path
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
<RestoreSnapshotForm className="mt-4" formId={formId} onSubmit={handleSubmit} />
|
|
<DialogFooter className="mt-4">
|
|
<Button type="button" variant="secondary" onClick={() => setOpen(false)}>
|
|
Cancel
|
|
</Button>
|
|
<Button type="submit" form={formId} disabled={restore.isPending}>
|
|
{restore.isPending ? "Restoring..." : "Restore"}
|
|
</Button>
|
|
</DialogFooter>
|
|
</ScrollArea>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
};
|