Select multiple batteries, pick a date, and optionally increment charge
cycles for all of them in one shot. Reuses the existing bulk-action form
and POST /battery/bulk-action route; no new routes or migrations needed.
- Device dropdowns (quick-assign, bulk install, assign page) now only show
devices with free slots; full devices are excluded entirely
- New ChargeLog model tracks charge dates with optional cycle increment;
battery detail page gets a Charge History card with add/delete rows
- Device list page gets per-device Unassign All button (with confirmation)
via new POST /device/<id>/unassign-all route
Adds Web App Manifest, a minimal Service Worker, and Apple/Android meta
tags so the app can be added to a phone home screen and opens full-screen
in standalone mode (no browser chrome).
- static/manifest.json: name, short_name, display=standalone, icons
- static/sw.js: minimal SW served at /sw.js (root scope) via new Flask route
- static/icon-192.png, icon-512.png: generated by sbin/gen_icons.py (stdlib only)
- base.html: manifest link, theme-color, apple-mobile-web-app-* tags, SW registration
- New CapacityTest model (battery_id FK CASCADE, mah, date, notes)
- DB migration: create capacity_test table, migrate existing single-test data
- Two new routes: add and delete capacity test records
- Battery.tested_capacity_mah/tested_date kept in sync with latest test
so dashboard display requires no changes
- Battery detail: Capacity History card with sortable table, health %
per reading, and a canvas line chart (shown when >= 2 records)
- Chart uses CSS variables for colors — works in light and dark mode
- Remove tested_capacity_mah/tested_date from Edit Details form
- 3 new acceptance tests (48 total)
- Device model: add device_type column (String 50, nullable)
- Device add/edit: type select with presets + custom entry
- Device detail: show type in info card; new Edit Device form
- Device list: Type column + client-side filter bar (type + text search)
- Mobile: card-style responsive tables on dashboard and device list,
form-grid-2col collapse, larger tap targets, stacked form-actions,
column picker viewport fix, filter bar full-width controls
- Assign page: larger radio touch targets (min-height 44px)
- 3 new acceptance tests for device_type (45 total)
- Dashboard bulk toolbar: select batteries, pick a device, click 'Install
in device'; confirms before moving already-installed batteries; enforces
slot capacity and warns on brand mix
- Battery detail: 'Unretire Battery' button replaces 'Retire Battery' when
battery is retired, restoring it to available status
- Tests: 3 new bulk-install-device tests (capacity block, move, success);
42 total passing
- Dashboard: replace Assign link with device dropdown + arrow button for
quick inline assignment without leaving the page
- Device detail: replace hardcoded 4-row install form with 1 row + '+ Add
brand' button that clones rows dynamically
- Device detail: add 'Install Specific Battery' card with dropdown of all
available batteries (label, brand, size, notes) via new /device/<id>/install-one route
- Tests: 4 new acceptance tests covering dashboard quick-assign and
install-one, including capacity enforcement on both paths (39 total)
New nullable columns on Battery: size, chemistry, capacity_mah,
tested_capacity_mah, tested_date, charge_cycles, purchase_date.
Battery detail page shows all populated fields and a full edit form
with select dropdowns for size and chemistry (with Other fallback).
Capacity health % shown in green/orange/red when both nominal and
tested capacity are set. Dashboard gains a Size column.