Add case selection modal for importing series into existing cases
This commit is contained in:
@@ -130,6 +130,7 @@
|
||||
type="button"
|
||||
class="btn btn-primary"
|
||||
>Import {% if case %}into case{% endif %}</button>
|
||||
<button id="import-into-case-button" type="button" class="btn btn-outline-primary" data-bs-toggle="modal" data-bs-target="#caseSelectModal">Import into case…</button>
|
||||
</div>
|
||||
|
||||
<div id="import-status"></div>
|
||||
@@ -167,7 +168,104 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Case select modal for importing into an existing case -->
|
||||
<div class="modal fade" id="caseSelectModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Import into case</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mb-2">
|
||||
<label for="case-search-input-modal" class="form-label">Search cases</label>
|
||||
<input id="case-search-input-modal" name="q" class="form-control" type="search"
|
||||
placeholder="Type to search cases..."
|
||||
hx-get="{% url 'atlas:case_search' %}"
|
||||
hx-include="#case-search-input-modal"
|
||||
hx-target="#case-search-results-modal"
|
||||
hx-trigger="keyup changed delay:400ms"
|
||||
autocomplete="off">
|
||||
</div>
|
||||
<div id="case-search-results-modal" class="mt-2">
|
||||
<!-- initial empty state; results will be loaded by HTMX -->
|
||||
<div class="text-muted small">Type to search cases to import into.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Handle selecting a case from the modal results to import selected series into it
|
||||
document.body.addEventListener('click', async function (e) {
|
||||
// Only handle clicks inside the case select modal results
|
||||
const anchor = e.target.closest('#case-search-results-modal .list-group-item, #case-search-results-modal .list-group-item-action');
|
||||
if (!anchor) return;
|
||||
e.preventDefault();
|
||||
// Determine case pk: prefer data-case-pk, else parse from href
|
||||
let casePk = anchor.getAttribute('data-case-pk');
|
||||
if (!casePk) {
|
||||
const href = anchor.getAttribute('href') || '';
|
||||
const m = href.match(/case\/(\d+)\/?$/);
|
||||
if (m) casePk = m[1];
|
||||
}
|
||||
if (!casePk) {
|
||||
console.error('Could not determine case id for import');
|
||||
return;
|
||||
}
|
||||
|
||||
// Gather selected series (same logic as import button)
|
||||
const selected = Array.from(document.querySelectorAll('input[name="selection"]:checked'))
|
||||
.filter(cb => !cb.disabled)
|
||||
.map(cb => cb.value);
|
||||
const allCheckboxes = Array.from(document.querySelectorAll('input[name="selection"]'));
|
||||
const selectable = allCheckboxes.filter(cb => !cb.disabled).map(cb => cb.value);
|
||||
const selection = selected.length ? selected : selectable;
|
||||
if (!selection.length) {
|
||||
alert('Please select at least one series to import into the case.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Build import URL template and replace trailing 0 with casePk
|
||||
const importTemplate = "{% url 'api-1:import_dicoms_case' 0 %}";
|
||||
const importUrl = importTemplate.replace(/0\/?$/, casePk + '/');
|
||||
|
||||
const form = new URLSearchParams();
|
||||
for (const s of selection) form.append('selection', s);
|
||||
const orderSeriesInput = document.querySelector('input[name="order-series"]:checked');
|
||||
if (orderSeriesInput) form.append('order-series', orderSeriesInput.value);
|
||||
|
||||
const csrfToken = '{{ csrf_token }}';
|
||||
|
||||
try {
|
||||
const resp = await fetch(importUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'X-CSRFToken': csrfToken,
|
||||
},
|
||||
body: form.toString(),
|
||||
credentials: 'same-origin'
|
||||
});
|
||||
const text = await resp.text();
|
||||
// Close modal and show result in import-status
|
||||
const modalEl = document.getElementById('caseSelectModal');
|
||||
if (modalEl && window.bootstrap && bootstrap.Modal) {
|
||||
bootstrap.Modal.getInstance(modalEl)?.hide();
|
||||
}
|
||||
const statusDiv = document.getElementById('import-status');
|
||||
if (statusDiv) statusDiv.innerHTML = `<div>Imported into case ${casePk}: ${text}</div>`;
|
||||
// Optionally reload to reflect imported state
|
||||
setTimeout(function(){ location.reload(); }, 1200);
|
||||
} catch (err) {
|
||||
console.error('Import into case failed', err);
|
||||
alert('Import failed — check console for details.');
|
||||
}
|
||||
});
|
||||
// Update the selected count shown beside action buttons
|
||||
function updateSelectionCount() {
|
||||
const all = Array.from(document.querySelectorAll('input[name="selection"]'));
|
||||
|
||||
Reference in New Issue
Block a user