mirror of
https://github.com/nicotsx/zerobyte.git
synced 2026-06-04 14:43:52 -04:00
92 lines
3.1 KiB
TypeScript
92 lines
3.1 KiB
TypeScript
import { RotateCcw, Trash2 } from "lucide-react";
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/client/components/ui/card";
|
|
import { Button, buttonVariants } from "~/client/components/ui/button";
|
|
import type { Snapshot } from "~/client/lib/types";
|
|
import { useTimeFormat } from "~/client/lib/datetime";
|
|
import { cn } from "~/client/lib/utils";
|
|
import { Link } from "@tanstack/react-router";
|
|
import { SnapshotTreeBrowser } from "~/client/components/file-browsers/snapshot-tree-browser";
|
|
import { findCommonAncestor } from "@zerobyte/core/utils";
|
|
|
|
interface Props {
|
|
snapshot: Snapshot;
|
|
repositoryId: string;
|
|
backupId?: string;
|
|
displayBasePath?: string;
|
|
onDeleteSnapshot?: (snapshotId: string) => void;
|
|
isDeletingSnapshot?: boolean;
|
|
}
|
|
|
|
const treeProps = {
|
|
pageSize: 500,
|
|
className: "flex flex-1 min-h-0 flex-col",
|
|
treeContainerClassName: "overflow-auto flex-1 min-h-0 border border-border rounded-md bg-card m-4",
|
|
treeClassName: "px-2 py-2",
|
|
emptyMessage: "No files in this snapshot",
|
|
stateClassName: "flex-1 min-h-0",
|
|
} as const;
|
|
|
|
export const SnapshotFileBrowser = (props: Props) => {
|
|
const { snapshot, repositoryId, backupId, displayBasePath, onDeleteSnapshot, isDeletingSnapshot } = props;
|
|
const { formatDateTime } = useTimeFormat();
|
|
|
|
const hasNonPosixSnapshotPaths = snapshot.paths.some((path) => !path.startsWith("/"));
|
|
const queryBasePath = hasNonPosixSnapshotPaths ? "/" : findCommonAncestor(snapshot.paths);
|
|
|
|
return (
|
|
<div className="space-y-4">
|
|
<Card className="h-150 flex flex-col">
|
|
<CardHeader>
|
|
<div className="flex flex-col sm:flex-row sm:items-start sm:justify-between gap-4">
|
|
<div>
|
|
<CardTitle>File Browser</CardTitle>
|
|
<CardDescription
|
|
className={cn({ hidden: !snapshot.time })}
|
|
>{`Viewing snapshot from ${formatDateTime(snapshot?.time)}`}</CardDescription>
|
|
</div>
|
|
<div className="flex gap-2 flex-wrap sm:flex-nowrap">
|
|
<Link
|
|
to={
|
|
backupId
|
|
? "/backups/$backupId/$snapshotId/restore"
|
|
: "/repositories/$repositoryId/$snapshotId/restore"
|
|
}
|
|
params={
|
|
backupId
|
|
? { backupId, snapshotId: snapshot.short_id }
|
|
: { repositoryId: repositoryId, snapshotId: snapshot.short_id }
|
|
}
|
|
className={buttonVariants({ variant: "primary", size: "sm" })}
|
|
>
|
|
<RotateCcw className="h-4 w-4" />
|
|
Restore
|
|
</Link>
|
|
{onDeleteSnapshot && (
|
|
<Button
|
|
variant="destructive"
|
|
size="sm"
|
|
onClick={() => onDeleteSnapshot(snapshot.short_id)}
|
|
disabled={isDeletingSnapshot}
|
|
loading={isDeletingSnapshot}
|
|
>
|
|
<Trash2 className="h-4 w-4 mr-2" />
|
|
{isDeletingSnapshot ? "Deleting..." : "Delete Snapshot"}
|
|
</Button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</CardHeader>
|
|
<CardContent className="flex-1 overflow-hidden flex flex-col p-0">
|
|
<SnapshotTreeBrowser
|
|
repositoryId={repositoryId}
|
|
snapshotId={snapshot.short_id}
|
|
queryBasePath={queryBasePath}
|
|
displayBasePath={displayBasePath}
|
|
{...treeProps}
|
|
/>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
);
|
|
};
|