"use client"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from "@/components/ui/alert-dialog"; import { InfoBanner, SectionDivider, Toggle, formatStorageSize, } from "@/modules/settings/components/panel/controls"; import { SETTINGS_PANEL_INSET } from "@/modules/settings/components/panel/surface"; import { DAY_OF_WEEK_OPTIONS, SCHEDULE_TIME_OPTIONS, type BackupSettingsDraft, type SettingsBackend, } from "@/modules/settings/components/panel/types"; import { Download, Upload } from "@/components/icons/platform-icons"; import { useEffect, useState } from "react"; import { cn } from "@/lib/utils"; type BackupSectionProps = { data: SettingsBackend["backup"]; capabilities: SettingsBackend["capabilities"]["backup"]; settingsDraft: BackupSettingsDraft; onSettingsChange: (patch: Partial) => void; onRunBackupNow: () => Promise; onRestoreBackup: (backupId: string) => Promise; }; const selectCls = "h-8 w-full cursor-pointer appearance-none rounded-lg border border-glass-border bg-background/55 px-3 text-xs text-foreground focus:border-primary/40 focus:outline-none disabled:cursor-not-allowed disabled:opacity-50"; function PreferenceRow({ label, description, children, }: { label: string; description?: string; children: React.ReactNode; }) { return (
{label}
{description && (
{description}
)}
{children}
); } export function BackupSection({ data, capabilities, settingsDraft, onSettingsChange, onRunBackupNow, onRestoreBackup, }: BackupSectionProps) { const [restoreBackupId, setRestoreBackupId] = useState(null); useEffect(() => { if (!restoreBackupId && data.backups[0]) { setRestoreBackupId(data.backups[0].id); } }, [data.backups, restoreBackupId]); const selectedBackup = data.backups.find((b) => b.id === restoreBackupId) ?? data.backups[0] ?? null; return (
{data.settings.error && } {data.runNow.error && } {data.restore.error && } {/* ── Schedule ── */}
onSettingsChange({ enabled: !settingsDraft.enabled })} disabled={capabilities.schedule.disabled} disabledReason={capabilities.schedule.disabledReason} />
{settingsDraft.frequency === "weekly" && ( )} onSettingsChange({ retentionCount: e.target.value })} type="number" min={1} className="h-8 w-36 rounded-lg border border-glass-border bg-background/55 px-3 text-xs text-foreground focus:border-primary/40 focus:outline-none" /> {data.backupRoot}
{/* ── Actions ── */}
Run backup now
Creates a full archive immediately
Restore from backup
{selectedBackup ? `Selected: ${new Intl.DateTimeFormat(undefined, { dateStyle: "medium", timeStyle: "short" }).format(new Date(selectedBackup.createdAt))}` : "No backup selected"}
Restore full system backup? {selectedBackup ? `This will fully replace the current database and /DATA contents with ${selectedBackup.id}, then reboot the server.` : "Select a backup first."} Cancel { e.preventDefault(); if (!selectedBackup) return; void onRestoreBackup(selectedBackup.id); }} disabled={!selectedBackup || data.restore.isPending} > {data.restore.isPending ? "Restoring…" : "Restore Backup"}
{/* ── Recent Backups ── */} {data.backups.length === 0 ? (
No completed backups yet.
) : (
{data.backups.map((backup) => { const isSelected = selectedBackup?.id === backup.id; return ( ); })}
)}
); }