222 lines
9.1 KiB
HTML
222 lines
9.1 KiB
HTML
{% 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 %}
|
||
{% if ha_enabled and device.ha_entity_id %}
|
||
<tr>
|
||
<td style="padding:0.3rem 1rem 0.3rem 0;font-weight:600;color:#64748b;border:none;">HA Entity</td>
|
||
<td style="border:none;"><code>{{ device.ha_entity_id }}</code></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" id="installed">
|
||
<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>{% if ha_enabled %}<th>Bat %</th>{% endif %}<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>
|
||
{% if ha_enabled %}
|
||
<td data-label="Bat %">
|
||
{% if b.battery_percentage is not none %}
|
||
{% if b.battery_percentage < 20 %}
|
||
<span class="badge badge-warning" title="Low — consider replacing">⚠ {{ b.battery_percentage }}%</span>
|
||
{% else %}{{ b.battery_percentage }}%{% endif %}
|
||
{% else %}—{% endif %}
|
||
</td>
|
||
{% endif %}
|
||
<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) }}#installed">
|
||
<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>
|
||
{% if ha_enabled %}
|
||
<div class="form-group">
|
||
<label for="edit-ha-entity">Home Assistant Entity ID</label>
|
||
<input type="text" id="edit-ha-entity" name="ha_entity_id"
|
||
value="{{ device.ha_entity_id or '' }}"
|
||
placeholder="e.g. sensor.tv_remote_battery">
|
||
</div>
|
||
{% endif %}
|
||
<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') }}">← Back to Devices</a>
|
||
{% endblock %}
|