Add optional battery metadata fields

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.
This commit is contained in:
2026-04-12 14:57:22 -05:00
parent 47e1059532
commit 604d7bb699
5 changed files with 163 additions and 12 deletions
+129 -6
View File
@@ -4,6 +4,15 @@
{% block content %}
<h1>{{ battery.label }}</h1>
{% macro meta_row(label, value) %}
{% if value %}
<tr>
<td style="padding:0.3rem 1rem 0.3rem 0;font-weight:600;color:#64748b;border:none;">{{ label }}</td>
<td style="border:none;">{{ value }}</td>
</tr>
{% endif %}
{% endmacro %}
<div class="card">
<table style="width:auto;border:none;">
<tr>
@@ -28,17 +37,117 @@
{% endif %}
</td>
</tr>
{{ meta_row("Size", battery.size) }}
{{ meta_row("Chemistry", battery.chemistry) }}
{% if battery.capacity_mah %}
<tr>
<td style="padding:0.3rem 1rem 0.3rem 0;font-weight:600;color:#64748b;border:none;">Capacity</td>
<td style="border:none;">
{{ battery.capacity_mah }} mAh
{% if battery.tested_capacity_mah %}
{% set pct = (battery.tested_capacity_mah / battery.capacity_mah * 100)|round|int %}
{% if pct >= 80 %}{% set health_color = "#166534" %}
{% elif pct >= 60 %}{% set health_color = "#92400e" %}
{% else %}{% set health_color = "#991b1b" %}
{% endif %}
&rarr; tested <strong style="color:{{ health_color }};">{{ battery.tested_capacity_mah }} mAh ({{ pct }}%)</strong>
{% if battery.tested_date %}<span class="text-muted">on {{ battery.tested_date }}</span>{% endif %}
{% endif %}
</td>
</tr>
{% elif battery.tested_capacity_mah %}
<tr>
<td style="padding:0.3rem 1rem 0.3rem 0;font-weight:600;color:#64748b;border:none;">Tested Capacity</td>
<td style="border:none;">
{{ battery.tested_capacity_mah }} mAh
{% if battery.tested_date %}<span class="text-muted">on {{ battery.tested_date }}</span>{% endif %}
</td>
</tr>
{% endif %}
{{ meta_row("Charge Cycles", battery.charge_cycles) }}
{{ meta_row("Purchase Date", battery.purchase_date) }}
{% if battery.notes %}
<tr>
<td style="padding:0.3rem 1rem 0.3rem 0;font-weight:600;color:#64748b;border:none;">Notes</td>
<td style="border:none;">{{ battery.notes }}</td>
</tr>
{% endif %}
</table>
</div>
<!-- Notes -->
<!-- Edit Details -->
<div class="card">
<h2>Notes</h2>
<form method="post" action="{{ url_for('battery_edit_notes', battery_id=battery.id) }}">
<div class="form-group">
<textarea name="notes" placeholder="No notes yet…">{{ battery.notes or '' }}</textarea>
<h2>Edit Details</h2>
<form method="post" action="{{ url_for('battery_edit_details', battery_id=battery.id) }}">
<div style="display:grid;grid-template-columns:1fr 1fr;gap:0 1rem;">
<div class="form-group">
<label>Size</label>
<select id="size-select" onchange="metaSelectChanged(this,'size')">
<option value="">— none —</option>
{% for opt in ['AA','AAA','C','D','9V','18650','21700','14500','26650','CR2032','CR123A'] %}
<option value="{{ opt }}" {% if battery.size == opt %}selected{% endif %}>{{ opt }}</option>
{% endfor %}
<option value="__new__" {% if battery.size and battery.size not in ['AA','AAA','C','D','9V','18650','21700','14500','26650','CR2032','CR123A'] %}selected{% endif %}>Other…</option>
</select>
<input type="text" id="size" name="size" value="{{ battery.size or '' }}"
placeholder="Enter size"
style="display:{% if battery.size and battery.size not in ['AA','AAA','C','D','9V','18650','21700','14500','26650','CR2032','CR123A'] %}''{% else %}none{% endif %};margin-top:0.4rem;">
</div>
<div class="form-group">
<label>Chemistry</label>
<select id="chemistry-select" onchange="metaSelectChanged(this,'chemistry')">
<option value="">— none —</option>
{% for opt in ['NiMH','Alkaline','Li-ion','LiFePO4','NiCd','Zinc-Carbon','Li-MnO2'] %}
<option value="{{ opt }}" {% if battery.chemistry == opt %}selected{% endif %}>{{ opt }}</option>
{% endfor %}
<option value="__new__" {% if battery.chemistry and battery.chemistry not in ['NiMH','Alkaline','Li-ion','LiFePO4','NiCd','Zinc-Carbon','Li-MnO2'] %}selected{% endif %}>Other…</option>
</select>
<input type="text" id="chemistry" name="chemistry" value="{{ battery.chemistry or '' }}"
placeholder="Enter chemistry"
style="display:{% if battery.chemistry and battery.chemistry not in ['NiMH','Alkaline','Li-ion','LiFePO4','NiCd','Zinc-Carbon','Li-MnO2'] %}''{% else %}none{% endif %};margin-top:0.4rem;">
</div>
<div class="form-group">
<label for="capacity_mah">Capacity (mAh)</label>
<input type="number" id="capacity_mah" name="capacity_mah" min="0"
value="{{ battery.capacity_mah or '' }}" placeholder="e.g. 2000">
</div>
<div class="form-group">
<label for="charge_cycles">Charge Cycles</label>
<input type="number" id="charge_cycles" name="charge_cycles" min="0"
value="{{ battery.charge_cycles or '' }}" placeholder="e.g. 50">
</div>
<div class="form-group">
<label for="tested_capacity_mah">Tested Capacity (mAh)</label>
<input type="number" id="tested_capacity_mah" name="tested_capacity_mah" min="0"
value="{{ battery.tested_capacity_mah or '' }}" placeholder="e.g. 1850">
</div>
<div class="form-group">
<label for="tested_date">Test Date</label>
<input type="date" id="tested_date" name="tested_date"
value="{{ battery.tested_date or '' }}">
</div>
<div class="form-group">
<label for="purchase_date">Purchase Date</label>
<input type="date" id="purchase_date" name="purchase_date"
value="{{ battery.purchase_date or '' }}">
</div>
</div>
<button class="btn btn-primary" type="submit">Save Notes</button>
<div class="form-group">
<label for="notes">Notes</label>
<textarea id="notes" name="notes" placeholder="No notes yet…">{{ battery.notes or '' }}</textarea>
</div>
<button class="btn btn-primary" type="submit">Save Details</button>
</form>
</div>
@@ -67,4 +176,18 @@
</div>
<a class="text-muted" href="{{ url_for('dashboard') }}">&larr; Back to Dashboard</a>
<script>
function metaSelectChanged(sel, inputId) {
var input = document.getElementById(inputId);
if (sel.value === '__new__') {
input.style.display = '';
input.value = '';
input.focus();
} else {
input.style.display = 'none';
input.value = sel.value;
}
}
</script>
{% endblock %}