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:
1 parent
5081212212
commit
db6a85a703
54 files changed
+3379
-384
No files matched your search
@@ -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();
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user