94 lines
3.7 KiB
HTML
94 lines
3.7 KiB
HTML
{% extends "base.html" %}
|
|
{% block title %}Scopes · {{ app_name }}{% endblock %}
|
|
{% block body %}
|
|
{% include "_nav.html" %}
|
|
<main class="container">
|
|
<h1>Scopes</h1>
|
|
<p class="muted">
|
|
Every scope on record, with the accessories that fit it. Each part-type
|
|
column lists matching parts; <span class="fit-badge fit-badge-exact">Exact</span>
|
|
is a confirmed fit, <span class="fit-badge fit-badge-possible">Possible</span> a candidate.
|
|
</p>
|
|
|
|
<div class="filter-bar">
|
|
<form hx-get="/scopes/filter"
|
|
hx-target="#scopes-table-card"
|
|
hx-trigger="input delay:300ms, change"
|
|
hx-swap="outerHTML">
|
|
<input type="text" name="description" placeholder="Search by description or product ID…"
|
|
value="{{ filters.description or '' }}">
|
|
<select name="manufacturer_id">
|
|
<option value="">All manufacturers</option>
|
|
{% for m in manufacturers %}
|
|
<option value="{{ m.id }}" {{ "selected" if filters.manufacturer_id and filters.manufacturer_id|int == m.id }}>{{ m.name }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
<select name="scope_model_id">
|
|
<option value="">All models</option>
|
|
{% for sm in scope_models %}
|
|
<option value="{{ sm.id }}" {{ "selected" if filters.scope_model_id and filters.scope_model_id|int == sm.id }}>{{ sm.name }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
<select name="sub_part_type_id">
|
|
<option value="">All types</option>
|
|
{% for spt in sub_part_types %}
|
|
<option value="{{ spt.id }}" {{ "selected" if filters.sub_part_type_id and filters.sub_part_type_id|int == spt.id }}>{{ spt.name }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
<select name="fits_part_type_id">
|
|
<option value="">Fits any accessory</option>
|
|
{% for ct in column_types %}
|
|
<option value="{{ ct.id }}" {{ "selected" if filters.fits_part_type_id and filters.fits_part_type_id|int == ct.id }}>Fits {{ ct.name }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</form>
|
|
</div>
|
|
|
|
{% if can_write_scopes %}
|
|
<div class="bulk-actions">
|
|
<button id="delete-selected-scopes-btn" type="button" class="btn btn-danger" disabled
|
|
hx-post="/scopes/bulk-delete"
|
|
hx-include="[name='scope_ids']:checked, [name='description'], [name='manufacturer_id'], [name='scope_model_id'], [name='sub_part_type_id'], [name='fits_part_type_id']"
|
|
hx-target="#scopes-table-card"
|
|
hx-swap="outerHTML"
|
|
hx-confirm="Delete selected scopes?">Delete selected</button>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% include "_scopes_table_card.html" %}
|
|
</main>
|
|
|
|
{% if can_write_scopes %}
|
|
<script>
|
|
(function () {
|
|
function updateDeleteButton() {
|
|
var count = document.querySelectorAll('input[name="scope_ids"]:checked').length;
|
|
var btn = document.getElementById('delete-selected-scopes-btn');
|
|
if (!btn) return;
|
|
btn.textContent = count > 0 ? 'Delete selected (' + count + ')' : 'Delete selected';
|
|
btn.disabled = count === 0;
|
|
btn.setAttribute('hx-confirm', 'Delete ' + count + ' selected scope' + (count === 1 ? '' : 's') + '?');
|
|
}
|
|
|
|
document.addEventListener('change', function (e) {
|
|
if (!e.target) return;
|
|
|
|
if (e.target.id === 'scopes-select-all') {
|
|
document.querySelectorAll('input[name="scope_ids"]').forEach(function (cb) {
|
|
cb.checked = e.target.checked;
|
|
});
|
|
}
|
|
|
|
if (e.target.id === 'scopes-select-all' || e.target.name === 'scope_ids') {
|
|
updateDeleteButton();
|
|
}
|
|
});
|
|
|
|
// Re-run after every HTMX swap (filter results, post-delete) so the button
|
|
// state reflects the freshly rendered checkboxes, which start unchecked.
|
|
document.addEventListener('htmx:afterSwap', updateDeleteButton);
|
|
}());
|
|
</script>
|
|
{% endif %}
|
|
{% endblock %}
|