Add modal for export method selection in AdminPage and update export filename based on hosting type
Some checks failed
Deploy / build-and-deploy (push) Failing after 1s

This commit is contained in:
2025-06-21 17:48:29 +02:00
parent 82f4f5a07d
commit dd31bb735e
3 changed files with 118 additions and 2 deletions

View File

@@ -491,14 +491,80 @@ export default function AdminPage() {
};
function handleExportTarball() {
fetch('/api/admin/export')
// Create popup modal
const modal = document.createElement('div');
modal.style.position = 'fixed';
modal.style.top = '0';
modal.style.left = '0';
modal.style.width = '100%';
modal.style.height = '100%';
modal.style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
modal.style.display = 'flex';
modal.style.alignItems = 'center';
modal.style.justifyContent = 'center';
modal.style.zIndex = '1000';
const modalContent = document.createElement('div');
modalContent.style.backgroundColor = 'white';
modalContent.style.padding = '30px';
modalContent.style.borderRadius = '8px';
modalContent.style.maxWidth = '500px';
modalContent.style.width = '90%';
modalContent.style.textAlign = 'center';
modalContent.style.position = 'relative';
modalContent.innerHTML = `
<button id="close-btn" style="position: absolute; top: 10px; right: 15px; background: none; border: none; font-size: 24px; cursor: pointer; color: #666; font-weight: bold;">×</button>
<h2 style="margin: 0 0 20px 0; font-size: 1.5rem; font-weight: bold;">Export Method</h2>
<p style="margin: 0 0 20px 0; color: #666;">How are you hosting this application?</p>
<p style="margin: 0 0 20px 0; font-size: 0.9rem; color: #888; font-style: italic;">If you don't know your method of hosting, ask your Systems Administrator</p>
<div style="display: flex; gap: 10px; justify-content: center; margin-top: 20px;">
<button id="docker-btn" style="padding: 10px 20px; background-color: #059669; color: white; border: none; border-radius: 5px; cursor: pointer; font-weight: bold;">Docker</button>
<button id="local-btn" style="padding: 10px 20px; background-color: #2563eb; color: white; border: none; border-radius: 5px; cursor: pointer; font-weight: bold;">Local</button>
</div>
`;
modal.appendChild(modalContent);
document.body.appendChild(modal);
// Add event listeners
const dockerBtn = modal.querySelector('#docker-btn');
const localBtn = modal.querySelector('#local-btn');
const closeBtn = modal.querySelector('#close-btn');
const closeModal = () => {
document.body.removeChild(modal);
};
dockerBtn?.addEventListener('click', () => {
closeModal();
exportFromEndpoint('/api/admin/export');
});
localBtn?.addEventListener('click', () => {
closeModal();
exportFromEndpoint('/api/admin/exportlocal');
});
closeBtn?.addEventListener('click', closeModal);
// Close modal when clicking outside
modal.addEventListener('click', (e) => {
if (e.target === modal) {
closeModal();
}
});
}
function exportFromEndpoint(endpoint: string) {
fetch(endpoint)
.then(async (res) => {
if (!res.ok) throw new Error('Export failed');
const blob = await res.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'markdownblog-export.tar.gz';
a.download = endpoint.includes('local') ? 'local-export.tar.gz' : 'docker-export.tar.gz';
document.body.appendChild(a);
a.click();
a.remove();

View File

@@ -3,6 +3,9 @@ import { NextResponse } from 'next/server';
import { statSync, createReadStream, existsSync } from 'fs';
import path from 'path';
// This is the route for exporting posts when using the docker production server
// If you try this on the local server, it will fail because the posts directory is not on the local server
export async function GET() {
try {
const dockerDir = '/app/docker'; // update this to your actual path

View File

@@ -0,0 +1,47 @@
import tar from 'tar';
import { NextResponse } from 'next/server';
import { statSync, createReadStream, existsSync } from 'fs';
import path from 'path';
import { gzip } from 'zlib';
// This is the route for exporting posts when using the local production server
// If you try this on the docker server, it will fail because the posts directory is not on the docker server
export async function GET() {
try {
const localDir = 'posts';
const tarballName = 'local-export.tar.gz';
const tarballPath = path.join('/tmp', tarballName);
if (!existsSync(localDir)) {
return NextResponse.json({ error: `${localDir} directory does not exist` }, { status: 400 });
}
await tar.c(
{
gzip: true,
file: tarballPath,
cwd: path.dirname(localDir),
portable: true,
noMtime: true,
},
[path.basename(localDir)]
);
const stat = statSync(tarballPath);
const stream = createReadStream(tarballPath);
return new Response(stream as any, {
status: 200,
headers: {
'Content-Type': 'application/gzip',
'Content-Disposition': `attachment; filename="${tarballName}"`,
'Content-Length': stat.size.toString(),
},
});
} catch (error) {
console.error('Error exporting local:', error);
return NextResponse.json({ error: 'Error exporting local' }, { status: 500 });
}
}