-
+
+
Datenschutzhinweis
-
{$privacyNote}
+
{$privacyNote}
{/if}
-
+
-
Konto
+
+ Konto
+
@@ -375,35 +500,83 @@
href="/recover"
class="flex items-center gap-3 px-5 py-4 transition hover:bg-gray-50 dark:hover:bg-gray-700/50"
>
-
@@ -429,7 +602,12 @@
- Original-Dateien laden?
+
+ Original-Dateien laden?
+
Original-Dateien können deutlich mehr Datenvolumen verbrauchen. Am besten im WLAN aktivieren.
diff --git a/frontend/src/routes/admin/+page.svelte b/frontend/src/routes/admin/+page.svelte
index 37fb20c..5eae3d8 100644
--- a/frontend/src/routes/admin/+page.svelte
+++ b/frontend/src/routes/admin/+page.svelte
@@ -56,8 +56,8 @@
{
title: 'Limits & Größen',
fields: [
- { key: 'max_image_size_mb', label: 'Max. Bildgröße (MB)', kind: 'number' },
- { key: 'max_video_size_mb', label: 'Max. Videogröße (MB)', kind: 'number' }
+ { key: 'max_image_size_mb', label: 'Max. Bildgröße (MB)', kind: 'number' },
+ { key: 'max_video_size_mb', label: 'Max. Videogröße (MB)', kind: 'number' }
// compression_concurrency is set via COMPRESSION_WORKER_CONCURRENCY at
// boot, not live — omitted so it isn't a dead no-op control.
]
@@ -65,30 +65,50 @@
{
title: 'Rate-Limits',
fields: [
- { key: 'rate_limits_enabled', label: 'Rate-Limits aktiv', kind: 'bool', hint: 'Hauptschalter — wenn aus, sind alle Rate-Limits deaktiviert.' },
- { key: 'upload_rate_enabled', label: 'Upload-Limit aktiv', kind: 'bool' },
- { key: 'feed_rate_enabled', label: 'Feed-Limit aktiv', kind: 'bool' },
- { key: 'export_rate_enabled', label: 'Export-Limit aktiv', kind: 'bool' },
- { key: 'join_rate_enabled', label: 'Join-Limit aktiv', kind: 'bool' },
- { key: 'upload_rate_per_hour', label: 'Upload-Limit pro Stunde', kind: 'number' },
- { key: 'feed_rate_per_min', label: 'Feed-Anfragen pro Minute', kind: 'number' },
- { key: 'export_rate_per_day', label: 'Export-Downloads pro Tag', kind: 'number' }
+ {
+ key: 'rate_limits_enabled',
+ label: 'Rate-Limits aktiv',
+ kind: 'bool',
+ hint: 'Hauptschalter — wenn aus, sind alle Rate-Limits deaktiviert.'
+ },
+ { key: 'upload_rate_enabled', label: 'Upload-Limit aktiv', kind: 'bool' },
+ { key: 'feed_rate_enabled', label: 'Feed-Limit aktiv', kind: 'bool' },
+ { key: 'export_rate_enabled', label: 'Export-Limit aktiv', kind: 'bool' },
+ { key: 'join_rate_enabled', label: 'Join-Limit aktiv', kind: 'bool' },
+ { key: 'upload_rate_per_hour', label: 'Upload-Limit pro Stunde', kind: 'number' },
+ { key: 'feed_rate_per_min', label: 'Feed-Anfragen pro Minute', kind: 'number' },
+ { key: 'export_rate_per_day', label: 'Export-Downloads pro Tag', kind: 'number' }
]
},
{
title: 'Quoten',
fields: [
- { key: 'quota_enabled', label: 'Quoten aktiv', kind: 'bool', hint: 'Hauptschalter — wenn aus, wird nichts geprüft.' },
- { key: 'storage_quota_enabled', label: 'Speicher-Quote aktiv', kind: 'bool' },
- { key: 'upload_count_quota_enabled', label: 'Upload-Anzahl-Quote aktiv', kind: 'bool', hint: 'Reserviert für künftige Anzahl-Limits.' },
- { key: 'quota_tolerance', label: 'Toleranz (0–1)', kind: 'number' },
- { key: 'estimated_guest_count', label: 'Geschätzte Gästezahl', kind: 'number' }
+ {
+ key: 'quota_enabled',
+ label: 'Quoten aktiv',
+ kind: 'bool',
+ hint: 'Hauptschalter — wenn aus, wird nichts geprüft.'
+ },
+ { key: 'storage_quota_enabled', label: 'Speicher-Quote aktiv', kind: 'bool' },
+ {
+ key: 'upload_count_quota_enabled',
+ label: 'Upload-Anzahl-Quote aktiv',
+ kind: 'bool',
+ hint: 'Reserviert für künftige Anzahl-Limits.'
+ },
+ { key: 'quota_tolerance', label: 'Toleranz (0–1)', kind: 'number' },
+ { key: 'estimated_guest_count', label: 'Geschätzte Gästezahl', kind: 'number' }
]
},
{
title: 'Datenschutzhinweis',
fields: [
- { key: 'privacy_note', label: 'Datenschutzhinweis (freier Text)', kind: 'text', hint: 'Wird wörtlich im Konto-Bereich angezeigt. Kein HTML — Leerzeichen und Zeilenumbrüche werden übernommen.' }
+ {
+ key: 'privacy_note',
+ label: 'Datenschutzhinweis (freier Text)',
+ kind: 'text',
+ hint: 'Wird wörtlich im Konto-Bereich angezeigt. Kein HTML — Leerzeichen und Zeilenumbrüche werden übernommen.'
+ }
]
}
];
@@ -103,7 +123,12 @@
}
type AdminTab = 'stats' | 'config' | 'export' | 'users';
- const TAB_LABELS: Record
= { stats: 'Stats', config: 'Config', export: 'Export', users: 'Nutzer' };
+ const TAB_LABELS: Record = {
+ stats: 'Stats',
+ config: 'Config',
+ export: 'Export',
+ users: 'Nutzer'
+ };
let activeTab = $state('stats');
@@ -215,7 +240,11 @@
// Don't let a cleared number field persist as an empty/NaN config value.
for (const key of NUMBER_KEYS) {
const v = configDraft[key];
- if (v !== undefined && v !== config[key] && (String(v).trim() === '' || !Number.isFinite(Number(v)))) {
+ if (
+ v !== undefined &&
+ v !== config[key] &&
+ (String(v).trim() === '' || !Number.isFinite(Number(v)))
+ ) {
toastError(new Error('Bitte gib für alle Zahlenfelder einen gültigen Wert ein.'));
return;
}
@@ -350,20 +379,29 @@
function statusBadgeClass(status: string): string {
switch (status) {
- case 'done': return 'bg-green-100 text-green-700 dark:bg-green-900/40 dark:text-green-200';
- case 'running': return 'bg-blue-100 text-blue-700 dark:bg-blue-900/40 dark:text-blue-200';
- case 'failed': return 'bg-red-100 text-red-700 dark:bg-red-900/40 dark:text-red-200';
- default: return 'bg-gray-100 text-gray-600 dark:bg-gray-700 dark:text-gray-300';
+ case 'done':
+ return 'bg-green-100 text-green-700 dark:bg-green-900/40 dark:text-green-200';
+ case 'running':
+ return 'bg-blue-100 text-blue-700 dark:bg-blue-900/40 dark:text-blue-200';
+ case 'failed':
+ return 'bg-red-100 text-red-700 dark:bg-red-900/40 dark:text-red-200';
+ default:
+ return 'bg-gray-100 text-gray-600 dark:bg-gray-700 dark:text-gray-300';
}
}
function statusLabel(status: string): string {
switch (status) {
- case 'pending': return 'Ausstehend';
- case 'running': return 'Läuft';
- case 'done': return 'Fertig';
- case 'failed': return 'Fehlgeschlagen';
- default: return status;
+ case 'pending':
+ return 'Ausstehend';
+ case 'running':
+ return 'Läuft';
+ case 'done':
+ return 'Fertig';
+ case 'failed':
+ return 'Fehlgeschlagen';
+ default:
+ return status;
}
}
@@ -395,13 +433,23 @@
(pinModal = null)}>
{#if pinModal}
- Neue PIN für {pinModal.name}
+
+ Neue PIN für {pinModal.name}
+
- Zeige diese PIN dem Benutzer. Sie wird nur einmal angezeigt — beim Schließen wird sie verworfen.
+ Zeige diese PIN dem Benutzer. Sie wird nur einmal angezeigt — beim Schließen wird sie
+ verworfen.
-
-
{pinModal.pin}
-