Fix #165: Bereichs- und Schweregradfilter stehen nebeneinander

This commit is contained in:
fds2610-bot 2026-08-02 20:12:09 +02:00
parent 3ba3912fa4
commit fc65fcb9c5
3 changed files with 16 additions and 3 deletions

View file

@ -18,7 +18,7 @@
- **`migrations/091_system_events_level.sql`** (neu): Spalte `level` (info/warning/error) samt Indizes. Bestehende Einträge werden anhand ihres Textpräfixes eingestuft, nach dem die Liste sie bisher eingefärbt hat. - **`migrations/091_system_events_level.sql`** (neu): Spalte `level` (info/warning/error) samt Indizes. Bestehende Einträge werden anhand ihres Textpräfixes eingestuft, nach dem die Liste sie bisher eingefärbt hat.
- **`src/Models/EventLog.php`:** `add()` nimmt einen Schweregrad entgegen, dazu `warning()`, `error()`, `find()` mit Filter nach Bereich und Schweregrad sowie `channels()`. `tryAdd()` schreibt das Ereignis, ohne selbst scheitern zu können – nötig für Aufrufer, die bereits einen Fehler behandeln. - **`src/Models/EventLog.php`:** `add()` nimmt einen Schweregrad entgegen, dazu `warning()`, `error()`, `find()` mit Filter nach Bereich und Schweregrad sowie `channels()`. `tryAdd()` schreibt das Ereignis, ohne selbst scheitern zu können – nötig für Aufrufer, die bereits einen Fehler behandeln.
- **Neue Fehlerquellen:** `View::redirect()` protokolliert jede Meldung vom Typ `error` oder `warning` im Bereich `meldungen` – damit ist jede dem Nutzer angezeigte Fehlermeldung erfasst, ohne sie einzeln anbinden zu müssen. `BelegController::renderUploadErrors()` schreibt zusätzlich im Bereich `beleg-upload` mit Dateiname, `public/index.php` protokolliert unbehandelte Ausnahmen und schwere PHP-Fehler im Bereich `system`. - **Neue Fehlerquellen:** `View::redirect()` protokolliert jede Meldung vom Typ `error` oder `warning` im Bereich `meldungen` – damit ist jede dem Nutzer angezeigte Fehlermeldung erfasst, ohne sie einzeln anbinden zu müssen. `BelegController::renderUploadErrors()` schreibt zusätzlich im Bereich `beleg-upload` mit Dateiname, `public/index.php` protokolliert unbehandelte Ausnahmen und schwere PHP-Fehler im Bereich `system`.
- **`src/Controllers/EventController.php`, `src/Views/ereignisse/index.php`, `src/Views/ereignisse/_body.php`:** Aus der Nextcloud-Seite wird eine Übersicht über alle Bereiche mit zwei Auswahlfeldern (Bereich, Schweregrad). Der automatische Neuaufbau alle 60 Sekunden behält den eingestellten Filter. `/ereignisse/nextcloud-import` leitet auf die gefilterte Übersicht weiter, der bisherige Daten-Endpunkt bleibt erreichbar. - **`src/Controllers/EventController.php`, `src/Views/ereignisse/index.php`, `src/Views/ereignisse/_body.php`:** Aus der Nextcloud-Seite wird eine Übersicht über alle Bereiche mit zwei Auswahlfeldern (Bereich, Schweregrad), die nebeneinander stehen – beide setzen `width:auto` gegen das globale `select { width: 100% }`, das sie sonst im Flex-Formular untereinander schiebt. Der automatische Neuaufbau alle 60 Sekunden behält den eingestellten Filter. `/ereignisse/nextcloud-import` leitet auf die gefilterte Übersicht weiter, der bisherige Daten-Endpunkt bleibt erreichbar.
- **`tests/81_EreignisseAlleFehlerTest.php`** (neu), **`tests/e2e/specs/ereignisse.spec.js`** (neu), **`tests/58_EreignisAutoReloadTest.php`** (angepasst). - **`tests/81_EreignisseAlleFehlerTest.php`** (neu), **`tests/e2e/specs/ereignisse.spec.js`** (neu), **`tests/58_EreignisAutoReloadTest.php`** (angepasst).
### Buchungszeilen brauchen weniger Breite (#166) ### Buchungszeilen brauchen weniger Breite (#166)

View file

@ -31,13 +31,13 @@ $levelLabels = [
<div class="card"> <div class="card">
<div style="display:flex;justify-content:space-between;align-items:center;gap:1rem;flex-wrap:wrap;padding:.75rem 1rem;border-bottom:1px solid var(--color-border)"> <div style="display:flex;justify-content:space-between;align-items:center;gap:1rem;flex-wrap:wrap;padding:.75rem 1rem;border-bottom:1px solid var(--color-border)">
<form method="get" action="/ereignisse" id="events-filter" style="display:flex;align-items:center;gap:.5rem;flex-wrap:wrap"> <form method="get" action="/ereignisse" id="events-filter" style="display:flex;align-items:center;gap:.5rem;flex-wrap:wrap">
<select name="channel" onchange="this.form.submit()"> <select name="channel" onchange="this.form.submit()" style="width:auto;min-width:11rem">
<option value="">Alle Bereiche</option> <option value="">Alle Bereiche</option>
<?php foreach ($channels as $c): ?> <?php foreach ($channels as $c): ?>
<option value="<?= $h($c) ?>"<?= $c === $aktiverKanal ? ' selected' : '' ?>><?= $h($c) ?></option> <option value="<?= $h($c) ?>"<?= $c === $aktiverKanal ? ' selected' : '' ?>><?= $h($c) ?></option>
<?php endforeach; ?> <?php endforeach; ?>
</select> </select>
<select name="level" onchange="this.form.submit()"> <select name="level" onchange="this.form.submit()" style="width:auto;min-width:11rem">
<option value="">Alle Schweregrade</option> <option value="">Alle Schweregrade</option>
<?php foreach ($levelLabels as $value => $label): ?> <?php foreach ($levelLabels as $value => $label): ?>
<option value="<?= $h($value) ?>"<?= $value === $aktivesLevel ? ' selected' : '' ?>><?= $h($label) ?></option> <option value="<?= $h($value) ?>"<?= $value === $aktivesLevel ? ' selected' : '' ?>><?= $h($label) ?></option>

View file

@ -23,6 +23,19 @@ test.describe('Ereignisse', () => {
await expect(page.locator('select[name="channel"] option[value=""]')).toContainText('Alle Bereiche') await expect(page.locator('select[name="channel"] option[value=""]')).toContainText('Alle Bereiche')
}) })
test('Beide Auswahlfelder stehen nebeneinander', async ({ page }) => {
// Global gilt `select { width: 100% }` – ohne eigene Breite bricht das
// zweite Feld im Flex-Formular in die nächste Zeile um.
await page.setViewportSize({ width: 1280, height: 800 })
await gotoOk(page, '/ereignisse')
const bereich = await page.locator('select[name="channel"]').boundingBox()
const grad = await page.locator('select[name="level"]').boundingBox()
expect(Math.abs(bereich.y - grad.y)).toBeLessThan(5)
expect(grad.x).toBeGreaterThan(bereich.x + bereich.width - 1)
})
test('Der alte Nextcloud-Pfad landet auf der gefilterten Übersicht', async ({ page }) => { test('Der alte Nextcloud-Pfad landet auf der gefilterten Übersicht', async ({ page }) => {
await page.goto('/ereignisse/nextcloud-import') await page.goto('/ereignisse/nextcloud-import')
const url = new URL(page.url()) const url = new URL(page.url())