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:
@@ -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 %}
|
||||
→ 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') }}">← 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 %}
|
||||
|
||||
Reference in New Issue
Block a user