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)
This commit is contained in:
@@ -10,6 +10,12 @@
|
||||
<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>
|
||||
@@ -56,6 +62,14 @@
|
||||
</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__') {
|
||||
@@ -83,17 +97,17 @@ function addInstallRow() {
|
||||
{% set installed = device.batteries | selectattr('status', 'eq', 'installed') | list %}
|
||||
{% if installed %}
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<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><a href="{{ url_for('battery_detail', battery_id=b.id) }}">{{ b.label }}</a></td>
|
||||
<td>{{ b.brand }}</td>
|
||||
<td class="text-muted">{{ b.notes or '—' }}</td>
|
||||
<td>
|
||||
<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>
|
||||
@@ -131,6 +145,45 @@ function addInstallRow() {
|
||||
{% 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">
|
||||
|
||||
Reference in New Issue
Block a user