0.11.0 Multi LW
This commit is contained in:
@@ -1036,23 +1036,23 @@ export default function DashboardPage({
|
||||
}
|
||||
}, [pipeline?.state, metadataDialogVisible, metadataDialogContext?.jobId]);
|
||||
|
||||
// Auto-open CD metadata dialog when pipeline enters CD_METADATA_SELECTION
|
||||
// Auto-open CD metadata dialog when any drive enters CD_METADATA_SELECTION
|
||||
useEffect(() => {
|
||||
const currentState = String(pipeline?.state || '').trim().toUpperCase();
|
||||
if (currentState === 'CD_METADATA_SELECTION') {
|
||||
const ctx = pipeline?.context && typeof pipeline.context === 'object' ? pipeline.context : null;
|
||||
if (ctx?.jobId && !cdMetadataDialogVisible) {
|
||||
const cdDrives = pipeline?.cdDrives;
|
||||
if (!cdDrives || typeof cdDrives !== 'object') return;
|
||||
for (const drive of Object.values(cdDrives)) {
|
||||
const driveState = String(drive?.state || '').trim().toUpperCase();
|
||||
const ctx = drive?.context && typeof drive.context === 'object' ? drive.context : null;
|
||||
if (driveState === 'CD_METADATA_SELECTION' && ctx?.jobId && !cdMetadataDialogVisible) {
|
||||
setCdMetadataDialogContext(ctx);
|
||||
setCdMetadataDialogVisible(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (currentState === 'CD_READY_TO_RIP') {
|
||||
const ctx = pipeline?.context && typeof pipeline.context === 'object' ? pipeline.context : null;
|
||||
if (ctx?.jobId) {
|
||||
if (driveState === 'CD_READY_TO_RIP' && ctx?.jobId) {
|
||||
setCdRipPanelJobId(ctx.jobId);
|
||||
}
|
||||
}
|
||||
}, [pipeline?.state, pipeline?.context?.jobId]);
|
||||
}, [pipeline?.cdDrives]);
|
||||
|
||||
useEffect(() => {
|
||||
setQueueState(normalizeQueue(pipeline?.queue));
|
||||
@@ -1314,6 +1314,19 @@ export default function DashboardPage({
|
||||
await handleAnalyze();
|
||||
};
|
||||
|
||||
const handleAnalyzeForDrive = async (devicePath) => {
|
||||
setBusy(true);
|
||||
try {
|
||||
await api.analyzeDisc(devicePath);
|
||||
await refreshPipeline();
|
||||
await loadDashboardJobs();
|
||||
} catch (error) {
|
||||
showError(error);
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleRescan = async () => {
|
||||
setBusy(true);
|
||||
try {
|
||||
@@ -1969,7 +1982,11 @@ export default function DashboardPage({
|
||||
}
|
||||
};
|
||||
|
||||
const device = lastDiscEvent || pipeline?.context?.device;
|
||||
// CD drives are tracked per-drive in pipeline.cdDrives — exclude them from the single-drive display
|
||||
const lastNonCdDiscEvent = lastDiscEvent?.mediaProfile !== 'cd' ? lastDiscEvent : null;
|
||||
const contextDevice = pipeline?.context?.device;
|
||||
const device = lastNonCdDiscEvent || (contextDevice?.mediaProfile !== 'cd' ? contextDevice : null);
|
||||
const cdDriveEntries = Object.entries(pipeline?.cdDrives || {});
|
||||
const isDriveActive = driveActiveStates.includes(state);
|
||||
const canRescan = !isDriveActive;
|
||||
const canReanalyze = !isDriveActive && (state === 'ENCODING' ? Boolean(device) : !processingStates.includes(state));
|
||||
@@ -2236,6 +2253,74 @@ export default function DashboardPage({
|
||||
disabled={!canOpenMetadataModal}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Per-drive CD sections */}
|
||||
{cdDriveEntries.length > 0 && (
|
||||
<div className="cd-drives-section">
|
||||
{cdDriveEntries.map(([drivePath, drive]) => {
|
||||
const driveState = String(drive?.state || '').trim().toUpperCase();
|
||||
const driveDevice = drive?.device || {};
|
||||
const driveJobId = normalizeJobId(drive?.jobId);
|
||||
const driveCtx = drive?.context && typeof drive.context === 'object' ? drive.context : {};
|
||||
const cdStateSeverity = driveState === 'FINISHED' ? 'success'
|
||||
: driveState === 'ERROR' || driveState === 'CANCELLED' ? 'danger'
|
||||
: ['CD_RIPPING', 'CD_ENCODING'].includes(driveState) ? 'warning'
|
||||
: 'info';
|
||||
return (
|
||||
<div key={drivePath} className="cd-drive-item">
|
||||
<div className="cd-drive-header">
|
||||
<strong>{driveDevice.model || 'CD-Laufwerk'}</strong>
|
||||
<code className="cd-drive-path">{drivePath}</code>
|
||||
<Tag value={driveState} severity={cdStateSeverity} />
|
||||
</div>
|
||||
{driveDevice.discLabel && (
|
||||
<div className="cd-drive-disc-label">
|
||||
<strong>Disc:</strong> {driveDevice.discLabel}
|
||||
</div>
|
||||
)}
|
||||
<div className="cd-drive-actions">
|
||||
{driveState === 'DISC_DETECTED' && (
|
||||
<Button
|
||||
label="CD analysieren"
|
||||
icon="pi pi-search"
|
||||
size="small"
|
||||
onClick={() => handleAnalyzeForDrive(drivePath)}
|
||||
loading={busy}
|
||||
disabled={busy}
|
||||
/>
|
||||
)}
|
||||
{driveState === 'CD_METADATA_SELECTION' && (
|
||||
<Button
|
||||
label="Metadaten auswählen"
|
||||
icon="pi pi-list"
|
||||
size="small"
|
||||
severity="info"
|
||||
onClick={() => {
|
||||
setCdMetadataDialogContext({ ...driveCtx, jobId: driveJobId });
|
||||
setCdMetadataDialogVisible(true);
|
||||
}}
|
||||
disabled={!driveJobId}
|
||||
/>
|
||||
)}
|
||||
{(driveState === 'ERROR' || driveState === 'CANCELLED') && driveJobId && (
|
||||
<Button
|
||||
label="Erneut analysieren"
|
||||
icon="pi pi-refresh"
|
||||
size="small"
|
||||
severity="warning"
|
||||
onClick={() => handleAnalyzeForDrive(drivePath)}
|
||||
loading={busy}
|
||||
disabled={busy}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Non-CD / legacy single-drive display */}
|
||||
<div className="dashboard-drive-state">
|
||||
{device
|
||||
? <Tag value="Disk eingelegt" severity="success" icon="pi pi-circle-fill" />
|
||||
@@ -2260,7 +2345,7 @@ export default function DashboardPage({
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<p>Aktuell keine Disk erkannt.</p>
|
||||
cdDriveEntries.length === 0 ? <p>Aktuell keine Disk erkannt.</p> : null
|
||||
)}
|
||||
</Card>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user