added keep_hourly

This commit is contained in:
Philipp
2026-05-21 09:17:51 +02:00
parent 4af9f32c46
commit 15c4dd9a8b
7 changed files with 87 additions and 14 deletions
+20 -10
View File
@@ -1,6 +1,6 @@
import { RotateCcw } from 'lucide-react';
import { Eye, RotateCcw } from 'lucide-react';
export function SnapshotTable({ onRestore, snapshots }) {
export function SnapshotTable({ onInspect, onRestore, snapshots }) {
return (
<section className="overflow-hidden rounded-md border border-zinc-800 bg-zinc-900/70">
<div className="border-b border-zinc-800 px-4 py-3">
@@ -23,14 +23,24 @@ export function SnapshotTable({ onRestore, snapshots }) {
<td className="px-4 py-3 text-zinc-300">{formatTime(snapshot.time)}</td>
<td className="px-4 py-3 text-zinc-400">{(snapshot.tags || []).join(', ') || '-'}</td>
<td className="px-4 py-3 text-right">
<button
className="inline-flex h-8 items-center gap-2 rounded-md border border-red-900 px-2.5 text-xs text-red-300 hover:border-red-600 hover:text-red-200"
onClick={() => onRestore(snapshot)}
type="button"
>
<RotateCcw className="h-4 w-4" />
Restore
</button>
<div className="inline-flex items-center gap-2">
<button
className="inline-flex h-8 items-center gap-2 rounded-md border border-zinc-700 px-2.5 text-xs text-zinc-100 hover:border-cyan-500 hover:text-cyan-200"
onClick={() => onInspect(snapshot)}
type="button"
>
<Eye className="h-4 w-4" />
View
</button>
<button
className="inline-flex h-8 items-center gap-2 rounded-md border border-red-900 px-2.5 text-xs text-red-300 hover:border-red-600 hover:text-red-200"
onClick={() => onRestore(snapshot)}
type="button"
>
<RotateCcw className="h-4 w-4" />
Restore
</button>
</div>
</td>
</tr>
))}
+33 -1
View File
@@ -3,11 +3,15 @@ import { useEffect, useMemo, useState } from 'react';
import { api, errorMessage } from '../api.js';
import { JobStatusPanel } from './JobStatusPanel.jsx';
import { RestoreModal } from './RestoreModal.jsx';
import { SnapshotFilesPanel } from './SnapshotFilesPanel.jsx';
import { SnapshotTable } from './SnapshotTable.jsx';
export function VMDetail({ jobs, onBack, onChanged, vm }) {
const [snapshots, setSnapshots] = useState([]);
const [selectedSnapshot, setSelectedSnapshot] = useState(null);
const [inspectedSnapshot, setInspectedSnapshot] = useState(null);
const [snapshotFiles, setSnapshotFiles] = useState([]);
const [snapshotFilesLoading, setSnapshotFilesLoading] = useState(false);
const [confirmText, setConfirmText] = useState('');
const [busy, setBusy] = useState(false);
const [error, setError] = useState('');
@@ -61,6 +65,21 @@ export function VMDetail({ jobs, onBack, onChanged, vm }) {
}
}
async function inspectSnapshot(snapshot) {
setInspectedSnapshot(snapshot);
setSnapshotFiles([]);
setSnapshotFilesLoading(true);
setError('');
try {
const result = await api.get(`/snapshots/${encodeURIComponent(vm.name)}/${encodeURIComponent(snapshot.id)}/files`);
setSnapshotFiles(result.data);
} catch (requestError) {
setError(errorMessage(requestError));
} finally {
setSnapshotFilesLoading(false);
}
}
return (
<section className="space-y-5">
<div className="flex flex-col gap-4 border-b border-zinc-800 pb-5 sm:flex-row sm:items-end sm:justify-between">
@@ -95,7 +114,20 @@ export function VMDetail({ jobs, onBack, onChanged, vm }) {
{error ? <div className="rounded-md border border-amber-900 bg-amber-950/50 px-4 py-3 text-sm text-amber-200">{error}</div> : null}
<JobStatusPanel job={visibleJob} />
<SnapshotTable snapshots={snapshots} onRestore={(snapshot) => setSelectedSnapshot(snapshot)} />
<SnapshotTable
snapshots={snapshots}
onInspect={inspectSnapshot}
onRestore={(snapshot) => setSelectedSnapshot(snapshot)}
/>
<SnapshotFilesPanel
files={snapshotFiles}
loading={snapshotFilesLoading}
onClose={() => {
setInspectedSnapshot(null);
setSnapshotFiles([]);
}}
snapshot={inspectedSnapshot}
/>
<RestoreModal
busy={busy}
confirmText={confirmText}