151 lines
4.7 KiB
React
151 lines
4.7 KiB
React
import { useEffect, useRef, useState } from 'react';
|
|
import { Card } from 'primereact/card';
|
|
import { DataTable } from 'primereact/datatable';
|
|
import { Column } from 'primereact/column';
|
|
import { Tag } from 'primereact/tag';
|
|
import { Button } from 'primereact/button';
|
|
import { Toast } from 'primereact/toast';
|
|
import { api } from '../api/client';
|
|
import { confirmModal } from '../utils/confirmModal';
|
|
|
|
function formatDetectedMediaType(value) {
|
|
const mediaType = String(value || '').trim().toLowerCase();
|
|
if (mediaType === 'bluray') {
|
|
return 'Blu-ray';
|
|
}
|
|
if (mediaType === 'dvd') {
|
|
return 'DVD';
|
|
}
|
|
if (mediaType === 'cd') {
|
|
return 'CD';
|
|
}
|
|
if (mediaType === 'audiobook') {
|
|
return 'Audiobook';
|
|
}
|
|
return 'Sonstiges';
|
|
}
|
|
|
|
export default function DatabasePage() {
|
|
const [orphanRows, setOrphanRows] = useState([]);
|
|
const [orphanLoading, setOrphanLoading] = useState(false);
|
|
const [orphanImportBusyPath, setOrphanImportBusyPath] = useState(null);
|
|
const toastRef = useRef(null);
|
|
|
|
const loadOrphans = async () => {
|
|
setOrphanLoading(true);
|
|
try {
|
|
const response = await api.getOrphanRawFolders();
|
|
setOrphanRows(response.rows || []);
|
|
} catch (error) {
|
|
toastRef.current?.show({ severity: 'error', summary: 'RAW-Prüfung fehlgeschlagen', detail: error.message });
|
|
} finally {
|
|
setOrphanLoading(false);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
void loadOrphans();
|
|
}, []);
|
|
|
|
const handleImportOrphanRaw = async (row) => {
|
|
const target = row?.rawPath || row?.folderName || '-';
|
|
const confirmed = await confirmModal({
|
|
header: 'Historienjob anlegen',
|
|
message: `Für RAW-Ordner "${target}" einen neuen Historienjob anlegen?`,
|
|
acceptLabel: 'Job anlegen',
|
|
rejectLabel: 'Abbrechen'
|
|
});
|
|
if (!confirmed) {
|
|
return;
|
|
}
|
|
|
|
setOrphanImportBusyPath(row.rawPath);
|
|
try {
|
|
const response = await api.importOrphanRawFolder(row.rawPath);
|
|
const newJobId = response?.job?.id;
|
|
toastRef.current?.show({
|
|
severity: 'success',
|
|
summary: 'Job angelegt',
|
|
detail: newJobId ? `Historieneintrag #${newJobId} erstellt.` : 'Historieneintrag wurde erstellt.',
|
|
life: 3500
|
|
});
|
|
await loadOrphans();
|
|
} catch (error) {
|
|
toastRef.current?.show({
|
|
severity: 'error',
|
|
summary: 'Import fehlgeschlagen',
|
|
detail: error.message,
|
|
life: 4500
|
|
});
|
|
} finally {
|
|
setOrphanImportBusyPath(null);
|
|
}
|
|
};
|
|
const orphanTitleBody = (row) => (
|
|
<div>
|
|
<div><strong>{row.title || '-'}</strong></div>
|
|
<small>{row.year || '-'} | {row.imdbId || '-'}</small>
|
|
</div>
|
|
);
|
|
const orphanMediaBody = (row) => (
|
|
<Tag value={formatDetectedMediaType(row?.detectedMediaType)} />
|
|
);
|
|
const orphanPathBody = (row) => (
|
|
<div className="orphan-path-cell">
|
|
{row.rawPath}
|
|
</div>
|
|
);
|
|
const orphanActionBody = (row) => (
|
|
<Button
|
|
label="Job anlegen"
|
|
icon="pi pi-plus"
|
|
size="small"
|
|
onClick={() => handleImportOrphanRaw(row)}
|
|
loading={orphanImportBusyPath === row.rawPath}
|
|
disabled={Boolean(orphanImportBusyPath)}
|
|
/>
|
|
);
|
|
|
|
return (
|
|
<div className="page-grid">
|
|
<Toast ref={toastRef} />
|
|
|
|
<Card
|
|
title="Gefundene RAW-Einträge"
|
|
subTitle="Es werden RAW-Ordner ohne zugehörigen Historienjob aus Settings- und Default-RAW-Pfaden angezeigt."
|
|
>
|
|
<div className="table-filters">
|
|
<Button
|
|
label="RAW prüfen"
|
|
icon="pi pi-search"
|
|
onClick={loadOrphans}
|
|
loading={orphanLoading}
|
|
disabled={Boolean(orphanImportBusyPath)}
|
|
/>
|
|
<Tag value={`${orphanRows.length} gefunden`} severity={orphanRows.length > 0 ? 'warning' : 'success'} />
|
|
</div>
|
|
|
|
<div className="table-scroll-wrap table-scroll-wide">
|
|
<DataTable
|
|
value={orphanRows}
|
|
dataKey="rawPath"
|
|
paginator
|
|
rows={10}
|
|
loading={orphanLoading}
|
|
emptyMessage="Keine verwaisten RAW-Ordner gefunden"
|
|
responsiveLayout="scroll"
|
|
>
|
|
<Column field="folderName" header="RAW-Ordner" style={{ minWidth: '18rem' }} />
|
|
<Column header="Medium" body={orphanMediaBody} style={{ width: '10rem' }} />
|
|
<Column header="Titel" body={orphanTitleBody} style={{ minWidth: '14rem' }} />
|
|
<Column field="entryCount" header="Dateien" style={{ width: '8rem' }} />
|
|
<Column header="Pfad" body={orphanPathBody} style={{ minWidth: '22rem' }} />
|
|
<Column field="lastModifiedAt" header="Geändert" style={{ width: '16rem' }} />
|
|
<Column header="Aktion" body={orphanActionBody} style={{ width: '10rem' }} />
|
|
</DataTable>
|
|
</div>
|
|
</Card>
|
|
</div>
|
|
);
|
|
}
|