+
+ {audiobookUploadStatusLabel}
+
-
- Modell: {device.model || '-'}
-
-
- Disk-Label: {device.discLabel || '-'}
-
-
- Laufwerks-Label: {device.label || '-'}
-
-
-
Mount: {device.mountpoint || '-'}
+ {audiobookUpload?.statusText ?
{audiobookUpload.statusText} : null}
+ {audiobookUploadFileName ? (
+
+ Datei: {audiobookUploadFileName}
+
+ ) : null}
+
+
+
+ {audiobookUploadPhase === 'processing'
+ ? '100% | Upload fertig, Job wird vorbereitet ...'
+ : audiobookUploadTotalBytes > 0
+ ? `${Math.round(audiobookUploadProgress)}% | ${formatBytes(audiobookUploadLoadedBytes)} / ${formatBytes(audiobookUploadTotalBytes)}`
+ : `${Math.round(audiobookUploadProgress)}%`}
+
+ ) : null}
+
+ {audiobookUploadFileName && audiobookUploadPhase === 'idle'
+ ? `Ausgewählt: ${audiobookUploadFileName}`
+ : 'Unterstützt im MVP: AAX-Upload. Danach erscheint ein eigener Audiobook-Startschritt mit Format- und Qualitätswahl.'}
+
+
+
+
+
+
+
+
+ {queueState?.cdBypassesQueue && }
+ 0 ? 'warning' : 'success'} />
+ 0 ? 'warning' : 'success'} />
+ 0 ? 'warning' : 'success'} />
+
+
+
+
+
Laufende Jobs
+ {queueRunningJobs.length === 0 ? (
+
Keine laufenden Jobs.
+ ) : (
+ queueRunningJobs.map((item) => {
+ const hasScriptSummary = hasQueueScriptSummary(item);
+ const detailKey = buildRunningQueueScriptKey(item?.jobId);
+ const detailsExpanded = hasScriptSummary && expandedQueueScriptKeys.has(detailKey);
+ return (
+
+
+
+
+ #{item.jobId} | {item.title || `Job #${item.jobId}`}
+ {item.hasScripts ? : null}
+ {item.hasChains ? : null}
+
+ {getStatusLabel(item.status)}
+
+ {hasScriptSummary ? (
+
+ ) : null}
+
+ {detailsExpanded ?
: null}
+
+ );
+ })
+ )}
+
+
+
+
Warteschlange
+
+
+ {queuedJobs.length === 0 ? (
+
Queue ist leer.
+ ) : (
+ <>
+ {queuedJobs.map((item) => {
+ const entryId = Number(item?.entryId);
+ const isNonJob = item.type && item.type !== 'job';
+ const isDragging = Number(draggingQueueEntryId) === entryId;
+ const hasScriptSummary = !isNonJob && hasQueueScriptSummary(item);
+ const detailKey = buildQueuedQueueScriptKey(entryId);
+ const detailsExpanded = hasScriptSummary && expandedQueueScriptKeys.has(detailKey);
+ return (
+
+
setDraggingQueueEntryId(entryId)}
+ onDragEnter={() => handleQueueDragEnter(entryId)}
+ onDragOver={(event) => event.preventDefault()}
+ onDrop={(event) => {
+ event.preventDefault();
+ void handleQueueDrop();
+ }}
+ onDragEnd={() => {
+ setDraggingQueueEntryId(null);
+ void syncQueueFromServer();
+ }}
+ >
+
+
+
+
+
+ {isNonJob ? (
+ {item.position || '-'}. {queueEntryLabel(item)}
+ ) : (
+ <>
+
+ {item.position || '-'} | #{item.jobId} | {item.title || `Job #${item.jobId}`}
+ {item.hasScripts ? : null}
+ {item.hasChains ? : null}
+
+ {item.actionLabel || item.action || '-'} | {getStatusLabel(item.status)}
+ >
+ )}
+
+
+ {hasScriptSummary ? (
+
+ ) : null}
+
+
+ {detailsExpanded ?
: null}
+
+
+ );
+ })}
+ >
+ )}
+
+
+
+
+
+
+ 0 ? 'warning' : 'success'} />
+
+
+
+
+ {runtimeLoading && runtimeActiveItems.length === 0 && runtimeRecentItems.length === 0 ? (
+ Aktivitäten werden geladen ...
) : (
- Aktuell keine Disk erkannt.
+
+
+
Aktiv
+ {runtimeActiveItems.length === 0 ? (
+
Keine laufenden Skript-/Ketten-/Cron-Ausführungen.
+ ) : (
+
+ {runtimeActiveItems.map((item, index) => {
+ const statusMeta = runtimeStatusMeta(item?.status);
+ const canCancel = Boolean(item?.canCancel);
+ const canNextStep = String(item?.type || '').trim().toLowerCase() === 'chain' && Boolean(item?.canNextStep);
+ const cancelBusy = isRuntimeActionBusy(item?.id, 'cancel');
+ const nextStepBusy = isRuntimeActionBusy(item?.id, 'next-step');
+ return (
+
+
+
{item?.name || '-'}
+
+
+
+
+
+
+ Quelle: {item?.source || '-'}
+ {item?.jobId ? ` | Job #${item.jobId}` : ''}
+ {item?.cronJobId ? ` | Cron #${item.cronJobId}` : ''}
+
+ {item?.currentStep ?
Schritt: {item.currentStep} : null}
+ {item?.currentScriptName ?
Laufendes Skript: {item.currentScriptName} : null}
+ {item?.message ?
{item.message} : null}
+
+
Gestartet: {formatUpdatedAt(item?.startedAt)}
+ {canCancel || canNextStep ? (
+
+ {canNextStep ? (
+
+ ) : null}
+
+ );
+ })}
+
+ )}
+
+
+
+
Zuletzt abgeschlossen
+ {runtimeRecentItems.length === 0 ? (
+
Keine abgeschlossenen Einträge vorhanden.
+ ) : (
+
+ {runtimeRecentItems.map((item, index) => {
+ const outcomeMeta = runtimeOutcomeMeta(item?.outcome, item?.status);
+ return (
+
+
+
{item?.name || '-'}
+
+
+
+
+
+
+ Quelle: {item?.source || '-'}
+ {item?.jobId ? ` | Job #${item.jobId}` : ''}
+ {item?.cronJobId ? ` | Cron #${item.cronJobId}` : ''}
+
+ {Number.isFinite(Number(item?.exitCode)) ?
Exit-Code: {item.exitCode} : null}
+ {item?.message ?
{item.message} : null}
+ {item?.errorMessage ?
{item.errorMessage} : null}
+ {hasRuntimeOutputDetails(item) ? (
+
+ ) : null}
+
+ Ende: {formatUpdatedAt(item?.finishedAt || item?.startedAt)}
+ {item?.durationMs != null ? ` | Dauer: ${formatDurationMs(item.durationMs)}` : ''}
+
+
+ );
+ })}
+
+ )}
+
+
)}
+