feat: import SQLite migration dumps through the PostgreSQL panel restore

The SQLite panel's Download Migration produces a portable SQL text dump
advertised as seeding a PostgreSQL panel, but the PostgreSQL Restore only
accepted pg_dump custom archives, so the migration file was rejected with
'Invalid file' even though the upload picker asked for .dump. importDB now
sniffs the upload header: PGDMP archives keep the pg_restore path, while
raw SQLite databases (.db) and SQL text migration dumps are rebuilt,
integrity-checked, and copied into PostgreSQL with the same MigrateData
engine as 'x-ui migrate-db --dsn'. The restore picker accepts .dump/.db on
PostgreSQL and the backup modal texts describe the accepted formats in
every locale.
This commit is contained in:
MHSanaei
2026-07-12 18:04:38 +02:00
parent 44f2f426d8
commit 30b611614b
18 changed files with 200 additions and 49 deletions
+2 -2
View File
@@ -468,9 +468,9 @@ export const sections: readonly Section[] = [
{
method: 'POST',
path: '/panel/api/server/importDB',
summary: 'Restore the panel DB from an uploaded SQLite file (multipart form, field name "db"). The panel restarts after restore. Destructive.',
summary: 'Restore the panel DB from an uploaded backup (multipart form, field name "db"). SQLite panels accept a .db file; PostgreSQL panels accept a pg_dump archive (.dump), a SQLite database (.db), or a SQLite migration dump. The panel restarts after restore. Destructive.',
params: [
{ name: 'db', in: 'body (multipart)', type: 'file', desc: 'SQLite database file to upload.' },
{ name: 'db', in: 'body (multipart)', type: 'file', desc: 'Database backup or migration file to upload.' },
],
},
{
+1 -1
View File
@@ -32,7 +32,7 @@ export default function BackupModal({ open, basePath: _basePath, onClose, onBusy
function importDb() {
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.accept = isPostgres ? '.dump' : '.db';
fileInput.accept = isPostgres ? '.dump,.db' : '.db';
fileInput.addEventListener('change', async (e) => {
const dbFile = (e.target as HTMLInputElement).files?.[0];
if (!dbFile) return;