feat: viewer local upload, Bambu collapse, planning done/fail, stats waste, portal link in jobs, sidebar collapsible, settings layout fix
Deploy via Portainer / deploy (push) Successful in 0s

This commit is contained in:
Jo
2026-07-07 09:16:24 +02:00
parent 7b65c4b2e2
commit b22e5e0fb4
9 changed files with 502 additions and 78 deletions
+103
View File
@@ -81,4 +81,107 @@
</div>
</div>
</div>
<!-- ── Gaspillage & Échecs ──────────────────────────────────────────────────── -->
<div class="row g-4 mt-0">
<!-- Gaspillage par matière -->
<div class="col-md-6">
<div class="card">
<div class="card-header py-3">
<i class="bi bi-trash3 text-danger me-2"></i>Filament gaspillé par matière
</div>
<div class="card-body p-0">
{% if waste_by_material %}
{% set max_waste = waste_by_material | map(attribute='wasted_g') | max %}
<table class="table table-hover mb-0">
<thead class="table-light">
<tr>
<th>Matière</th>
<th class="text-end">Gaspillé</th>
<th class="text-end text-muted small">Stock restant</th>
</tr>
</thead>
<tbody>
{% for m in waste_by_material %}
<tr>
<td>
{% if m.color %}
<span style="display:inline-block;width:10px;height:10px;border-radius:50%;
background:{{ m.color | css_color }};border:1px solid #ccc;
vertical-align:middle;margin-right:5px"></span>
{% endif %}
<span class="fw-semibold">{{ m.name }}</span>
{% if m.type %}<span class="badge bg-light text-dark ms-1 small">{{ m.type }}</span>{% endif %}
</td>
<td class="text-end">
<span class="text-danger fw-bold">{{ m.wasted_g }} g</span>
{% if max_waste > 0 %}
<div class="progress mt-1" style="height:3px">
<div class="progress-bar bg-danger" style="width:{{ (m.wasted_g / max_waste * 100)|round(0) }}%"></div>
</div>
{% endif %}
</td>
<td class="text-end text-muted small">{{ m.stock_g }} g</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<div class="text-center text-muted py-4">
<i class="bi bi-check-circle text-success fs-2 d-block mb-2"></i>
Aucun gaspillage enregistré.
</div>
{% endif %}
</div>
</div>
</div>
<!-- Taux d'échec par imprimante -->
<div class="col-md-6">
<div class="card">
<div class="card-header py-3">
<i class="bi bi-printer text-warning me-2"></i>Taux d'échec par imprimante
</div>
<div class="card-body p-0">
{% if failure_by_printer %}
<table class="table table-hover mb-0">
<thead class="table-light">
<tr>
<th>Imprimante</th>
<th class="text-center">Taux</th>
<th class="text-end">Gaspillé</th>
</tr>
</thead>
<tbody>
{% for p in failure_by_printer %}
{% set rate = (p.failed_slots / p.total_slots * 100) | round(1) %}
<tr>
<td>
<div class="fw-semibold">{{ p.name }}</div>
<div class="text-muted small">{{ p.failed_slots }}/{{ p.total_slots }} créneaux</div>
</td>
<td class="text-center">
<span class="badge {% if rate >= 20 %}bg-danger{% elif rate >= 10 %}bg-warning text-dark{% else %}bg-success{% endif %}">
{{ rate }}%
</span>
</td>
<td class="text-end {% if p.wasted_g > 0 %}text-danger{% else %}text-muted{% endif %} fw-semibold">
{{ p.wasted_g }} g
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<div class="text-center text-muted py-4">
<i class="bi bi-check-circle text-success fs-2 d-block mb-2"></i>
Aucun échec enregistré.
</div>
{% endif %}
</div>
</div>
</div>
</div>
{% endblock %}