updated interface
This commit is contained in:
118
app/templates/devices/list.html
Normal file
118
app/templates/devices/list.html
Normal file
@@ -0,0 +1,118 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Devices – Location Management{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="d-flex align-items-center justify-content-between mb-4">
|
||||
<h2 class="fw-bold mb-0">
|
||||
<i class="bi bi-hdd-stack me-2 text-info"></i>Devices
|
||||
</h2>
|
||||
{% if current_user.is_admin() %}
|
||||
<a href="{{ url_for('devices.add_device') }}" class="btn btn-primary">
|
||||
<i class="bi bi-plus-circle me-1"></i> Add Device
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<p class="text-secondary mb-4">
|
||||
Define named, personalized devices (lights, switches, pumps, sensors…) that map to
|
||||
specific relay or input channels on your boards. Devices can be placed on Layout pages
|
||||
as interactive widgets.
|
||||
</p>
|
||||
|
||||
{% if devices %}
|
||||
|
||||
{# Group by area #}
|
||||
{% set areas = devices | map(attribute='area') | unique | list %}
|
||||
{% set no_area = devices | selectattr('area', 'none') | list
|
||||
+ devices | selectattr('area', 'equalto', '') | list
|
||||
+ devices | selectattr('area', 'equalto', None) | list %}
|
||||
|
||||
{# Collect non-empty areas #}
|
||||
{% set named_areas = [] %}
|
||||
{% for d in devices %}
|
||||
{% if d.area and d.area != '' and d.area not in named_areas %}
|
||||
{% set _ = named_areas.append(d.area) %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{# Devices with no area #}
|
||||
{% set ungrouped = [] %}
|
||||
{% for d in devices %}
|
||||
{% if not d.area or d.area == '' %}
|
||||
{% set _ = ungrouped.append(d) %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% for area in named_areas %}
|
||||
<h5 class="text-secondary fw-semibold mb-3 mt-4">
|
||||
<i class="bi bi-geo-alt me-1"></i>{{ area }}
|
||||
</h5>
|
||||
<div class="row g-3 mb-2">
|
||||
{% for device in devices %}
|
||||
{% if device.area == area %}
|
||||
<div class="col-md-6 col-xl-4" id="device-card-{{ device.id }}">
|
||||
{% include "devices/_card.html" %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% if ungrouped %}
|
||||
{% if named_areas %}
|
||||
<h5 class="text-secondary fw-semibold mb-3 mt-4">
|
||||
<i class="bi bi-three-dots me-1"></i>Other
|
||||
</h5>
|
||||
{% endif %}
|
||||
<div class="row g-3 mb-2">
|
||||
{% for device in ungrouped %}
|
||||
<div class="col-md-6 col-xl-4" id="device-card-{{ device.id }}">
|
||||
{% include "devices/_card.html" %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% else %}
|
||||
<div class="text-center py-5 text-secondary">
|
||||
<i class="bi bi-hdd-stack display-4 d-block mb-3 opacity-25"></i>
|
||||
<p class="mb-1">No devices defined yet.</p>
|
||||
{% if current_user.is_admin() %}
|
||||
<a href="{{ url_for('devices.add_device') }}" class="btn btn-sm btn-outline-primary mt-2">
|
||||
<i class="bi bi-plus-circle me-1"></i> Add your first device
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
function deviceToggle(btn, deviceId) {
|
||||
btn.disabled = true;
|
||||
fetch(`/devices/${deviceId}/toggle`, {
|
||||
method: "POST",
|
||||
headers: {"X-Requested-With": "XMLHttpRequest"}
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (!data.ok) { btn.disabled = false; return; }
|
||||
const card = document.getElementById("device-card-" + deviceId);
|
||||
const badge = card.querySelector(".device-state-badge");
|
||||
if (badge) {
|
||||
badge.className = "badge device-state-badge text-bg-" + data.state_color;
|
||||
badge.textContent = data.state_label;
|
||||
}
|
||||
// Update toggle icon
|
||||
btn.className = btn.className.replace(/btn-(outline-)?[a-z]+/, "btn-" + data.state_color);
|
||||
if (data.state) {
|
||||
btn.innerHTML = '<i class="bi bi-power me-1"></i>ON';
|
||||
} else {
|
||||
btn.innerHTML = '<i class="bi bi-power me-1"></i>OFF';
|
||||
}
|
||||
btn.disabled = false;
|
||||
})
|
||||
.catch(() => { btn.disabled = false; });
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user