import { useState } from "react"; import Modal from "../ui/Modal"; import Button from "../ui/Button"; import Field, { inputClass } from "../ui/Field"; import { applySettingsImport, previewSettingsImport } from "../../lib/tauri-commands"; import { describeImport, describeImportWarnings } from "../../lib/settingsImportPreview"; import type { AppSettings, SettingsImportPreview } from "../../lib/types"; interface Props { onClose: () => void; /** Fired once the import is actually applied, so the caller can refresh * whatever reads settings from the store. */ onImported: (settings: AppSettings) => void; } /** * Two phases: enter the password and pick the file (backend resolves the * file dialog itself — see `commands::settings_export_commands`), then * confirm a preview before anything is actually applied. The same password * is reused for the second call rather than asking again; nothing about * that call needs a fresh secret; the backend just doesn't cache the * *decrypted payload* between the two. */ export default function ImportSettingsModal({ onClose, onImported }: Props) { const [password, setPassword] = useState(""); const [busy, setBusy] = useState(false); const [error, setError] = useState(null); const [preview, setPreview] = useState(null); const [applied, setApplied] = useState(false); const [secretWarnings, setSecretWarnings] = useState([]); const handleChooseFile = async () => { setError(null); setBusy(true); try { const result = await previewSettingsImport(password); if (result) setPreview(result); else onClose(); // File picker dismissed. } catch (e) { setError(String(e)); } finally { setBusy(false); } }; const handleConfirm = async () => { setError(null); setBusy(true); try { const outcome = await applySettingsImport(password); setApplied(true); setSecretWarnings(outcome.secret_restore_warnings); onImported(outcome.settings); } catch (e) { setError(String(e)); } finally { setBusy(false); } }; return ( Done ) : preview ? ( <> ) : ( <> ) } > {applied ? (

Settings imported.

{secretWarnings.map((warning) => (

{warning}

))}
) : preview ? (

Exported {new Date(preview.exported_at).toLocaleString()} from Triple-C{" "} {preview.app_version}.

{/* Warnings render before the replace list, deliberately: the list * below can run long, and the one thing here that most needs to * stay above the fold while scrolling is "this turns on a * network-listening service" or "this runs a different image" — * not a bullet buried among ordinary settings. */} {describeImportWarnings(preview).map((warning) => (

{warning}

))}

This will replace:

    {describeImport(preview).map((item) => (
  • {item}
  • ))}
{error &&

{error}

}
) : (
{(id) => ( setPassword(e.target.value)} disabled={busy} className={inputClass} /> )} {error &&

{error}

}
)}
); }