Grotti 3.4.0: Dateien umbenennen, Bedarf/PLA-Match, Pause- und gklib-Fixes.

This commit is contained in:
Dominic Gundel committed 2026-10-18 21:36:12 +02:00
1 parent 67a89d1794
commit dd0e7ebc6b
16 files changed
+430 -58

No files matched your search

+48 -9
View File
@@ -360,17 +360,37 @@ function spoolWarnText() {
const hosts = selectedHosts();
const fileTypes = ((file.filaments || []).map((f) => (f.type || "").toLowerCase()).filter(Boolean));
const fileProfiles = ((file.filaments || []).map((f) => (f.profile || "").toLowerCase()).filter(Boolean));
const PROFILE_VARIANTS = ["meta", "matte", "matt", "silk", "plus", "hf", "cf"];
function profileHasVariant(want) {
return PROFILE_VARIANTS.some((v) => new RegExp("\\b" + v + "\\b", "i").test(want || ""));
}
function profileBaseType(want) {
const m = String(want || "").toLowerCase().match(/\b(pla|petg|abs|asa|tpu|pa|pc|hips|pva)\b/);
return m ? m[1] : "";
}
function profileOk(spoolRows) {
if (!fileProfiles.length) return true;
const names = spoolRows.map((s) => (s.name || "").toLowerCase()).filter(Boolean);
if (!names.length) return true;
return fileProfiles.every((want) => names.some((n) => {
if (n === want) return true;
if (!n.startsWith(want) || /[a-z0-9]/i.test(n.charAt(want.length) || "")) return false;
const rest = n.slice(want.length).replace(/^[\s·\-_|/]+/, "");
const first = (rest.split(/\s+/)[0] || "").toLowerCase();
return !["meta", "matte", "matt", "silk", "plus", "hf", "cf"].includes(first);
}));
const types = spoolRows.map((s) => (s.material_type || "").toLowerCase()).filter(Boolean);
if (!names.length && !types.length) return true;
return fileProfiles.every((want) => {
if (names.some((n) => {
if (n === want) return true;
if (!n.startsWith(want) || /[a-z0-9]/i.test(n.charAt(want.length) || "")) return false;
const rest = n.slice(want.length).replace(/^[\s·\-_|/]+/, "");
const first = (rest.split(/\s+/)[0] || "").toLowerCase();
return !PROFILE_VARIANTS.includes(first);
})) return true;
// Basis-Profil (nur „… PLA“): Typ reicht, Marke egal — keine Meta/Matte-Spule
if (profileHasVariant(want)) return false;
const kind = profileBaseType(want);
if (!kind) return true;
return spoolRows.some((s) => {
const t = (s.material_type || "").toLowerCase();
const n = (s.name || "").toLowerCase();
return t === kind && !profileHasVariant(n);
});
});
}
for (const host of hosts) {
const name = (printers.find((p) => p.host === host) || {}).name || host;
@@ -827,11 +847,12 @@ function thumbHtml(file) {
function libItemHtml(file) {
const project = projects.find((p) => String(p.id) === String(file.project_id));
const rename = `<button type="button" class="icon-btn" data-rename="${file.id}" title="Umbenennen">${icon("edit")}</button>`;
const del = `<button type="button" class="icon-btn" data-delete="${file.id}" title="Datei löschen">${icon("trash")}</button>`;
return `<div class="lib-item ${String(file.id) === String(sel.fileId) ? "on" : ""}" role="button" tabindex="0" data-file="${file.id}">
${thumbHtml(file)}
<span style="min-width:0"><span class="t" title="${escapeHtml(file.name)}">${escapeHtml(file.name)}</span><span class="m">${alwaysMeta(file, project)}</span></span>
<span class="side">${moveSelectHtml(file)}${infoPopupHtml(file)}${del}</span>
<span class="side">${moveSelectHtml(file)}${infoPopupHtml(file)}${rename}${del}</span>
</div>`;
}
@@ -1530,6 +1551,24 @@ document.getElementById("lib-list").addEventListener("click", (event) => {
event.stopPropagation();
return;
}
const ren = event.target.closest("[data-rename]");
if (ren) {
event.stopPropagation();
const file = files.find((f) => String(f.id) === String(ren.dataset.rename));
if (!file) return;
const next = window.prompt("Neuer Dateiname:", file.name);
if (next == null) return;
const trimmed = String(next).trim();
if (!trimmed || trimmed === file.name) return;
api("/dateien/" + file.id + "/umbenennen", { method: "POST", json: { name: trimmed } })
.then(async (saved) => {
toast("Umbenannt in „" + (saved.name || trimmed) + "“.", "good");
await load();
if (saved && saved.id) selectFile(saved.id);
})
.catch((error) => toast(error.message || String(error), "bad"));
return;
}
const del = event.target.closest("[data-delete]");
if (del) {
event.stopPropagation();