Files
POPS/app/templates/bracket_detail.html
Martin Hohenberg 6868862d77 Replace combined filament dropdown with separate material + color dropdowns
- app/constants.py: MATERIALS and COLORS standard value lists
- Migration 0008: job_material + job_color columns on print_jobs
- Job creation (both /jobs and /brackets/{id}/jobs) stores these independently
  of the filament inventory
- All job tables updated to display job_material · job_color

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 22:08:29 +02:00

171 lines
7.4 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 %}{{ bracket.name }} — POPS{% endblock %}
{% block content %}
{% set total = bracket.jobs | length %}
{% set done = bracket.jobs | selectattr('status.value', 'equalto', 'done') | list | length %}
{% set printing = bracket.jobs | selectattr('status.value', 'equalto', 'printing') | list | length %}
{% set pct = (done / total * 100) | int if total else 0 %}
<div class="d-flex align-items-center gap-3 mb-4">
<a href="/brackets" class="text-secondary text-decoration-none"><i class="bi bi-arrow-left"></i></a>
<div class="flex-grow-1">
<h5 class="text-white mb-0">{{ bracket.name }}</h5>
{% if bracket.customer %}<small class="text-secondary">{{ bracket.customer }}</small>{% endif %}
</div>
<button class="btn btn-sm btn-primary" data-bs-toggle="modal" data-bs-target="#addJobsModal">
<i class="bi bi-plus-lg me-1"></i>Add Job(s)
</button>
</div>
{# ── Progress ── #}
{% if total %}
<div class="card mb-4 p-3">
<div class="d-flex justify-content-between mb-2">
<span class="text-secondary small">{{ done }} done · {{ printing }} printing · {{ total - done - printing }} queued</span>
<span class="text-secondary small">{{ pct }}%</span>
</div>
<div class="progress" style="height:8px">
<div class="progress-bar bg-success" style="width:{{ pct }}%"></div>
</div>
</div>
{% endif %}
{# ── Jobs table ── #}
<div class="card">
{% if bracket.jobs %}
<table class="table table-dark table-hover mb-0 align-middle" style="font-size:.875rem">
<thead>
<tr class="text-secondary small">
<th class="fw-normal">UUID</th>
<th class="fw-normal">File</th>
<th class="fw-normal">Material</th>
<th class="fw-normal">Printer</th>
<th class="fw-normal">Status</th>
<th class="fw-normal text-end">Created</th>
</tr>
</thead>
<tbody>
{% for j in bracket.jobs %}
<tr>
<td class="font-monospace text-secondary" style="font-size:.75rem">
{{ j.job_uuid[:8] if j.job_uuid else '—' }}
</td>
<td class="text-white">{{ j.file_name or j.name }}</td>
<td class="text-secondary">
{% if j.job_material %}{{ j.job_material }}{% if j.job_color %} · {{ j.job_color }}{% endif %}{% else %}—{% endif %}
</td>
<td class="text-secondary">{{ j.printer.name if j.printer else '—' }}</td>
<td>
{% set s = j.status.value %}
{% if s == 'printing' %}<span class="badge bg-primary">printing</span>
{% elif s == 'done' %}<span class="badge bg-success">done</span>
{% elif s == 'failed' %}<span class="badge bg-danger">failed</span>
{% elif s == 'cancelled' %}<span class="badge bg-warning text-dark">cancelled</span>
{% else %}<span class="badge bg-secondary">queued</span>
{% endif %}
</td>
<td class="text-secondary text-end">{{ j.created_at.strftime('%d.%m %H:%M') }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<div class="card-body text-secondary">No jobs in this bracket yet.</div>
{% endif %}
</div>
{# ── Add Jobs Modal ── #}
<div class="modal fade" id="addJobsModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content bg-dark border-secondary">
<form method="POST" action="/brackets/{{ bracket.id }}/jobs" enctype="multipart/form-data">
<div class="modal-header border-secondary">
<h6 class="modal-title text-white">Add Job(s) to Bracket</h6>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body d-flex flex-column gap-3">
{# STL file #}
<div>
<label class="form-label text-secondary small">STL / File</label>
<ul class="nav nav-pills mb-2" role="tablist">
<li class="nav-item">
<button class="nav-link active py-1 px-3" style="font-size:.8rem"
data-bs-toggle="pill" data-bs-target="#bUploadPane" type="button">
<i class="bi bi-upload me-1"></i>Upload
</button>
</li>
<li class="nav-item">
<button class="nav-link py-1 px-3" style="font-size:.8rem"
data-bs-toggle="pill" data-bs-target="#bLibraryPane" type="button">
<i class="bi bi-folder2-open me-1"></i>Library
<span class="badge bg-secondary ms-1">{{ stl_files | length }}</span>
</button>
</li>
</ul>
<div class="tab-content">
<div class="tab-pane fade show active" id="bUploadPane">
<input type="file" name="stl_file"
class="form-control bg-dark border-secondary text-white"
accept=".stl,.3mf,.gcode">
</div>
<div class="tab-pane fade" id="bLibraryPane">
{% if stl_files %}
<select name="stl_select" class="form-select bg-dark border-secondary text-white">
<option value="">— select file —</option>
{% for f in stl_files %}
{% set c = stl_cache.get(f) %}
<option value="{{ f }}">{{ f }}{% if c %} — {{ c.cube_x|round(1) }}×{{ c.cube_y|round(1) }}×{{ c.cube_z|round(1) }} mm · {{ c.volume_ccm }} cm³{% endif %}</option>
{% endfor %}
</select>
{% else %}
<p class="text-secondary small mb-0">No files in library yet.</p>
{% endif %}
</div>
</div>
</div>
<div class="row g-3">
<div class="col-md-4">
<label class="form-label text-secondary small">Material</label>
<select name="job_material" class="form-select bg-dark border-secondary text-white">
<option value="">— none —</option>
{% for m in materials %}<option>{{ m }}</option>{% endfor %}
</select>
</div>
<div class="col-md-4">
<label class="form-label text-secondary small">Color</label>
<select name="job_color" class="form-select bg-dark border-secondary text-white">
<option value="">— none —</option>
{% for c in colors %}<option>{{ c }}</option>{% endfor %}
</select>
</div>
<div class="col-md-4">
<label class="form-label text-secondary small">
Quantity
<span class="text-secondary fw-normal">(copies to create)</span>
</label>
<input type="number" name="quantity"
class="form-control bg-dark border-secondary text-white"
value="1" min="1" max="500">
</div>
</div>
<div>
<label class="form-label text-secondary small">Notes</label>
<textarea name="notes" class="form-control bg-dark border-secondary text-white"
rows="2" placeholder="Optional notes (applied to all copies)"></textarea>
</div>
</div>
<div class="modal-footer border-secondary">
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-primary btn-sm">Add Jobs</button>
</div>
</form>
</div>
</div>
</div>
{% endblock %}