Simplify battery management: bulk add, device-level auto-install, mass operations

- Replace single-battery add form with bulk add (brand + count, auto-generated labels)
- Add device-level install form: specify brand+qty pairs, system autoselects available batteries
- Add bulk actions on dashboard: retire, delete, unassign, change brand (checkbox multi-select)
- Keep per-battery assign route for special cases (e.g. known low-capacity battery)
- Remove unique constraint on Battery.label (labels are now auto-generated)
- Add *.snapshot to .gitignore for DB snapshot files
- Rewrite tests: 35 passing (11 new tests for bulk-add, device-install, bulk-actions)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-12 12:57:10 -05:00
parent 2e36d5f53c
commit 1f5234a3e9
8 changed files with 403 additions and 131 deletions
+18
View File
@@ -25,6 +25,24 @@
</table>
</div>
<div class="card">
<h2>Install Batteries</h2>
{% set free_slots = device.battery_slots - device.installed_count() %}
<p class="text-muted" style="margin-bottom:0.75rem;">{{ free_slots }} slot(s) free</p>
<form method="post" action="{{ url_for('device_install', device_id=device.id) }}">
<div style="display:grid;grid-template-columns:1fr auto;gap:0.4rem;max-width:360px;align-items:center;margin-bottom:0.75rem;">
<span style="font-weight:600;font-size:0.85rem;color:#64748b;">Brand</span>
<span style="font-weight:600;font-size:0.85rem;color:#64748b;">Qty</span>
{% for _ in range(4) %}
<input type="text" name="brand[]" placeholder="e.g. Eneloop" style="padding:0.3rem 0.5rem;">
<input type="number" name="qty[]" value="0" min="0"
style="padding:0.3rem 0.5rem;width:4rem;text-align:center;">
{% endfor %}
</div>
<button class="btn btn-primary" type="submit">Install</button>
</form>
</div>
<div class="card">
<h2>Installed Batteries</h2>
{% set installed = device.batteries | selectattr('status', 'eq', 'installed') | list %}