added frontent viewer for snapshot
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
import { File, Folder } from 'lucide-react';
|
||||
|
||||
export function SnapshotFilesPanel({ files, loading, onClose, snapshot }) {
|
||||
if (!snapshot) return null;
|
||||
|
||||
return (
|
||||
<section className="overflow-hidden rounded-md border border-zinc-800 bg-zinc-900/70">
|
||||
<div className="flex items-center justify-between gap-3 border-b border-zinc-800 px-4 py-3">
|
||||
<div>
|
||||
<h2 className="text-sm font-semibold">Snapshot Contents</h2>
|
||||
<p className="mt-1 font-mono text-xs text-zinc-500">{snapshot.id.slice(0, 8)}</p>
|
||||
</div>
|
||||
<button
|
||||
className="h-8 rounded-md border border-zinc-700 px-2.5 text-xs text-zinc-100 hover:border-zinc-500"
|
||||
onClick={onClose}
|
||||
type="button"
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full min-w-[680px] text-left text-sm">
|
||||
<thead className="border-b border-zinc-800 text-xs uppercase tracking-wide text-zinc-500">
|
||||
<tr>
|
||||
<th className="px-4 py-3 font-medium">Path</th>
|
||||
<th className="px-4 py-3 font-medium">Type</th>
|
||||
<th className="px-4 py-3 font-medium">Size</th>
|
||||
<th className="px-4 py-3 font-medium">Modified</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-zinc-800">
|
||||
{files.map((entry) => (
|
||||
<tr key={`${entry.type}:${entry.path}`}>
|
||||
<td className="px-4 py-3">
|
||||
<span className="inline-flex items-center gap-2 font-mono text-zinc-100">
|
||||
{entry.type === 'dir' ? <Folder className="h-4 w-4 text-cyan-300" /> : <File className="h-4 w-4 text-zinc-400" />}
|
||||
{entry.path}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-4 py-3 text-zinc-300">{entry.type}</td>
|
||||
<td className="px-4 py-3 text-zinc-300">{entry.type === 'dir' ? '-' : formatBytes(entry.size)}</td>
|
||||
<td className="px-4 py-3 text-zinc-300">{formatTime(entry.mtime)}</td>
|
||||
</tr>
|
||||
))}
|
||||
{!files.length ? (
|
||||
<tr>
|
||||
<td className="px-4 py-8 text-center text-zinc-500" colSpan="4">
|
||||
{loading ? 'Loading snapshot contents...' : 'No files found.'}
|
||||
</td>
|
||||
</tr>
|
||||
) : null}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
function formatBytes(value) {
|
||||
if (!value) return '0 B';
|
||||
const units = ['B', 'KiB', 'MiB', 'GiB', 'TiB'];
|
||||
let size = Number(value);
|
||||
let unitIndex = 0;
|
||||
while (size >= 1024 && unitIndex < units.length - 1) {
|
||||
size /= 1024;
|
||||
unitIndex += 1;
|
||||
}
|
||||
return `${size.toFixed(unitIndex === 0 ? 0 : 1)} ${units[unitIndex]}`;
|
||||
}
|
||||
|
||||
function formatTime(value) {
|
||||
if (!value) return '-';
|
||||
return new Intl.DateTimeFormat(undefined, { dateStyle: 'medium', timeStyle: 'medium' }).format(new Date(value));
|
||||
}
|
||||
Reference in New Issue
Block a user