Files
battery-tracker-app/templates/device_detail.html
T
iterminate 3bc897c1e5 Add device_type field, mobile-friendly improvements, and device filtering
- 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)
2026-04-12 22:02:29 -05:00

199 lines
8.0 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "base.html" %}
{% block title %}{{ device.name }} — Battery Tracker{% endblock %}
{% block content %}
<h1>{{ device.name }}</h1>
<div class="card">
<table style="width:auto;border:none;">
<tr>
<td style="padding:0.3rem 1rem 0.3rem 0;font-weight:600;color:#64748b;border:none;">Slots</td>
<td style="border:none;">{{ device.installed_count() }} / {{ device.battery_slots }} used</td>
</tr>
{% if device.device_type %}
<tr>
<td style="padding:0.3rem 1rem 0.3rem 0;font-weight:600;color:#64748b;border:none;">Type</td>
<td style="border:none;">{{ device.device_type }}</td>
</tr>
{% endif %}
{% if device.has_mixed_brands() %}
<tr>
<td style="padding:0.3rem 1rem 0.3rem 0;font-weight:600;color:#64748b;border:none;">Warning</td>
<td style="border:none;"><span class="badge badge-warning">⚠ Mixed brands installed</span></td>
</tr>
{% endif %}
{% if device.notes %}
<tr>
<td style="padding:0.3rem 1rem 0.3rem 0;font-weight:600;color:#64748b;border:none;">Notes</td>
<td style="border:none;">{{ device.notes }}</td>
</tr>
{% endif %}
</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 id="install-grid" style="display:grid;grid-template-columns:1fr auto;gap:0.4rem;max-width:400px;align-items:start;margin-bottom:0.5rem;">
<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>
<div class="install-row-pair" style="display:contents;">
<div>
<select onchange="brandSelectChanged(this)">
<option value="">— select —</option>
{% for b in brands|default([]) %}
<option value="{{ b }}">{{ b }}</option>
{% endfor %}
<option value="__new__"> New brand…</option>
</select>
<input type="text" name="brand[]" value=""
placeholder="Type brand name"
style="display:none;margin-top:0.3rem;padding:0.3rem 0.5rem;">
</div>
<input type="number" name="qty[]" value="0" min="0"
style="padding:0.3rem 0.5rem;width:4rem;text-align:center;">
</div>
</div>
<button type="button" class="btn btn-sm btn-secondary" onclick="addInstallRow()" style="margin-bottom:0.75rem;">+ Add brand</button>
<br>
<button class="btn btn-primary" type="submit">Install</button>
</form>
<script>
function editTypeSelectChanged(sel) {
var input = document.getElementById('edit-device-type');
if (sel.value === '__new__') {
input.style.display = ''; input.value = ''; input.focus();
} else {
input.style.display = 'none'; input.value = sel.value;
}
}
function brandSelectChanged(sel) {
var input = sel.nextElementSibling;
if (sel.value === '__new__') {
input.style.display = ''; input.value = ''; input.focus();
} else {
input.style.display = 'none';
input.value = (sel.value === '') ? '' : sel.value;
}
}
function addInstallRow() {
var grid = document.getElementById('install-grid');
var tmpl = grid.querySelector('.install-row-pair');
var clone = tmpl.cloneNode(true);
clone.querySelector('select').value = '';
clone.querySelector('input[type=text]').style.display = 'none';
clone.querySelector('input[type=text]').value = '';
clone.querySelector('input[type=number]').value = '0';
grid.appendChild(clone);
}
</script>
</div>
<div class="card">
<h2>Installed Batteries</h2>
{% set installed = device.batteries | selectattr('status', 'eq', 'installed') | list %}
{% if installed %}
<div class="table-wrap">
<table class="responsive-table">
<thead>
<tr><th>Label</th><th>Brand</th><th>Notes</th><th>Actions</th></tr>
</thead>
<tbody>
{% for b in installed %}
<tr>
<td data-label="Label"><a href="{{ url_for('battery_detail', battery_id=b.id) }}">{{ b.label }}</a></td>
<td data-label="Brand">{{ b.brand }}</td>
<td data-label="Notes" class="text-muted">{{ b.notes or '—' }}</td>
<td data-label="Actions">
<form class="inline" method="post" action="{{ url_for('battery_unassign', battery_id=b.id) }}">
<input type="hidden" name="next" value="{{ url_for('device_detail', device_id=device.id) }}">
<button class="btn btn-sm btn-warning" type="submit">Unassign</button>
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<p class="text-muted">No batteries installed.</p>
{% endif %}
</div>
<div class="card">
<h2>Install Specific Battery</h2>
{% if available_batteries %}
<form method="post" action="{{ url_for('device_install_one', device_id=device.id) }}">
<div class="form-group">
<label for="battery_id">Battery</label>
<select name="battery_id" id="battery_id">
<option value="">— select —</option>
{% for b in available_batteries %}
<option value="{{ b.id }}">{{ b.label }} — {{ b.brand }}
{%- if b.size %} {{ b.size }}{% endif %}
{%- if b.notes %} ({{ b.notes }}){% endif %}</option>
{% endfor %}
</select>
</div>
<button class="btn btn-primary" type="submit">Install</button>
</form>
{% else %}
<p class="text-muted">No available batteries.</p>
{% endif %}
</div>
<div class="card">
<h2>Edit Device</h2>
<form method="post" action="{{ url_for('device_edit', device_id=device.id) }}">
<div class="form-group">
<label for="edit-name">Name</label>
<input type="text" id="edit-name" name="name" value="{{ device.name }}" required>
</div>
<div class="form-group">
<label for="edit-slots">Battery Slots</label>
<input type="number" id="edit-slots" name="battery_slots" value="{{ device.battery_slots }}" min="1" required>
</div>
<div class="form-group">
<label>Type</label>
{% set _preset_types = ['Remote Control','Game Controller','Flashlight','Lock','Sensor','Toy','Clock','Smoke Detector'] %}
<select id="edit-device-type-select" onchange="editTypeSelectChanged(this)">
<option value="">— none —</option>
{% for opt in _preset_types %}
<option value="{{ opt }}" {% if device.device_type == opt %}selected{% endif %}>{{ opt }}</option>
{% endfor %}
{% for opt in device_types|default([]) %}
{% if opt not in _preset_types %}
<option value="{{ opt }}" {% if device.device_type == opt %}selected{% endif %}>{{ opt }}</option>
{% endif %}
{% endfor %}
<option value="__new__" {% if device.device_type and device.device_type not in _preset_types and device.device_type not in device_types|default([]) %}selected{% endif %}>Other…</option>
</select>
<input type="text" id="edit-device-type" name="device_type"
value="{{ device.device_type or '' }}"
placeholder="Enter device type"
style="display:{% if device.device_type and device.device_type not in _preset_types %}''{% else %}none{% endif %};margin-top:0.4rem;">
</div>
<div class="form-group">
<label for="edit-notes">Notes</label>
<textarea id="edit-notes" name="notes">{{ device.notes or '' }}</textarea>
</div>
<button class="btn btn-primary" type="submit">Save Changes</button>
</form>
</div>
<div class="card">
<h2>Delete Device</h2>
<p style="margin-bottom:1rem;" class="text-muted">
Deleting this device will unassign all installed batteries and mark them available.
</p>
<form method="post" action="{{ url_for('device_delete', device_id=device.id) }}">
<button class="btn btn-danger" type="submit">Delete {{ device.name }}</button>
</form>
</div>
<a class="text-muted" href="{{ url_for('device_list') }}">&larr; Back to Devices</a>
{% endblock %}