diff --git a/AppImage/components/restore-progress-card.tsx b/AppImage/components/restore-progress-card.tsx
index b57c06c8..86a5c922 100644
--- a/AppImage/components/restore-progress-card.tsx
+++ b/AppImage/components/restore-progress-card.tsx
@@ -65,6 +65,16 @@ interface RestoreRollback {
components_to_uninstall?: string[]
}
+interface DataPoolsImport {
+ ok: string[]
+ forced: string[]
+ partial: string[]
+ missing: string[]
+ failed: string[]
+ finished_at?: string
+ log_path?: string
+}
+
interface RestoreState {
status: "running" | "complete" | "failed"
started_at: string
@@ -79,6 +89,7 @@ interface RestoreState {
summary: RestoreSummary | null
acknowledged: boolean
duration?: string
+ data_pools_import?: DataPoolsImport
}
interface HistoryEntry {
@@ -371,6 +382,8 @@ const RestoreDetailModal: React.FC<{
)}
+ {state.data_pools_import && }
+
Rollback delta
@@ -392,6 +405,94 @@ const RestoreDetailModal: React.FC<{
)
}
+// ── Data-pools auto-import block ──────────────────────────────
+// Rendered inside the RestoreDetailModal (and the compact header
+// badge on the card) so the operator sees which ZFS data pools
+// were imported automatically during the restore, which ones ZFS
+// took with -f because the on-disk hostid didn't match the fresh
+// install, and which ones were skipped and need manual attention.
+// The section is populated by backup_host.sh:_rs_persist_datapool_import
+// and survives the ScriptTerminalModal being closed.
+const DataPoolsBlock: React.FC<{ section: DataPoolsImport }> = ({ section }) => {
+ const total =
+ section.ok.length +
+ section.forced.length +
+ section.partial.length +
+ section.missing.length +
+ section.failed.length
+ if (total === 0) return null
+
+ const Row: React.FC<{
+ label: string
+ tone: "ok" | "warn" | "info" | "error"
+ items: string[]
+ help?: string
+ }> = ({ label, tone, items, help }) => {
+ if (items.length === 0) return null
+ const toneClass =
+ tone === "ok"
+ ? "text-emerald-400"
+ : tone === "warn"
+ ? "text-amber-400"
+ : tone === "error"
+ ? "text-red-400"
+ : "text-blue-400"
+ return (
+
+
+ {tone === "ok" &&
}
+ {tone === "warn" &&
}
+ {tone === "error" &&
}
+ {tone === "info" &&
}
+
{label}
+
({items.length})
+
+
{items.join(", ")}
+ {help &&
{help}
}
+
+ )
+ }
+
+ return (
+
+
+
+ ZFS data pools — auto-import
+
+
+
+
+
+
+
+
+ {section.log_path && (
+
Log: {section.log_path}
+ )}
+
+ )
+}
+
// ── History browser modal ─────────────────────────────────────
const RestoreHistoryModal: React.FC<{ open: boolean; onClose: () => void }> = ({ open, onClose }) => {
@@ -510,6 +611,14 @@ export const RestoreProgressCard: React.FC = () => {
}
const hasWarnings = state.sanity_warnings.length > 0
+ const pools = state.data_pools_import
+ const poolCount =
+ (pools?.ok.length ?? 0) +
+ (pools?.forced.length ?? 0) +
+ (pools?.partial.length ?? 0) +
+ (pools?.missing.length ?? 0) +
+ (pools?.failed.length ?? 0)
+ const poolWarnings = (pools?.partial.length ?? 0) + (pools?.missing.length ?? 0) + (pools?.failed.length ?? 0)
const barColor =
state.status === "failed" ? "bg-red-500" : state.status === "complete" ? "bg-emerald-500" : "bg-blue-500"
@@ -530,6 +639,20 @@ export const RestoreProgressCard: React.FC = () => {
{state.sanity_warnings.length} boot warning{state.sanity_warnings.length === 1 ? "" : "s"}
)}
+ {poolCount > 0 && (
+
0
+ ? "text-amber-400 border-amber-500/40 bg-amber-500/10 gap-1"
+ : "text-emerald-400 border-emerald-500/40 bg-emerald-500/10 gap-1"
+ }
+ >
+
+ {poolCount} ZFS pool{poolCount === 1 ? "" : "s"}
+ {poolWarnings > 0 && ` · ${poolWarnings} need attention`}
+
+ )}