import React, { useState, useEffect } from 'react' import { Folder, ChevronRight, ChevronUp, X, Check, Loader2, FileAudio, AlertCircle, Info } from 'lucide-react' import api from '../../api/client' interface Entry { name: string; path: string; isDir: boolean } interface MountInfo { mountPoint: string; fsType: string; source: string } interface RootInfo { path: string; exists: boolean; entryCount?: number | null; permError?: boolean } interface Props { initialPath?: string onSelect: (path: string) => void onClose: () => void } export default function FileBrowser({ initialPath = '/', onSelect, onClose }: Props) { const [path, setPath] = useState(initialPath) const [entries, setEntries] = useState([]) const [parent, setParent] = useState(null) const [loading, setLoading] = useState(false) const [error, setError] = useState('') const [showDiagnose, setShowDiagnose] = useState(false) const [diagnose, setDiagnose] = useState<{ mounts: MountInfo[]; candidateRoots: RootInfo[]; hint: string } | null>(null) const load = async (p: string) => { setLoading(true) setError('') try { const r = await api.get('/api/filebrowser', { params: { path: p } }) setPath(r.data.path) setParent(r.data.parent) setEntries(r.data.entries) } catch (err: any) { setError(err.response?.data?.detail || 'Fehler beim Laden') } finally { setLoading(false) } } const loadDiagnose = async () => { try { const r = await api.get('/api/filebrowser/diagnose') setDiagnose(r.data) } catch {} } useEffect(() => { load(initialPath) }, []) useEffect(() => { loadDiagnose() }, []) const visibleRoots = diagnose?.candidateRoots?.filter((r) => r.exists) || [] const quickPaths = ['/audiofiles', ...visibleRoots.map((r) => r.path).filter((p) => p !== '/audiofiles'), '/'] return (
e.stopPropagation()} > {/* Header */}

Ordner auswählen

{/* Diagnose-Panel */} {showDiagnose && diagnose && (

Aktive Volume-Mounts im Container:

{diagnose.mounts.length === 0 ? (

Keine Mounts gefunden

) : (
{diagnose.mounts.map((m, i) => (
{m.mountPoint} ({m.fsType})
))}
)}

Top-Level-Verzeichnisse:

{diagnose.candidateRoots.map((r) => (
{r.exists ? ( ) : ( × )} {r.path} {r.exists && r.entryCount !== null && r.entryCount !== undefined && ( ({r.entryCount} Einträge) )} {r.permError && (kein Zugriff)}
))}

{diagnose.hint}

)} {/* Quick access */}
{quickPaths.map((p) => ( ))}
{/* Current path */}
{parent && ( )}

{path}

{/* Entry list */}
{loading ? (
) : error ? (

{error}

Falls dein Mount auf der Host-Maschine existiert, aber hier nicht sichtbar ist: er muss in docker-compose.yml als Volume gemountet werden. Setze EXTRA_AUDIO_PATH=/dein/pfad in der .env und starte mit docker-compose down && docker-compose up -d neu. Klick oben auf für Details.

) : entries.length === 0 ? (

Ordner ist leer

) : ( entries.map((e) => e.isDir ? ( ) : (
{e.name}
) ) )}
{/* Footer */}
) }