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 ---