feat: improve upload admin workflow
Add users.is_admin SQLite migration for promoted admins. Support curl PUT request uploads, save uploads into admin file-manager paths, default 25 GiB uploads, tabbed UI, and local dev preview.
This commit is contained in:
@@ -38,6 +38,8 @@ export default async function DashboardPage({ searchParams }) {
|
||||
const success = readSearchParam(resolvedSearchParams, 'success');
|
||||
const totalBytes = uploads.reduce((total, item) => total + (Number(item.size_bytes) || 0), 0);
|
||||
const nowTs = Date.now();
|
||||
const requestedTab = readSearchParam(resolvedSearchParams, 'tab');
|
||||
const activeTab = ['upload', 'files', 'requests'].includes(requestedTab) ? requestedTab : 'upload';
|
||||
|
||||
return (
|
||||
<main className="page-shell">
|
||||
@@ -65,27 +67,31 @@ export default async function DashboardPage({ searchParams }) {
|
||||
|
||||
<StatusMessage error={error} success={success} />
|
||||
|
||||
<div className="dashboard-top-grid">
|
||||
<section className="panel panel-spotlight">
|
||||
<nav className="tabs" aria-label="Dashboard-Bereiche">
|
||||
<a className={`tab ${activeTab === 'upload' ? 'active' : ''}`} href="/manage/dashboard?tab=upload">
|
||||
Upload
|
||||
</a>
|
||||
<a className={`tab ${activeTab === 'files' ? 'active' : ''}`} href="/manage/dashboard?tab=files">
|
||||
Dateien
|
||||
</a>
|
||||
<a className={`tab ${activeTab === 'requests' ? 'active' : ''}`} href="/manage/dashboard?tab=requests">
|
||||
Anfragen
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
<div className="summary-line">
|
||||
<span>{uploads.length} aktive Uploads</span>
|
||||
<span>{totalBytes > 0 ? formatBytes(totalBytes) : '0 B'} genutzt</span>
|
||||
</div>
|
||||
|
||||
{activeTab === 'upload' ? (
|
||||
<section className="panel">
|
||||
<h2>Neue Datei hochladen</h2>
|
||||
<UploadProgressForm csrfToken={csrfToken} />
|
||||
</section>
|
||||
) : null}
|
||||
|
||||
<aside className="panel panel-soft">
|
||||
<h2>Schnellüberblick</h2>
|
||||
<div className="info-stack">
|
||||
<div className="info-card">
|
||||
<strong>{uploads.length}</strong>
|
||||
<span className="muted">aktive Uploads</span>
|
||||
</div>
|
||||
<div className="info-card">
|
||||
<strong>{totalBytes > 0 ? formatBytes(totalBytes) : '0 B'}</strong>
|
||||
<span className="muted">genutzter Speicher</span>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
{activeTab === 'requests' ? (
|
||||
<section className="panel">
|
||||
<h2>Upload-Anfragen</h2>
|
||||
<p className="muted">Benachrichtigung erfolgt an deinen Benutzernamen (E-Mail-Adresse).</p>
|
||||
@@ -162,7 +168,9 @@ export default async function DashboardPage({ searchParams }) {
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
) : null}
|
||||
|
||||
{activeTab === 'files' ? (
|
||||
<section className="panel">
|
||||
<h2>Aktuelle Uploads</h2>
|
||||
{uploads.length === 0 ? (
|
||||
@@ -225,6 +233,7 @@ export default async function DashboardPage({ searchParams }) {
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
) : null}
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user