Grotti 3.6.0: Lauf-Identität nach Filament-Pause, robustere Queue, Projekte/Aufträge list-first und API-Polish.

This commit is contained in:
Dominic Gundel committed 2026-10-25 08:24:24 +01:00
1 parent d1eb87ba25
commit 2b1e36634a
53 files changed
+4254 -636

No files matched your search

+33 -8
View File
@@ -19,14 +19,18 @@
<button type="button" data-period="last_week" class="fchip">Letzte Woche</button>
<button type="button" data-period="last_month" class="fchip">Letzter Monat</button>
</div>
<div class="stat-filters">
<input type="date" id="since" title="Von" class="date-field">
<input type="date" id="until" title="Bis" class="date-field">
<select id="host"><option value="">Alle Drucker</option></select>
<input type="text" id="material" placeholder="Sorte" size="8" autocomplete="off">
<input type="text" id="brand" placeholder="Marke" size="8" autocomplete="off">
<input type="text" id="color" placeholder="Farbe" size="8" autocomplete="off">
</div>
<details class="stat-more">
<summary>Weitere Filter</summary>
<div class="stat-filters">
<input type="date" id="since" title="Von" class="date-field">
<input type="date" id="until" title="Bis" class="date-field">
<select id="host"><option value="">Alle Drucker</option></select>
<select id="project"><option value="">Alle Projekte</option></select>
<input type="text" id="material" placeholder="Sorte" size="8" autocomplete="off">
<input type="text" id="brand" placeholder="Marke" size="8" autocomplete="off">
<input type="text" id="color" placeholder="Farbe" size="8" autocomplete="off">
</div>
</details>
</div>
<p id="stat-note"></p>
<div id="stat" class="statistik"></div>
@@ -231,17 +235,37 @@ function render(data) {
</div>`;
}
async function fillProjects() {
const select = document.getElementById("project");
if (!select || select.dataset.filled) return;
try {
const rows = await api("/projekte?status=");
const current = select.value;
rows.forEach((p) => {
const opt = document.createElement("option");
opt.value = p.id;
opt.textContent = p.name;
select.appendChild(opt);
});
select.dataset.filled = "1";
if ([...select.options].some((o) => o.value === current)) select.value = current;
} catch (error) { /* optional */ }
}
async function load() {
await fillProjects();
const params = new URLSearchParams();
const since = document.getElementById("since").value;
const until = document.getElementById("until").value;
const host = document.getElementById("host").value;
const project = document.getElementById("project").value;
const material = document.getElementById("material").value.trim();
const brand = document.getElementById("brand").value.trim();
const color = document.getElementById("color").value.trim();
if (since) params.set("since", since);
if (until) params.set("until", until);
if (host) params.set("host", host);
if (project) params.set("project_id", project);
if (material) params.set("material", material);
if (brand) params.set("brand", brand);
if (color) params.set("color", color);
@@ -278,6 +302,7 @@ document.getElementById("period").addEventListener("click", (event) => {
});
});
document.getElementById("host").addEventListener("change", scheduleLoad);
document.getElementById("project").addEventListener("change", scheduleLoad);
["material", "brand", "color"].forEach((id) => {
const node = document.getElementById(id);
if (!node) return;