feat: Enhance duplicate series handling with deselect functionality and UI updates

This commit is contained in:
Ross
2026-05-11 12:20:51 +01:00
parent 22c5576fc9
commit 7ac8517062
+44 -2
View File
@@ -67,7 +67,12 @@
</div>
<div id="selection-summary" class="alert alert-secondary py-2 mb-3 d-none"></div>
<div id="duplicate-progress" class="small text-muted mb-2"></div>
<div class="d-flex flex-wrap align-items-center gap-2 mb-2">
<div id="duplicate-progress" class="small text-muted"></div>
<button type="button" id="deselect-duplicates" class="btn btn-sm btn-outline-danger d-none">
<i class="bi bi-x-circle me-1"></i>Deselect all duplicates
</button>
</div>
<div class="alert alert-warning d-none anon-alert" role="alert">
<p class="mb-2">Potential anonymisation issues were detected. Flagged series are highlighted below.</p>
@@ -431,6 +436,7 @@
function updateUploadButtonState() {
const uploadButton = document.getElementById("uploadButton");
const anonAlert = document.querySelector(".anon-alert");
const deselectDuplicatesBtn = document.getElementById("deselect-duplicates");
const hasSelected = window.uploadPreview.records.some(r => r.include);
const hasWarnings = hasAnonymisationWarnings();
const hasDuplicates = window.uploadPreview.records.some(r => r.include && r.duplicate);
@@ -439,6 +445,9 @@
window.uploadPreview.records.some((r) => r.include && !r.duplicateChecked);
renderAnonymisationIssueSummary();
if (deselectDuplicatesBtn) {
deselectDuplicatesBtn.classList.toggle("d-none", !hasDuplicates);
}
if (!hasSelected) {
uploadButton.disabled = true;
@@ -483,14 +492,36 @@
}
function getSeriesStatusClass(series) {
const includeCount = series.files.filter(f => f.include).length;
if (!includeCount) return "series-card excluded";
const hasTagWarnings = series.files.some(f => f.tagWarnings.length > 0);
const hasOcrWarnings = series.files.some(f => f.ocrWarning);
const hasDuplicates = series.files.some(f => f.duplicate);
const hasDuplicates = series.files.some(f => f.include && f.duplicate);
if (hasTagWarnings || hasOcrWarnings) return "series-card warning";
if (hasDuplicates) return "series-card duplicate";
return "series-card";
}
function deselectDuplicateSeries() {
const duplicateSeriesUids = new Set(
window.uploadPreview.records
.filter((record) => record.include && record.duplicate)
.map((record) => record.seriesUid)
);
if (!duplicateSeriesUids.size) {
toastr.info("No selected duplicate series to deselect.");
return;
}
duplicateSeriesUids.forEach((seriesUid) => applyIncludeToSeries(seriesUid, false));
window.uploadPreview.forceAnonymisationOverride = false;
scheduleDuplicateCheck();
renderGroupedPreview();
toastr.info(`Deselected ${duplicateSeriesUids.size} duplicate series.`);
}
function renderGroupedPreview() {
const groupedRoot = document.getElementById("preupload-grouped");
const grouped = window.uploadPreview.grouped;
@@ -1264,6 +1295,10 @@
renderGroupedPreview();
});
bindIfExists("deselect-duplicates", "click", () => {
deselectDuplicateSeries();
});
bindIfExists("show-thumbnails", "change", () => {
renderGroupedPreview();
});
@@ -1339,6 +1374,13 @@
background: rgba(220, 53, 69, 0.08);
}
.series-card.excluded {
border-color: rgba(148, 163, 184, 0.35);
background: rgba(148, 163, 184, 0.08);
opacity: 0.55;
filter: grayscale(0.25);
}
.series-header {
display: flex;
justify-content: space-between;