fix: bw/stats 404, gateway links, history crash
- swr.ts: remove useBandwidth(), drop bw from useDashboard() - events/route.ts: skip bandwidth SSE (Kubo 0.28.0 unsupported) - usage/page.tsx: remove getBWStats call + bw references - helpers.ts: gatewayLink -> ipfs.maos.dedyn.io (subdomain only) - upload/page.tsx: fix local gatewayLink (subdomain only) - storage.ts: update default gatewayUrl, add defensive getHistory()
This commit is contained in:
@@ -5,7 +5,7 @@ import { getSettings, saveSettings, resetSettings, type PortalSettings } from '@
|
||||
import { useTheme } from '@/lib/theme';
|
||||
import PortalLayout from '@/app/layout-portal';
|
||||
import {
|
||||
Settings, Globe, Server, HardDrive, RefreshCw,
|
||||
Settings, Globe, Server, HardDrive, RefreshCw, Shield,
|
||||
Sun, Moon, Save, RotateCcw, Check, AlertTriangle,
|
||||
} from 'lucide-react';
|
||||
|
||||
@@ -16,6 +16,13 @@ function formatStorageMB(mb: number): string {
|
||||
return mb + ' MB';
|
||||
}
|
||||
|
||||
function formatBytes(bytes: number): string {
|
||||
if (bytes === 0) return '0 B';
|
||||
const units = ['B', 'KB', 'MB', 'GB'];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(1024));
|
||||
return (bytes / Math.pow(1024, i)).toFixed(i > 0 ? 1 : 0) + ' ' + units[i];
|
||||
}
|
||||
|
||||
/* ════════════════════════════ Page ════════════════════════════ */
|
||||
|
||||
export default function SettingsPage() {
|
||||
@@ -185,6 +192,90 @@ export default function SettingsPage() {
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Upload Restrictions',
|
||||
icon: Shield,
|
||||
iconColor: 'text-accent-rose',
|
||||
fields: (
|
||||
<div className="space-y-4">
|
||||
{/* Allowed file types */}
|
||||
<div>
|
||||
<label className="text-xs text-surface-400 mb-1.5 block">Allowed File Extensions</label>
|
||||
<input
|
||||
value={form.allowedFileTypes}
|
||||
onChange={e => update('allowedFileTypes', e.target.value)}
|
||||
placeholder=".jpg,.png,.pdf,.mp4 (leave empty for all)"
|
||||
className={inputCls('allowedFileTypes')}
|
||||
/>
|
||||
{errorMsg('allowedFileTypes')}
|
||||
<p className="mt-1.5 text-[11px] text-surface-500">
|
||||
Comma-separated extensions. Empty = all file types accepted.
|
||||
Extension check is case-insensitive.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Max file size */}
|
||||
<div>
|
||||
<label className="text-xs text-surface-400 mb-1.5 block">
|
||||
Max File Size: <span className="text-surface-200 font-medium">{formatBytes(form.maxFileSize)}</span>
|
||||
</label>
|
||||
<div className="flex items-center gap-3">
|
||||
<input
|
||||
type="range"
|
||||
min={1024}
|
||||
max={1024 * 1024 * 1024}
|
||||
step={1024 * 1024}
|
||||
value={Math.max(1024, form.maxFileSize)}
|
||||
onChange={e => update('maxFileSize', Number(e.target.value))}
|
||||
className="flex-1 accent-brand-500 h-1.5 rounded-full appearance-none bg-surface-700 cursor-pointer"
|
||||
style={{ accentColor: '#14b8a6' }}
|
||||
/>
|
||||
<input
|
||||
type="number"
|
||||
min={0}
|
||||
max={1024 * 1024 * 1024}
|
||||
value={form.maxFileSize}
|
||||
onChange={e => update('maxFileSize', Math.max(0, Number(e.target.value) || 0))}
|
||||
className="w-24 rounded-lg bg-surface-900 border border-surface-700 px-2 py-1.5 text-xs text-surface-200 text-center focus:outline-none focus:border-brand-500"
|
||||
/>
|
||||
</div>
|
||||
<p className="mt-1.5 text-[11px] text-surface-500">
|
||||
Maximum file size in bytes. 0 = unlimited.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Max files per batch */}
|
||||
<div>
|
||||
<label className="text-xs text-surface-400 mb-1.5 block">
|
||||
Max Files Per Upload: <span className="text-surface-200 font-medium">{form.maxFiles}</span>
|
||||
</label>
|
||||
<div className="flex items-center gap-3">
|
||||
<input
|
||||
type="range"
|
||||
min={1}
|
||||
max={100}
|
||||
step={1}
|
||||
value={form.maxFiles}
|
||||
onChange={e => update('maxFiles', Number(e.target.value))}
|
||||
className="flex-1 accent-brand-500 h-1.5 rounded-full appearance-none bg-surface-700 cursor-pointer"
|
||||
style={{ accentColor: '#14b8a6' }}
|
||||
/>
|
||||
<input
|
||||
type="number"
|
||||
min={1}
|
||||
max={100}
|
||||
value={form.maxFiles}
|
||||
onChange={e => update('maxFiles', Math.max(1, Math.min(100, Number(e.target.value) || 0)))}
|
||||
className="w-16 rounded-lg bg-surface-900 border border-surface-700 px-2 py-1.5 text-xs text-surface-200 text-center focus:outline-none focus:border-brand-500"
|
||||
/>
|
||||
</div>
|
||||
<p className="mt-1.5 text-[11px] text-surface-500">
|
||||
Maximum number of files allowed in a single upload batch.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Auto-Refresh',
|
||||
icon: RefreshCw,
|
||||
|
||||
Reference in New Issue
Block a user