Grotti 3.7.0: Treiber für Kobra 4 und Marlin, smartere Dateien-Auswahl und einstellbare Etiketten.

Senden und Abbruch laufen über den Treiber, Orca-Doppelzeilen und tote Ideen-API fallen weg, Drucker folgen der Datei, Etikettenformat liegt in den Einstellungen.
This commit is contained in:
Dominic Gundel committed 2026-11-02 14:03:57 +01:00
1 parent 5081212212
commit db6a85a703
54 files changed
+3379 -384

No files matched your search

+92 -1
View File
@@ -107,6 +107,7 @@
{% endif %}
</div>
<div class="topbar-tools">
<button type="button" class="icon-btn" id="meldung-open" title="Problem melden" aria-label="Problem melden"><svg class="ico"><use href="#i-alert"/></svg></button>
<a class="icon-btn {{ 'on' if page == 'einstellungen' else '' }}" href="/einstellungen" title="Einstellungen" aria-label="Einstellungen"><svg class="ico"><use href="#i-settings"/></svg></a>
<a class="icon-btn {{ 'on' if page == 'doku' else '' }}" href="/doku" title="Doku" aria-label="Doku"><svg class="ico"><use href="#i-book"/></svg></a>
{% if current_user %}
@@ -163,6 +164,22 @@
{% endif %}
<form method="dialog"><button class="ghost" value="cancel">Schließen</button></form>
</dialog>
<dialog id="meldung-dlg" class="abraeumen-dlg">
<form method="dialog" id="meldung-form" class="abraeumen-form">
<h2>Problem melden</h2>
<p class="tiny">Kurz beschreiben. Grotti hängt Version und Seite an und speichert eine Kopie hier. Zusätzlich geht die Meldung an den Entwickler.</p>
<div class="field">
<label for="meldung-text">Was stimmt nicht?</label>
<textarea id="meldung-text" rows="5" required maxlength="4000" placeholder="z. B. Start auf dem Tenlog bricht ab…"></textarea>
</div>
<p class="tiny" id="meldung-error-hint" hidden></p>
<div class="actions">
<button type="submit" class="btn-primary" id="meldung-send">Senden</button>
<button type="button" class="ghost" id="meldung-cancel">Abbrechen</button>
</div>
<p id="meldung-note" class="tiny"></p>
</form>
</dialog>
<script src="{{ url_for('static', filename='api.js') }}?v=33"></script>
<script src="{{ url_for('static', filename='ui.js') }}?v=6"></script>
<script>
@@ -172,6 +189,80 @@ async function doLogout() {
}
document.getElementById("logout-btn")?.addEventListener("click", doLogout);
document.getElementById("logout-btn-m")?.addEventListener("click", doLogout);
(function meldungUi() {
const dlg = document.getElementById("meldung-dlg");
const form = document.getElementById("meldung-form");
const text = document.getElementById("meldung-text");
const errHint = document.getElementById("meldung-error-hint");
const note = document.getElementById("meldung-note");
if (!dlg || !form) return;
let lastError = "";
function openMeldung(prefill) {
note.textContent = "";
note.className = "tiny";
if (prefill) text.value = prefill;
if (lastError) {
errHint.hidden = false;
errHint.textContent = "Letzter Fehler: " + lastError.slice(0, 240);
} else {
errHint.hidden = true;
errHint.textContent = "";
}
dlg.showModal();
text.focus();
}
window.openMeldung = openMeldung;
window.rememberUiError = (message) => {
lastError = String(message || "").slice(0, 2000);
};
document.getElementById("meldung-open")?.addEventListener("click", () => openMeldung(""));
document.getElementById("meldung-cancel")?.addEventListener("click", () => dlg.close());
form.addEventListener("submit", async (event) => {
event.preventDefault();
const button = document.getElementById("meldung-send");
button.disabled = true;
try {
const desk = document.querySelector("#desk[data-host]:not([hidden])");
const host = desk?.dataset?.host || "";
const row = await api("/meldungen", {
method: "POST",
json: {
text: text.value,
page: location.pathname + location.search + location.hash,
printer_host: host,
error_text: lastError,
},
});
if (row.relay_ok) {
toast("Meldung gespeichert und an den Entwickler geschickt.", "good");
} else {
toast("Lokal gespeichert. Beim Entwickler nicht angekommen: " + (row.relay_message || ""), "bad");
}
text.value = "";
lastError = "";
dlg.close();
} catch (error) {
note.textContent = error.message || String(error);
note.className = "tiny msg";
} finally {
button.disabled = false;
}
});
window.addEventListener("error", (event) => {
const message = event?.message || String(event?.error || "");
if (message) lastError = message.slice(0, 2000);
});
window.addEventListener("unhandledrejection", (event) => {
const reason = event?.reason;
const message = reason && reason.message ? reason.message : String(reason || "");
if (message) lastError = message.slice(0, 2000);
});
});
(function userMenuClose() {
const menu = document.getElementById("user-menu");
if (!menu) return;
@@ -624,8 +715,8 @@ refreshJetzt();
aufgaben: () => refreshJetzt(),
drucker: () => {
refreshJetzt();
// Nur onDruckerLive — sonst zeichnen Wand und Dateien doppelt.
if (typeof window.onDruckerLive === "function") window.onDruckerLive();
if (typeof window.onQueueChanged === "function") window.onQueueChanged();
},
};