feat(ui): Toast-Feedback ueberall, Job-Detail-Popup, System-Tab, Wizard-Media-Server, Favicon, Footer

- ToastContext: jede Aktion quittiert sichtbar ('Erfolgreich aktualisiert'
  ploppt oben rechts rein) — Refresh-Knoepfe drehen jetzt wirklich
  (Laufwerke, Logs, Worker, Speicherziele).
- JobDetailModal: Klick auf Titel in 'Neueste Jobs' -> Poster, Jahr,
  Beschreibung, Genres, Ablagepfad, Fehler.
- Logs: Filter-Pills um Warnung + Fehler ergaenzt (vorher nur
  Alle/Info/Erfolg).
- Speicherziele: Benutzer/Passwort VOR dem 'Freigaben auflisten'-Knopf
  (Windows/NAS lehnen Gast-Abfragen ab — genau daher kam das
  NT_STATUS_ACCESS_DENIED), Hinweistext, Toasts beim Einhaengen/Entfernen.
- Datei-Browser (Speicherziele + Rip-Ziel-Dialog) zeigt Dateien grau mit
  Groesse — Ordner wirkten faelschlich leer.
- Einstellungen: neuer System-Tab (Werkzeug-Versionen je Worker, Key-Status,
  Plattenplatz, MakeMKV-Beta-Key-Feld), Media-Server-Wahl im Ripping-Tab,
  Arbeitsverzeichnis im Verarbeitung-Tab, Benachrichtigungs-Anleitung
  (Discord/ntfy/Slack) + 'Test senden'.
- First-Run-Wizard: Media-Server-Schritt (Jellyfin/Emby/Kodi/Plex/Keins).
- Favicon (Disc im Logo-Verlauf, public/favicon.svg — /vite.svg war 404)
  + Footer 'Created with (Herz) by LucyAI, Claude and KrBrZ'.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-07-24 08:55:42 +02:00
parent e032a9df1c
commit 13c1ae6064
16 changed files with 722 additions and 76 deletions
+11 -2
View File
@@ -3,6 +3,7 @@ import { Clock, Activity, AlertCircle, CheckCircle, Disc } from 'lucide-react'
import { api } from '../lib/api'
import { useDarkMode } from '../context/ThemeContext'
import DeviceDiscovery from '../components/DeviceDiscovery'
import JobDetailModal from '../components/JobDetailModal'
import LiveLogSection from '../components/LiveLogSection'
interface Job {
@@ -139,6 +140,7 @@ export default function Dashboard() {
const [jobs, setJobs] = useState<Job[]>([])
const [workers, setWorkers] = useState<WorkerInfo[]>([])
const [loading, setLoading] = useState(true)
const [detailJobId, setDetailJobId] = useState<string | null>(null)
const { theme } = useDarkMode()
useEffect(() => {
@@ -281,9 +283,13 @@ export default function Dashboard() {
<TypeBadge type={job.type} />
</td>
<td className="px-6 py-4 whitespace-nowrap">
<div className={`text-sm font-medium ${theme === 'dark' ? 'text-slate-100' : 'text-slate-900'}`}>
<button
onClick={() => setDetailJobId(job.id)}
title="Details zu diesem Titel anzeigen"
className={`text-sm font-medium text-left hover:underline transition-colors ${theme === 'dark' ? 'text-slate-100 hover:text-indigo-300' : 'text-slate-900 hover:text-indigo-600'}`}
>
{job.title || 'Unbekannt'}
</div>
</button>
</td>
<td className="px-6 py-4 whitespace-nowrap">
<StatusBadge status={job.status} />
@@ -327,6 +333,9 @@ export default function Dashboard() {
{/* Live-Log ganz unten — Detail-Ansicht, nicht Haupt-Info */}
<LiveLogSection />
{/* Klick auf einen Job-Titel: Film-/Serien-Info + Job-Fakten */}
<JobDetailModal jobId={detailJobId} onClose={() => setDetailJobId(null)} />
</div>
)
}