Bugtracker in „Bugs" umbenennen und Erfolgsmeldung einblenden

Reiter, Panel, Käfer-Beschriftungen und Doku sprechen von Bugs statt
Fehlern. Nach dem Senden schließt sich das Panel sofort und eine
Einblendung bestätigt die Meldung.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
ferdi2goandClaude Fable 5.1 committed 2026-10-15 08:27:01 +00:00
1 parent 4ec23ccd25
commit e8ab95159e
5 files changed
+32 -31

No files matched your search

+1 -1
View File
@@ -1 +1 @@
Rotatory lost fair und zufällig aus, wer das tägliche Morning Meeting moderiert: pro Wochentag ein Hauptmoderator und ein Nebenmoderator aus der Belegschaft. Urlaub, Krankheit, Feiertage, Teilzeit-Freitage und Personen, die nicht moderieren, werden automatisch berücksichtigt. Die Monatsübersicht zeigt auf jedem Tag die Fotos der beiden Moderatoren, sodass jeder auf einen Blick sieht, wer dran ist. Einzelne Tage lassen sich manuell festlegen oder neu auslosen. Die Belegschaft samt Fotos und die Abwesenheiten kommen auf Wunsch direkt aus der Nextcloud, und auf Knopfdruck landet der Plan als Termine im geteilten Nextcloud-Kalender des Teams. Teammitglieder können ohne Anmeldung einen Tausch anfragen und Fehler mit Screenshot melden; die Bearbeitung ist per Passwort geschützt.
Rotatory lost fair und zufällig aus, wer das tägliche Morning Meeting moderiert: pro Wochentag ein Hauptmoderator und ein Nebenmoderator aus der Belegschaft. Urlaub, Krankheit, Feiertage, Teilzeit-Freitage und Personen, die nicht moderieren, werden automatisch berücksichtigt. Die Monatsübersicht zeigt auf jedem Tag die Fotos der beiden Moderatoren, sodass jeder auf einen Blick sieht, wer dran ist. Einzelne Tage lassen sich manuell festlegen oder neu auslosen. Die Belegschaft samt Fotos und die Abwesenheiten kommen auf Wunsch direkt aus der Nextcloud, und auf Knopfdruck landet der Plan als Termine im geteilten Nextcloud-Kalender des Teams. Teammitglieder können ohne Anmeldung einen Tausch anfragen und Bugs mit Screenshot melden; die Bearbeitung ist per Passwort geschützt.
+1 -1
View File
@@ -25,7 +25,7 @@ Wofür dieses Projekt gut ist, und was jemand wissen muss, der hier weiterarbeit
- Vor dem Commit linten und formatieren
- Tests für die tragende Fachlogik
- Wenig Abhängigkeiten — was Browser und Node schon können, reicht meistens. Ausnahme mit
Begründung: `public/vendor/html2canvas.min.js` (Screenshots für Fehlermeldungen; der Browser
Begründung: `public/vendor/html2canvas.min.js` (Screenshots für Bug-Meldungen; der Browser
kann Seiten nicht selbst fotografieren), selbst gehostet, nichts von fremden Servern laden
- Semantisches HTML, mobil zuerst, bedienbar per Tastatur, ausreichender Kontrast
- Konfiguration über Umgebungsvariablen; keine Zugangsdaten im Quelltext
+4 -4
View File
@@ -90,13 +90,13 @@ Bearbeiter sehen alle Anfragen unter „Anfragen" mit Zähler in der Navigation
manuell wählen, „Erledigt" und „Ablehnen" schließen die Anfrage ohne Änderung. Nach einem
Tausch den Zeitraum erneut nach Nextcloud schreiben.
## Fehler melden
## Bugs melden
Unten rechts sitzt ein Käfer-Button. Ein Klick nimmt den sichtbaren Bildschirm auf (mit der
selbst gehosteten Bibliothek html2canvas, die die Seite aus dem Seiteninhalt nachzeichnet),
zeigt ihn als Vorschau, in der sich rote Rechtecke aufziehen lassen, und fragt nach einer
Beschreibung und optional dem Namen. Dafür ist keine Anmeldung nötig; pro Adresse sind zehn
Meldungen je Stunde möglich. Bearbeiter sehen die Meldungen unter „Fehler" mit Zähler.
Meldungen je Stunde möglich. Bearbeiter sehen die Meldungen unter „Bugs" mit Zähler.
„Prompt kopieren" legt eine fertige Anweisung für Claude Code in die Zwischenablage, die
Vorlage dafür steht in den Einstellungen; „Screenshot kopieren" das Bild dazu. Bilder in die
Zwischenablage legen erlauben Browser nur über https; auf einer http-Adresse öffnet
@@ -139,7 +139,7 @@ server/
ics.js iCalendar-Erzeugung
nextcloud.js CalDAV/CardDAV-Client (Discovery, PROPFIND, MKCALENDAR, REPORT, PUT, DELETE)
requests.js Tauschanfragen prüfen und ausführen
bugs.js Fehlermeldungen: Screenshot prüfen, Prompt-Vorlage
bugs.js Bug-Meldungen: Screenshot prüfen, Prompt-Vorlage
auth.js Bearbeitungsschutz (Cookie, Bremse)
ical.js iCalendar- und vCard-Leser, Namenszuordnung
env.js .env-Leser
@@ -149,5 +149,5 @@ test/ node:test
```
Abhängigkeiten: nur `express`; im Browser zusätzlich die selbst gehostete Bibliothek
html2canvas (`public/vendor/`, MIT) für Screenshots in Fehlermeldungen. Fotos werden im Browser
html2canvas (`public/vendor/`, MIT) für Screenshots in Bug-Meldungen. Fotos werden im Browser
per Canvas verkleinert, `fetch` und `crypto` kommen aus Node.
+11 -10
View File
@@ -51,7 +51,7 @@ async function api(path, { method = 'GET', body, raw } = {}) {
}
// ---------- Anmeldung zum Bearbeiten ----------
const EDITOR_VIEWS = ['personen', 'abwesenheiten', 'anfragen', 'fehler', 'einstellungen'];
const EDITOR_VIEWS = ['personen', 'abwesenheiten', 'anfragen', 'bugs', 'einstellungen'];
function isEditor() { return !state.data || state.data.auth?.editor !== false; }
function applyAuthUI() {
const a = state.data?.auth || { protected: false, editor: true };
@@ -148,7 +148,7 @@ function avatarEl(p, cls = '') {
// ---------- Navigation ----------
function showView(name) {
const known = ['kalender', 'personen', 'abwesenheiten', 'anfragen', 'fehler', 'einstellungen'];
const known = ['kalender', 'personen', 'abwesenheiten', 'anfragen', 'bugs', 'einstellungen'];
if (!known.includes(name)) name = 'kalender';
if (!isEditor() && EDITOR_VIEWS.includes(name)) name = 'kalender';
if (name === 'abwesenheiten' && state.data) prepareAbsenceImport();
@@ -1140,14 +1140,14 @@ $('#holiday-add').addEventListener('submit', async (e) => {
} catch (err) { toast(err.message, true); }
});
// ---------- Fehler melden (für alle) ----------
// ---------- Bug melden (für alle) ----------
const bugPanel = $('#bug-panel');
const bugCanvas = $('#bug-canvas');
const bugState = { base: null, rects: [], draft: null, sending: false, capture: null, closeTimer: null, target: null };
function viewName() {
const v = location.hash.slice(1) || 'kalender';
const names = { kalender: 'Kalender', personen: 'Personen', abwesenheiten: 'Abwesenheiten', anfragen: 'Anfragen', fehler: 'Fehler', einstellungen: 'Einstellungen' };
const names = { kalender: 'Kalender', personen: 'Personen', abwesenheiten: 'Abwesenheiten', anfragen: 'Anfragen', bugs: 'Bugs', einstellungen: 'Einstellungen' };
const month = v === 'kalender' ? ` (${MONTHS[state.month.getMonth()]} ${state.month.getFullYear()})` : '';
return `${names[v] || v}${month}${isEditor() ? ', angemeldet' : ''}`;
}
@@ -1351,12 +1351,13 @@ $('#bug-form').addEventListener('submit', async (e) => {
return;
}
bugState.sending = false;
out.textContent = 'Danke, der Fehler ist gemeldet.';
bugState.closeTimer = setTimeout(() => { bugState.closeTimer = null; closeBugPanel(); }, 2000);
// Panel sofort schließen und die Bestätigung unten einblenden
closeBugPanel();
toast('Bug erfolgreich gemeldet. Danke für den Hinweis.');
if (isEditor()) load().catch((err) => toast(err.message, true));
});
// ---------- Fehlermeldungen bearbeiten (nur Bearbeiter) ----------
// ---------- Bugs bearbeiten (nur Bearbeiter) ----------
const canCopyImages = () => Boolean(window.isSecureContext && navigator.clipboard && navigator.clipboard.write && window.ClipboardItem);
async function copyText(text) {
if (window.isSecureContext && navigator.clipboard?.writeText) { await navigator.clipboard.writeText(text); return; }
@@ -1394,7 +1395,7 @@ function bugRow(b) {
a.title = 'Screenshot in voller Größe öffnen';
const img = document.createElement('img');
img.src = `bugs/${b.id}.png`;
img.alt = 'Screenshot zur Fehlermeldung';
img.alt = 'Screenshot zum Bug';
img.loading = 'lazy';
a.appendChild(img);
li.appendChild(a);
@@ -1431,7 +1432,7 @@ function bugRow(b) {
}
if (b.status === 'offen') btn('Erledigt', 'ghost', () => run(() => api(`api/bugs/${b.id}`, { method: 'PUT', body: { status: 'erledigt' } }), 'Als erledigt markiert.'));
else btn('Wieder öffnen', 'ghost', () => run(() => api(`api/bugs/${b.id}`, { method: 'PUT', body: { status: 'offen' } })));
btn('Löschen', 'ghost danger', () => { if (confirm('Diese Fehlermeldung samt Screenshot löschen?')) run(() => api(`api/bugs/${b.id}`, { method: 'DELETE' }), 'Meldung gelöscht.'); });
btn('Löschen', 'ghost danger', () => { if (confirm('Diesen Bug samt Screenshot löschen?')) run(() => api(`api/bugs/${b.id}`, { method: 'DELETE' }), 'Bug gelöscht.'); });
grow.appendChild(actions);
li.appendChild(grow);
return li;
@@ -1443,7 +1444,7 @@ function renderBugs() {
$('#bugs-clipboard-hint').hidden = canCopyImages();
const list = $('#bug-list');
list.textContent = '';
if (open.length === 0) list.innerHTML = '<li class="hint">Keine offenen Fehlermeldungen.</li>';
if (open.length === 0) list.innerHTML = '<li class="hint">Keine offenen Bugs.</li>';
for (const b of open) list.appendChild(bugRow(b));
const doneList = $('#bug-list-done');
doneList.textContent = '';
+15 -15
View File
@@ -17,7 +17,7 @@
<a href="#personen" data-view="personen">Personen</a>
<a href="#abwesenheiten" data-view="abwesenheiten">Abwesenheiten</a>
<a href="#anfragen" data-view="anfragen">Anfragen <span id="requests-count" class="count" hidden></span></a>
<a href="#fehler" data-view="fehler">Fehler <span id="bugs-count" class="count" hidden></span></a>
<a href="#bugs" data-view="bugs">Bugs <span id="bugs-count" class="count" hidden></span></a>
<a href="#einstellungen" data-view="einstellungen">Einstellungen</a>
</nav>
<button type="button" id="auth-button" class="topbar-action" hidden>Anmelden</button>
@@ -158,10 +158,10 @@
<ul id="request-list-done" class="list" hidden></ul>
</section>
<!-- Fehlermeldungen (nur Bearbeiter) -->
<section id="view-fehler" class="view" hidden aria-labelledby="bugs-title">
<h2 id="bugs-title">Fehlermeldungen</h2>
<p class="hint">Gemeldet über den Käfer-Button unten rechts. „Prompt kopieren" legt eine fertige Anweisung für Claude in die Zwischenablage, „Screenshot kopieren" das Bild dazu. Beides zusammen in Claude Code einfügen, dann wird der Fehler direkt bearbeitet.</p>
<!-- Bugs (nur Bearbeiter) -->
<section id="view-bugs" class="view" hidden aria-labelledby="bugs-title">
<h2 id="bugs-title">Bugs</h2>
<p class="hint">Gemeldet über den Käfer-Button unten rechts. „Prompt kopieren" legt eine fertige Anweisung für Claude in die Zwischenablage, „Screenshot kopieren" das Bild dazu. Beides zusammen in Claude Code einfügen, dann wird der Bug direkt bearbeitet.</p>
<p class="hint" id="bugs-clipboard-hint" hidden>Diese Adresse ist nicht verschlüsselt (http). Bilder kann der Browser hier nicht direkt in die Zwischenablage legen: „Screenshot öffnen" nutzen und dort mit Rechtsklick „Bild kopieren" wählen. Über eine https-Adresse geht es mit einem Klick.</p>
<ul id="bug-list" class="list bug-list"></ul>
<label class="inline" id="bugs-toggle"><input type="checkbox" id="bugs-show-done"> Erledigte anzeigen</label>
@@ -178,7 +178,7 @@
<label>Fairness-Fenster in Tagen <input type="number" name="historyWindowDays" min="0" max="365"></label>
<label>Kalendername in Nextcloud <input name="calendarDisplayName" maxlength="60"></label>
<label class="inline wide"><input type="checkbox" name="inviteAttendees"> Moderatoren als Teilnehmer eintragen (E-Mail nötig; Nextcloud verschickt dann Einladungen)</label>
<label class="wide">Vorlage für den Fehler-Prompt <textarea name="bugPromptTemplate" rows="7" maxlength="4000"></textarea></label>
<label class="wide">Vorlage für den Bug-Prompt <textarea name="bugPromptTemplate" rows="7" maxlength="4000"></textarea></label>
<p class="hint">Platzhalter: {text} Beschreibung, {reporter} Name, {date} Zeitpunkt, {page} Ansicht, {browser}, {viewport}, {version}, {url}. Leer lassen stellt die Vorlage wieder her.</p>
<div class="form-actions"><button type="submit" class="primary">Speichern</button></div>
</form>
@@ -205,7 +205,7 @@
<!-- Dialog: Tag bearbeiten -->
<dialog id="day-dialog">
<form method="dialog" class="dialog-form" id="day-form">
<div class="dialog-head"><h2 id="day-dialog-title">Tag</h2><button type="button" class="ghost icon-button dialog-bug" aria-label="Fehler in diesem Dialog melden" title="Fehler melden"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="6.5" r="2.5"/><path d="M7 14a5 5 0 0 1 10 0v2a5 5 0 0 1-10 0z"/><path d="M12 9v12"/><path d="M7 13H3.5"/><path d="M7 17H4l-1 2.5"/><path d="M17 13h3.5"/><path d="M17 17h3l1 2.5"/><path d="M8.5 9.5 5.5 7"/><path d="M15.5 9.5 18.5 7"/></svg></button></div>
<div class="dialog-head"><h2 id="day-dialog-title">Tag</h2><button type="button" class="ghost icon-button dialog-bug" aria-label="Bug in diesem Dialog melden" title="Bug melden"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="6.5" r="2.5"/><path d="M7 14a5 5 0 0 1 10 0v2a5 5 0 0 1-10 0z"/><path d="M12 9v12"/><path d="M7 13H3.5"/><path d="M7 17H4l-1 2.5"/><path d="M17 13h3.5"/><path d="M17 17h3l1 2.5"/><path d="M8.5 9.5 5.5 7"/><path d="M15.5 9.5 18.5 7"/></svg></button></div>
<p id="day-dialog-info" class="hint"></p>
<label>Hauptmoderation <select name="main"></select></label>
<label>Nebenmoderation <select name="co"></select></label>
@@ -224,7 +224,7 @@
<!-- Dialog: Auslosen -->
<dialog id="plan-dialog">
<form method="dialog" class="dialog-form" id="plan-form">
<div class="dialog-head"><h2>Moderation auslosen</h2><button type="button" class="ghost icon-button dialog-bug" aria-label="Fehler in diesem Dialog melden" title="Fehler melden"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="6.5" r="2.5"/><path d="M7 14a5 5 0 0 1 10 0v2a5 5 0 0 1-10 0z"/><path d="M12 9v12"/><path d="M7 13H3.5"/><path d="M7 17H4l-1 2.5"/><path d="M17 13h3.5"/><path d="M17 17h3l1 2.5"/><path d="M8.5 9.5 5.5 7"/><path d="M15.5 9.5 18.5 7"/></svg></button></div>
<div class="dialog-head"><h2>Moderation auslosen</h2><button type="button" class="ghost icon-button dialog-bug" aria-label="Bug in diesem Dialog melden" title="Bug melden"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="6.5" r="2.5"/><path d="M7 14a5 5 0 0 1 10 0v2a5 5 0 0 1-10 0z"/><path d="M12 9v12"/><path d="M7 13H3.5"/><path d="M7 17H4l-1 2.5"/><path d="M17 13h3.5"/><path d="M17 17h3l1 2.5"/><path d="M8.5 9.5 5.5 7"/><path d="M15.5 9.5 18.5 7"/></svg></button></div>
<label>Von Monat <input type="month" name="from" required></label>
<label>Bis Monat <input type="month" name="to" required></label>
<label class="inline"><input type="checkbox" name="overwrite"> Bereits ausgeloste, nicht fixierte Tage neu auslosen</label>
@@ -242,7 +242,7 @@
<!-- Dialog: Nextcloud -->
<dialog id="nextcloud-dialog">
<form method="dialog" class="dialog-form" id="nextcloud-form">
<div class="dialog-head"><h2>In Nextcloud schreiben</h2><button type="button" class="ghost icon-button dialog-bug" aria-label="Fehler in diesem Dialog melden" title="Fehler melden"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="6.5" r="2.5"/><path d="M7 14a5 5 0 0 1 10 0v2a5 5 0 0 1-10 0z"/><path d="M12 9v12"/><path d="M7 13H3.5"/><path d="M7 17H4l-1 2.5"/><path d="M17 13h3.5"/><path d="M17 17h3l1 2.5"/><path d="M8.5 9.5 5.5 7"/><path d="M15.5 9.5 18.5 7"/></svg></button></div>
<div class="dialog-head"><h2>In Nextcloud schreiben</h2><button type="button" class="ghost icon-button dialog-bug" aria-label="Bug in diesem Dialog melden" title="Bug melden"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="6.5" r="2.5"/><path d="M7 14a5 5 0 0 1 10 0v2a5 5 0 0 1-10 0z"/><path d="M12 9v12"/><path d="M7 13H3.5"/><path d="M7 17H4l-1 2.5"/><path d="M17 13h3.5"/><path d="M17 17h3l1 2.5"/><path d="M8.5 9.5 5.5 7"/><path d="M15.5 9.5 18.5 7"/></svg></button></div>
<p id="nextcloud-info" class="hint"></p>
<label>Zielkalender
<select name="target"><option value="">– Kalender laden …</option></select>
@@ -264,7 +264,7 @@
<!-- Dialog: Kontakte importieren -->
<dialog id="contacts-dialog">
<form method="dialog" class="dialog-form" id="contacts-form">
<div class="dialog-head"><h2>Personen aus Nextcloud</h2><button type="button" class="ghost icon-button dialog-bug" aria-label="Fehler in diesem Dialog melden" title="Fehler melden"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="6.5" r="2.5"/><path d="M7 14a5 5 0 0 1 10 0v2a5 5 0 0 1-10 0z"/><path d="M12 9v12"/><path d="M7 13H3.5"/><path d="M7 17H4l-1 2.5"/><path d="M17 13h3.5"/><path d="M17 17h3l1 2.5"/><path d="M8.5 9.5 5.5 7"/><path d="M15.5 9.5 18.5 7"/></svg></button></div>
<div class="dialog-head"><h2>Personen aus Nextcloud</h2><button type="button" class="ghost icon-button dialog-bug" aria-label="Bug in diesem Dialog melden" title="Bug melden"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="6.5" r="2.5"/><path d="M7 14a5 5 0 0 1 10 0v2a5 5 0 0 1-10 0z"/><path d="M12 9v12"/><path d="M7 13H3.5"/><path d="M7 17H4l-1 2.5"/><path d="M17 13h3.5"/><path d="M17 17h3l1 2.5"/><path d="M8.5 9.5 5.5 7"/><path d="M15.5 9.5 18.5 7"/></svg></button></div>
<label>Adressbuch <select name="addressbook"></select></label>
<p id="contacts-info" class="hint">Lade Kontakte …</p>
<div class="contacts-tools">
@@ -284,7 +284,7 @@
<!-- Dialog: Tausch anfragen (für alle) -->
<dialog id="request-dialog">
<form method="dialog" class="dialog-form" id="request-form">
<div class="dialog-head"><h2>Tausch anfragen</h2><button type="button" class="ghost icon-button dialog-bug" aria-label="Fehler in diesem Dialog melden" title="Fehler melden"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="6.5" r="2.5"/><path d="M7 14a5 5 0 0 1 10 0v2a5 5 0 0 1-10 0z"/><path d="M12 9v12"/><path d="M7 13H3.5"/><path d="M7 17H4l-1 2.5"/><path d="M17 13h3.5"/><path d="M17 17h3l1 2.5"/><path d="M8.5 9.5 5.5 7"/><path d="M15.5 9.5 18.5 7"/></svg></button></div>
<div class="dialog-head"><h2>Tausch anfragen</h2><button type="button" class="ghost icon-button dialog-bug" aria-label="Bug in diesem Dialog melden" title="Bug melden"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="6.5" r="2.5"/><path d="M7 14a5 5 0 0 1 10 0v2a5 5 0 0 1-10 0z"/><path d="M12 9v12"/><path d="M7 13H3.5"/><path d="M7 17H4l-1 2.5"/><path d="M17 13h3.5"/><path d="M17 17h3l1 2.5"/><path d="M8.5 9.5 5.5 7"/><path d="M15.5 9.5 18.5 7"/></svg></button></div>
<p id="request-info" class="hint"></p>
<label>Ich bin <select name="personId" required></select></label>
<label>Tag, an dem ich nicht kann <input type="date" name="date" required></label>
@@ -303,7 +303,7 @@
<!-- Dialog: Anmelden zum Bearbeiten -->
<dialog id="login-dialog">
<form method="dialog" class="dialog-form" id="login-form">
<div class="dialog-head"><h2>Zum Bearbeiten anmelden</h2><button type="button" class="ghost icon-button dialog-bug" aria-label="Fehler in diesem Dialog melden" title="Fehler melden"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="6.5" r="2.5"/><path d="M7 14a5 5 0 0 1 10 0v2a5 5 0 0 1-10 0z"/><path d="M12 9v12"/><path d="M7 13H3.5"/><path d="M7 17H4l-1 2.5"/><path d="M17 13h3.5"/><path d="M17 17h3l1 2.5"/><path d="M8.5 9.5 5.5 7"/><path d="M15.5 9.5 18.5 7"/></svg></button></div>
<div class="dialog-head"><h2>Zum Bearbeiten anmelden</h2><button type="button" class="ghost icon-button dialog-bug" aria-label="Bug in diesem Dialog melden" title="Bug melden"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="6.5" r="2.5"/><path d="M7 14a5 5 0 0 1 10 0v2a5 5 0 0 1-10 0z"/><path d="M12 9v12"/><path d="M7 13H3.5"/><path d="M7 17H4l-1 2.5"/><path d="M17 13h3.5"/><path d="M17 17h3l1 2.5"/><path d="M8.5 9.5 5.5 7"/><path d="M15.5 9.5 18.5 7"/></svg></button></div>
<p class="hint">Ansehen kann jeder. Auslosen, Personen, Abwesenheiten und Nextcloud erfordern das Bearbeitungspasswort.</p>
<label>Passwort <input type="password" name="password" id="login-password" autocomplete="current-password" required></label>
<p id="login-result" class="result error" hidden></p>
@@ -315,11 +315,11 @@
</form>
</dialog>
<!-- Fehler melden: Käfer-Button und Panel, für alle sichtbar -->
<!-- Bug melden: Käfer-Button und Panel, für alle sichtbar -->
<div id="bug-widget">
<button type="button" id="bug-button" class="bug-button" aria-label="Fehler melden" title="Fehler melden" aria-expanded="false" aria-controls="bug-panel"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="6.5" r="2.5"/><path d="M7 14a5 5 0 0 1 10 0v2a5 5 0 0 1-10 0z"/><path d="M12 9v12"/><path d="M7 13H3.5"/><path d="M7 17H4l-1 2.5"/><path d="M17 13h3.5"/><path d="M17 17h3l1 2.5"/><path d="M8.5 9.5 5.5 7"/><path d="M15.5 9.5 18.5 7"/></svg></button>
<button type="button" id="bug-button" class="bug-button" aria-label="Bug melden" title="Bug melden" aria-expanded="false" aria-controls="bug-panel"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="6.5" r="2.5"/><path d="M7 14a5 5 0 0 1 10 0v2a5 5 0 0 1-10 0z"/><path d="M12 9v12"/><path d="M7 13H3.5"/><path d="M7 17H4l-1 2.5"/><path d="M17 13h3.5"/><path d="M17 17h3l1 2.5"/><path d="M8.5 9.5 5.5 7"/><path d="M15.5 9.5 18.5 7"/></svg></button>
<dialog id="bug-panel" class="bug-panel" aria-labelledby="bug-title">
<h2 id="bug-title">Fehler melden</h2>
<h2 id="bug-title">Bug melden</h2>
<p id="bug-status" class="hint">Bildschirm wird aufgenommen …</p>
<div class="bug-shot" id="bug-shot" hidden>
<canvas id="bug-canvas" aria-label="Screenshot der Seite. Markiere die Stelle mit einem roten Rechteck."></canvas>