From 554d798ae29548d7fbae2aa2b32a780a7381556d Mon Sep 17 00:00:00 2001 From: ValueOn AG Date: Sun, 24 May 2026 08:15:06 +0200 Subject: [PATCH] dbsync --- src/pages/admin/AdminDatabaseHealthPage.tsx | 81 +++++++++++---------- 1 file changed, 44 insertions(+), 37 deletions(-) diff --git a/src/pages/admin/AdminDatabaseHealthPage.tsx b/src/pages/admin/AdminDatabaseHealthPage.tsx index 6c8d304..d7f7347 100644 --- a/src/pages/admin/AdminDatabaseHealthPage.tsx +++ b/src/pages/admin/AdminDatabaseHealthPage.tsx @@ -841,10 +841,11 @@ const MigrationTab: React.FC = () => { _addExportLog(t('Export gestartet: {count} Datenbanken', { count: totalDbs })); - const exportData: Record = {}; + const rawChunks: string[] = []; let totalTables = 0; let totalRecords = 0; let errors = 0; + let exportedCount = 0; for (let i = 0; i < dbList.length; i++) { const dbName = dbList[i]; @@ -852,14 +853,17 @@ const MigrationTab: React.FC = () => { try { const res = await api.get('/api/admin/database-health/migration/export-single', { params: { database: dbName }, + responseType: 'text', }); - const dbPayload = res.data.data; - exportData[dbName] = dbPayload; - totalTables += dbPayload.tableCount || 0; - totalRecords += dbPayload.totalRecords || 0; + const parsed = JSON.parse(res.data); + const dbData = parsed.data; + totalTables += dbData?.tableCount || 0; + totalRecords += dbData?.totalRecords || 0; + rawChunks.push(`${JSON.stringify(dbName)}:${JSON.stringify(dbData)}`); + exportedCount++; _addExportLog( t('{db}: {tables} Tabellen, {records} Datensaetze', { - db: dbName, tables: dbPayload.tableCount || 0, records: dbPayload.totalRecords || 0, + db: dbName, tables: dbData?.tableCount || 0, records: dbData?.totalRecords || 0, }), 'success', ); @@ -873,7 +877,7 @@ const MigrationTab: React.FC = () => { } } - if (Object.keys(exportData).length === 0) { + if (exportedCount === 0) { _addExportLog(t('Export abgebrochen: keine Daten exportiert'), 'error'); toast.showError(t('Export fehlgeschlagen')); setExporting(false); @@ -883,45 +887,48 @@ const MigrationTab: React.FC = () => { _addExportLog(t('Erstelle Exportdatei...')); await new Promise(r => setTimeout(r, 0)); - const fullPayload = { - meta: { + try { + const meta = JSON.stringify({ exportedAt: new Date().toISOString(), version: '1.0', - databaseCount: Object.keys(exportData).length, + databaseCount: exportedCount, totalTables, totalRecords, - }, - databases: exportData, - }; + }); + const jsonStr = `{"meta":${meta},"databases":{${rawChunks.join(',')}}}`; - const ts = new Date().toISOString().replace(/:/g, '-').slice(0, 19); - const scope = isFullExport ? 'full' : 'partial'; - const filename = `db_backup_${instanceLabel}_${scope}_${ts}.json`; + const ts = new Date().toISOString().replace(/:/g, '-').slice(0, 19); + const scope = isFullExport ? 'full' : 'partial'; + const filename = `db_backup_${instanceLabel}_${scope}_${ts}.json`; - const jsonStr = JSON.stringify(fullPayload); - const blob = new Blob([jsonStr], { type: 'application/json' }); - const url = URL.createObjectURL(blob); - const a = document.createElement('a'); - a.href = url; - a.download = filename; - document.body.appendChild(a); - a.click(); - document.body.removeChild(a); - URL.revokeObjectURL(url); + const blob = new Blob([jsonStr], { type: 'application/json' }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = filename; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); - _addExportLog( - t('Export abgeschlossen: {dbs} Datenbanken, {tables} Tabellen, {records} Datensaetze', { - dbs: Object.keys(exportData).length, tables: totalTables, records: totalRecords, - }), - 'success', - ); + _addExportLog( + t('Export abgeschlossen: {dbs} Datenbanken, {tables} Tabellen, {records} Datensaetze', { + dbs: exportedCount, tables: totalTables, records: totalRecords, + }), + 'success', + ); - if (errors > 0) { - toast.showWarning(t('Export mit {count} Fehlern abgeschlossen', { count: errors })); - } else { - toast.showSuccess(t('Export erfolgreich')); + if (errors > 0) { + toast.showWarning(t('Export mit {count} Fehlern abgeschlossen', { count: errors })); + } else { + toast.showSuccess(t('Export erfolgreich')); + } + } catch (err: any) { + _addExportLog(t('Fehler beim Erstellen der Exportdatei: {error}', { error: String(err) }), 'error'); + toast.showError(t('Export fehlgeschlagen')); + } finally { + setExporting(false); } - setExporting(false); }; // --- Restore: File upload ---