import { MessageNotice } from '../appNotice'; import { useEffect, useRef, useState } from 'react'; import { invoke } from '@tauri-apps/api/core'; import { ArchiveRestore, LoaderCircle, X } from 'lucide-react'; import { useI18n } from '../i18n'; import './AgentConfigBackupDialog.css'; type FileSummary = { path: string; exists: boolean | null; size: number | null }; type Version = { id: string; createdAt: string | null; fileCount: number; location: string; files: FileSummary[]; restorable: boolean; error: string | null }; type Listing = { versions: Version[] }; type Preview = { revision: string; files: FileSummary[]; differences: { file: string; field: string; before: string; after: string }[] }; export function AgentConfigBackupDialog({ client, onClose, onRestored }: { client: string; onClose: () => void; onRestored: () => Promise; }) { const { t, formatDate } = useI18n(); const dialog = useRef(null); const [listing, setListing] = useState({ versions: [] }); const [selected, setSelected] = useState(null); const [preview, setPreview] = useState(null); const [confirmation, setConfirmation] = useState<'restore' | 'delete' | null>(null); const [busy, setBusy] = useState(true); const [error, setError] = useState(''); useEffect(() => { let disposed = false; dialog.current?.showModal(); void invoke('list_agent_config_backups', { client }) .then((value) => { if (!disposed) setListing(value); }) .catch((cause) => { if (!disposed) setError(String(cause)); }) .finally(() => { if (!disposed) setBusy(false); }); return () => { disposed = true; }; }, [client]); const choose = async (version: Version) => { setBusy(true); setError(''); setSelected(version); setPreview(null); setConfirmation(null); try { if (version.restorable) setPreview(await invoke('preview_agent_config_backup', { client, id: version.id })); } catch (cause) { setError(String(cause)); } finally { setBusy(false); } }; const confirm = async () => { if (!selected || !confirmation || (confirmation === 'restore' && !preview)) return; setBusy(true); setError(''); try { if (confirmation === 'restore') { await invoke('restore_agent_config_backup', { client, id: selected.id, revision: preview!.revision }); await onRestored(); onClose(); } else { await invoke('delete_agent_config_backup', { client, id: selected.id }); setSelected(null); setPreview(null); setConfirmation(null); setListing(await invoke('list_agent_config_backups', { client })); } } catch (cause) { setError(String(cause)); setPreview(null); setConfirmation(null); } finally { setBusy(false); } }; const date = (version: Version) => version.createdAt ? formatDate(version.createdAt, { dateStyle: 'short', timeStyle: 'medium' }) : version.id; return { event.preventDefault(); if (!busy) onClose(); }}>

{t('agents.backup.button')}

{t('agents.backup.description')}

{busy &&

{t('agents.backup.loading')}

} {!selected && !busy &&

{t('agents.backup.select')}

} {selected && <> {t('agents.backup.location')}

{selected.location}

{selected.error &&

{selected.error}

}
    {selected.files.map((file) =>
  • {file.path}{file.exists === null ? t('agents.backup.invalid') : file.exists ? `${t('agents.backup.present')} ยท ${file.size ?? 0} B` : t('agents.backup.missing')}
  • )}
{preview &&

{t(preview.differences.length ? 'agents.backup.overwrite' : 'agents.backup.unchanged')}

} {preview?.differences.filter((diff) => diff.field.startsWith('modelMappings')).map((diff) =>

{t('agents.backup.mappingRestore')} {diff.field}

)} }
{confirmation && selected &&
{t(confirmation === 'restore' ? 'agents.backup.restoreConfirm' : 'agents.backup.deleteConfirm', { version: date(selected) })}

{t(confirmation === 'restore' ? 'agents.backup.restoreWarning' : 'agents.backup.deleteWarning')}

} {error && setError('')} />}
; }