diff --git a/src/pages/admin/AdminDatabaseHealthPage.tsx b/src/pages/admin/AdminDatabaseHealthPage.tsx index 32bcaae..f83e103 100644 --- a/src/pages/admin/AdminDatabaseHealthPage.tsx +++ b/src/pages/admin/AdminDatabaseHealthPage.tsx @@ -957,24 +957,37 @@ const MigrationTab: React.FC = () => { e.preventDefault(); }; - // --- Restore: Validate --- + // --- Restore: Validate (uploads file to server, streams to disk) --- + const importTokenRef = useRef(''); + const _validateFile = async (file: File) => { setValidating(true); setValidation(null); + importTokenRef.current = ''; try { const formData = new FormData(); formData.append('file', file); - const res = await api.post('/api/admin/database-health/migration/validate', formData, { + const res = await api.post('/api/admin/database-health/migration/upload-import', formData, { headers: { 'Content-Type': 'multipart/form-data' }, + timeout: 0, + }); + importTokenRef.current = res.data.token || ''; + setValidation({ + valid: res.data.valid, + summary: (res.data.databases || []).map((d: any) => ({ + database: d.database, + tableCount: d.tableCount, + recordCount: d.recordCount, + registered: true, + })), + warnings: res.data.warnings || [], + systemObjectsFound: res.data.systemObjectsFound || [], }); - setValidation(res.data); } catch (err: any) { const detail = err?.response?.data?.detail; setValidation({ - valid: false, - summary: [], - warnings: [typeof detail === 'string' ? detail : t('Validierung fehlgeschlagen')], - systemObjectsFound: [], + valid: false, summary: [], systemObjectsFound: [], + warnings: [typeof detail === 'string' ? detail : t('Upload oder Validierung fehlgeschlagen')], }); } finally { setValidating(false); @@ -989,7 +1002,7 @@ const MigrationTab: React.FC = () => { }, []); const _startImport = async () => { - if (!uploadedFile || !validation?.valid) return; + if (!importTokenRef.current || !validation?.valid) return; const modeLabel = importMode === 'replace' ? t('Neu (Datenbank leeren und importieren)') @@ -1004,39 +1017,13 @@ const MigrationTab: React.FC = () => { setImporting(true); setImportLog([]); - _addImportLog(t('Vorbereitung: Datei wird hochgeladen und validiert...')); - - let token = ''; - let dbList: Array<{ database: string; tableCount: number; recordCount: number }> = []; - - try { - const formData = new FormData(); - formData.append('file', uploadedFile); - const prepRes = await api.post('/api/admin/database-health/migration/prepare-import', formData, { - headers: { 'Content-Type': 'multipart/form-data' }, - }); - token = prepRes.data.token; - dbList = prepRes.data.databases || []; - const warnings: string[] = prepRes.data.warnings || []; - for (const w of warnings) { - _addImportLog(t('Warnung: {msg}', { msg: w }), 'error'); - } - _addImportLog( - t('Validierung OK: {count} Datenbanken bereit', { count: dbList.length }), - 'success', - ); - } catch (err: any) { - const detail = err?.response?.data?.detail; - const msg = typeof detail === 'string' ? detail : detail?.message || t('Vorbereitung fehlgeschlagen'); - _addImportLog(msg, 'error'); - toast.showError(msg); - setImporting(false); - return; - } - + const token = importTokenRef.current; + const dbList = validation.summary.filter(s => s.registered); + const totalDbs = dbList.length; let totalRecords = 0; let errors = 0; - const totalDbs = dbList.length; + + _addImportLog(t('Import gestartet: {count} Datenbanken', { count: totalDbs })); for (let i = 0; i < dbList.length; i++) { const dbInfo = dbList[i]; @@ -1074,7 +1061,6 @@ const MigrationTab: React.FC = () => { } } - // Clean up server-side cache try { await api.post('/api/admin/database-health/migration/import-done', { token }); } catch { /* ignore */ } _addImportLog( @@ -1089,12 +1075,14 @@ const MigrationTab: React.FC = () => { } else { toast.showSuccess(t('{count} Datensaetze erfolgreich importiert', { count: totalRecords })); } + importTokenRef.current = ''; setImporting(false); }; const _resetUpload = () => { setUploadedFile(null); setValidation(null); + importTokenRef.current = ''; }; return (