From 1aa51ca94322c718b5ef052ae69fad9dc2eed37f Mon Sep 17 00:00:00 2001
From: Hitonabi
Date: Thu, 23 Jul 2026 15:30:09 +0200
Subject: [PATCH] UI-Feinschliff: Settings-Tabs funktionieren, Details-Knopf
tut etwas
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- Settings: Tabs waren reine Dekoration (kein onClick, isActive fest) —
jetzt echte Tab-Navigation (Ripping/Verzeichnisse/APIs/Benachrichtigungen)
+ OMDb-Key-Feld im APIs-Tab
- Laufwerk-Details: aufklappbares Panel (Pfad/Modell/Seriennummer/Disc)
mit "Rippen starten" (POST /jobs) und "Auswerfen" (Eject-Endpoint)
- Placebos raus: 4 tote Schnellaktionen, doppelte Geraete-Sektion mit
zweitem totem Details-Knopf, toter Abmelden-Knopf
Co-Authored-By: Claude Fable 5
---
docker/ui/src/App.tsx | 10 +-
docker/ui/src/components/DeviceDiscovery.tsx | 80 ++++++++++++-
docker/ui/src/pages/Dashboard.tsx | 116 +------------------
docker/ui/src/pages/Settings.tsx | 53 ++++++---
4 files changed, 123 insertions(+), 136 deletions(-)
diff --git a/docker/ui/src/App.tsx b/docker/ui/src/App.tsx
index 66a0f8a..1e05aa5 100644
--- a/docker/ui/src/App.tsx
+++ b/docker/ui/src/App.tsx
@@ -1,5 +1,5 @@
import { useState } from 'react'
-import { LayoutDashboard, Disc, Settings, LogOut, Sun, Moon, Terminal } from 'lucide-react'
+import { LayoutDashboard, Disc, Settings, Sun, Moon, Terminal } from 'lucide-react'
import { useDarkMode } from './context/ThemeContext'
import Dashboard from './pages/Dashboard'
import MetadataPreview from './pages/MetadataPreview'
@@ -61,12 +61,8 @@ function App() {
))}
-
-
-
+ {/* Abmelden-Knopf entfernt (23.07.): es gibt (noch) keinen
+ Login-Flow im UI — ein toter Knopf gaukelt nur einen vor. */}
{/* Main Content */}
diff --git a/docker/ui/src/components/DeviceDiscovery.tsx b/docker/ui/src/components/DeviceDiscovery.tsx
index 195f7ca..894d4ae 100644
--- a/docker/ui/src/components/DeviceDiscovery.tsx
+++ b/docker/ui/src/components/DeviceDiscovery.tsx
@@ -16,6 +16,9 @@ interface Device {
export default function DeviceDiscovery() {
const [devices, setDevices] = useState([])
const [loading, setLoading] = useState(true)
+ const [expandedId, setExpandedId] = useState(null)
+ const [actionFeedback, setActionFeedback] = useState(null)
+ const [actionBusy, setActionBusy] = useState(false)
const { theme } = useDarkMode()
const refreshDevices = async () => {
@@ -29,6 +32,33 @@ export default function DeviceDiscovery() {
}
}
+ const startRip = async (device: Device) => {
+ setActionBusy(true)
+ setActionFeedback(null)
+ try {
+ const response = await api.post('/jobs', { device_path: device.path })
+ setActionFeedback(`✓ Job angelegt (${response.data.id.slice(0, 8)}…) — Fortschritt im Dashboard`)
+ } catch (error: any) {
+ setActionFeedback(`✗ ${error?.response?.data?.detail || 'Job konnte nicht angelegt werden'}`)
+ } finally {
+ setActionBusy(false)
+ }
+ }
+
+ const ejectDisc = async (device: Device) => {
+ setActionBusy(true)
+ setActionFeedback(null)
+ try {
+ await api.post(`/devices/${device.id}/eject`)
+ setActionFeedback('✓ Disc ausgeworfen')
+ refreshDevices()
+ } catch (error: any) {
+ setActionFeedback(`✗ ${error?.response?.data?.detail || 'Auswurf fehlgeschlagen'}`)
+ } finally {
+ setActionBusy(false)
+ }
+ }
+
useEffect(() => {
refreshDevices()
const interval = setInterval(refreshDevices, 5000)
@@ -146,10 +176,56 @@ export default function DeviceDiscovery() {
-
-
+ }
{/* Save Button */}
@@ -314,10 +334,11 @@ export default function SettingsPage() {
)
}
-function TabButton({ icon: Icon, label, isActive, darkMode }: { icon: any, label: string, isActive: boolean, darkMode: boolean }) {
+function TabButton({ icon: Icon, label, isActive, onClick, darkMode }: { icon: any, label: string, isActive: boolean, onClick: () => void, darkMode: boolean }) {
const { theme } = useDarkMode()
return (