Merge pull request 'Fix n.n.: „+ Neu“ öffnet das Formular zur Neuanlage als modalen Dialog' (#106) from fds2610-bot/Finanzmanager:main into main

Reviewed-on: https://codeberg.org/fds2610/Finanzmanager/pulls/106
This commit is contained in:
fds2610 2026-10-01 09:53:51 +02:00
commit d5b4c8d350
19 changed files with 505 additions and 345 deletions

View file

@ -1,5 +1,10 @@
# Änderungen # Änderungen
## „+ Neu“ öffnet das Formular als Dialog (01.10.2026)
- Das Formular zur Neuanlage stand in elf Ansichten unter der Liste. Jetzt öffnet der Knopf „+ Neu“ es als modalen Dialog (`app.js`, `.neudialog`); nach dem Speichern erscheint die Liste wieder, mit dem neuen Eintrag. Betroffen: Klassen, Buchungsvorlagen, Regelmäßige Buchungen, Erinnerungen, Verträge, Adressen, Sparziele, Kredite, Abgleichregeln, Budgets, Berichtsgruppen.
- E2E: `neudialog.spec.js`; bestehende Specs öffnen den Dialog zuerst.
## Regelmäßige Buchungen: Klick zum Bearbeiten (01.10.2026) ## Regelmäßige Buchungen: Klick zum Bearbeiten (01.10.2026)
- In „Alle Reihen“ erscheinen alle Felder zunächst als Text und werden erst beim Anklicken zum Eingabefeld (`reihenliste.js`). Ja/Nein-Felder schalten per Klick um, „Speichern“ erscheint erst nach einer Änderung. Konto und Klasse stehen untereinander, die Spalte Name/Buchungstext nimmt den freien Platz. - In „Alle Reihen“ erscheinen alle Felder zunächst als Text und werden erst beim Anklicken zum Eingabefeld (`reihenliste.js`). Ja/Nein-Felder schalten per Klick um, „Speichern“ erscheint erst nach einer Änderung. Konto und Klasse stehen untereinander, die Spalte Name/Buchungstext nimmt den freien Platz.

View file

@ -1289,6 +1289,19 @@ table.splittabelle input.rechts { text-align: right; }
„Speichern“ und „Abbrechen“, damit es nicht im Vorbeigehen getroffen wird. */ „Speichern“ und „Abbrechen“, damit es nicht im Vorbeigehen getroffen wird. */
.splitdialog .knopfleiste .knopf.gefahr { margin-left: auto; } .splitdialog .knopfleiste .knopf.gefahr { margin-left: auto; }
/* „+ Neu“ in den Listenansichten: Das Formular zur Neuanlage liegt in einem
modalen Dialog, den der Knopf öffnet. Der Dialog trägt den Rahmen, das
Formular darin braucht ihn nicht noch einmal. */
.neudialog { max-height: 92vh; overflow-y: auto; }
.neudialog .formular.breit {
max-width: none;
padding: 0;
border: 0;
box-shadow: none;
background: none;
}
/* Die Formatwahl vor Import und Export – als Dialog auf der Verwaltungsseite /* Die Formatwahl vor Import und Export – als Dialog auf der Verwaltungsseite
und als Kachelinhalt auf der Ausweichseite, deshalb zwei Ebenen: der Dialog und als Kachelinhalt auf der Ausweichseite, deshalb zwei Ebenen: der Dialog
trägt den Rahmen, .formatwahl die Karten. */ trägt den Rahmen, .formatwahl die Karten. */

View file

@ -314,6 +314,20 @@
}); });
}); });
// „+ Neu“ in den Listenansichten: Der Knopf öffnet den Dialog mit dem
// Formular zur Neuanlage. Gespeichert wird per Formularversand; die Ansicht
// lädt danach neu und zeigt die Liste samt neuem Eintrag.
document.querySelectorAll('[data-neudialog]').forEach(function (knopf) {
knopf.addEventListener('click', function () {
const dialog = document.getElementById(knopf.dataset.neudialog);
if (dialog && typeof dialog.showModal === 'function') {
dialog.showModal();
const feld = dialog.querySelector('input:not([type=hidden]), select, textarea');
if (feld) { feld.focus(); }
}
});
});
// Übermittlungsprotokoll im Zahlungsverkehr: Ein Klick auf den Status holt das // Übermittlungsprotokoll im Zahlungsverkehr: Ein Klick auf den Status holt das
// Protokoll der Überweisung in einen modalen Dialog. Ohne <dialog> oder // Protokoll der Überweisung in einen modalen Dialog. Ohne <dialog> oder
// fetch bleibt der Status ein Link auf dieselbe Ansicht als eigene Seite. // fetch bleibt der Status ein Link auf dieselbe Ansicht als eigene Seite.

View file

@ -19,6 +19,7 @@ include __DIR__ . '/../layout/kopf.php';
</div> </div>
<div class="seitenaktionen"> <div class="seitenaktionen">
<button type="button" class="knopf primaer" id="neu-knopf" data-neudialog="neudialog">+ Neu</button>
<a href="/auswertungen" class="knopf">Zur Übersicht</a> <a href="/auswertungen" class="knopf">Zur Übersicht</a>
</div> </div>
@ -28,7 +29,7 @@ include __DIR__ . '/../layout/kopf.php';
und rücken unter „Nicht gruppiert“. und rücken unter „Nicht gruppiert“.
</p> </p>
<div class="kachel einzeln"> <dialog id="neudialog" class="splitdialog neudialog">
<h2>Neue Berichtsgruppe</h2> <h2>Neue Berichtsgruppe</h2>
<form method="post" action="/auswertungen/gruppen/neu" class="zeilenform"> <form method="post" action="/auswertungen/gruppen/neu" class="zeilenform">
<input type="hidden" name="csrf_token" value="<?= View::h($csrfToken) ?>"> <input type="hidden" name="csrf_token" value="<?= View::h($csrfToken) ?>">
@ -39,8 +40,9 @@ include __DIR__ . '/../layout/kopf.php';
<input type="number" name="sortierung" value="0" class="schmal"> <input type="number" name="sortierung" value="0" class="schmal">
</label> </label>
<button type="submit" class="knopf primaer">Anlegen</button> <button type="submit" class="knopf primaer">Anlegen</button>
<button type="submit" class="knopf" formmethod="dialog" formnovalidate>Abbrechen</button>
</form> </form>
</div> </dialog>
<?php <?php
$echte = array_filter($gruppen, static fn(array $eintrag): bool => $eintrag['gruppe'] !== null); $echte = array_filter($gruppen, static fn(array $eintrag): bool => $eintrag['gruppe'] !== null);

View file

@ -27,6 +27,7 @@ include __DIR__ . '/../layout/kopf.php';
</p> </p>
<div class="seitenaktionen"> <div class="seitenaktionen">
<button type="button" class="knopf primaer" id="neu-knopf" data-neudialog="neudialog">+ Neu</button>
<form method="post" action="/banking/regeln/pruefen" class="inline"> <form method="post" action="/banking/regeln/pruefen" class="inline">
<input type="hidden" name="csrf_token" value="<?= View::h($csrfToken) ?>"> <input type="hidden" name="csrf_token" value="<?= View::h($csrfToken) ?>">
<button type="submit" class="knopf" <button type="submit" class="knopf"
@ -147,16 +148,19 @@ include __DIR__ . '/../layout/kopf.php';
</table> </table>
<?php endif; ?> <?php endif; ?>
<dialog id="neudialog" class="splitdialog neudialog">
<form method="post" action="/banking/regeln/neu" class="formular breit"> <form method="post" action="/banking/regeln/neu" class="formular breit">
<input type="hidden" name="csrf_token" value="<?= View::h($csrfToken) ?>"> <input type="hidden" name="csrf_token" value="<?= View::h($csrfToken) ?>">
<h3>Neue Regel</h3> <h2>Neue Regel</h2>
<?php $regel = ['aktiv' => 1]; $idPrefix = 'neu_'; ?> <?php $regel = ['aktiv' => 1]; $idPrefix = 'neu_'; ?>
<?php include __DIR__ . '/regelfelder.php'; ?> <?php include __DIR__ . '/regelfelder.php'; ?>
<div class="knopfleiste"> <div class="knopfleiste">
<button type="submit" class="knopf primaer">Regel anlegen</button> <button type="submit" class="knopf primaer">Regel anlegen</button>
<button type="submit" class="knopf" formmethod="dialog" formnovalidate>Abbrechen</button>
</div> </div>
</form> </form>
</dialog>
<?php include __DIR__ . '/../layout/fuss.php'; ?> <?php include __DIR__ . '/../layout/fuss.php'; ?>

View file

@ -11,6 +11,7 @@ include __DIR__ . '/../layout/kopf.php';
<div class="seitenaktionen"> <div class="seitenaktionen">
<a href="/planung/budget" class="knopf primaer">Budgetplaner öffnen</a> <a href="/planung/budget" class="knopf primaer">Budgetplaner öffnen</a>
<button type="button" class="knopf primaer" id="neu-knopf" data-neudialog="neudialog">+ Neu</button>
<a href="/planung" class="knopf">Zurück zur Planung</a> <a href="/planung" class="knopf">Zurück zur Planung</a>
</div> </div>
@ -66,9 +67,8 @@ include __DIR__ . '/../layout/kopf.php';
</table> </table>
<?php endif; ?> <?php endif; ?>
<div class="kachelraster"> <dialog id="neudialog" class="splitdialog neudialog">
<div class="kachel"> <h2>Neues Budget</h2>
<header><h2>Neues Budget</h2></header>
<form method="post" action="/planung/budget/neu" class="formular"> <form method="post" action="/planung/budget/neu" class="formular">
<input type="hidden" name="csrf_token" value="<?= View::h($csrfToken) ?>"> <input type="hidden" name="csrf_token" value="<?= View::h($csrfToken) ?>">
@ -83,10 +83,12 @@ include __DIR__ . '/../layout/kopf.php';
<div class="knopfleiste"> <div class="knopfleiste">
<button type="submit" class="knopf primaer">Budget anlegen</button> <button type="submit" class="knopf primaer">Budget anlegen</button>
<button type="submit" class="knopf" formmethod="dialog" formnovalidate>Abbrechen</button>
</div> </div>
</form> </form>
</div> </dialog>
<div class="kachelraster">
<?php if ($budgets !== []): ?> <?php if ($budgets !== []): ?>
<div class="kachel"> <div class="kachel">
<header><h2>Budget kopieren</h2></header> <header><h2>Budget kopieren</h2></header>

View file

@ -22,6 +22,10 @@ include __DIR__ . '/../layout/kopf.php';
kündigen“, „Steuerbescheid prüfen“. Offene Erinnerungen erscheinen im Finanzkalender. kündigen“, „Steuerbescheid prüfen“. Offene Erinnerungen erscheinen im Finanzkalender.
</p> </p>
<div class="seitenaktionen">
<button type="button" class="knopf primaer" id="neu-knopf" data-neudialog="neudialog">+ Neu</button>
</div>
<?php if ($erinnerungen === []): ?> <?php if ($erinnerungen === []): ?>
<p class="platzhalter">Keine Erinnerungen.</p> <p class="platzhalter">Keine Erinnerungen.</p>
<?php else: ?> <?php else: ?>
@ -65,9 +69,10 @@ include __DIR__ . '/../layout/kopf.php';
</table> </table>
<?php endif; ?> <?php endif; ?>
<dialog id="neudialog" class="splitdialog neudialog">
<form method="post" action="/termine/erinnerungen/neu" class="formular breit"> <form method="post" action="/termine/erinnerungen/neu" class="formular breit">
<input type="hidden" name="csrf_token" value="<?= View::h($csrfToken) ?>"> <input type="hidden" name="csrf_token" value="<?= View::h($csrfToken) ?>">
<h3>Neue Erinnerung</h3> <h2>Neue Erinnerung</h2>
<label for="text">Erinnerung</label> <label for="text">Erinnerung</label>
<input type="text" id="text" name="text" required> <input type="text" id="text" name="text" required>
@ -80,7 +85,9 @@ include __DIR__ . '/../layout/kopf.php';
<div class="knopfleiste"> <div class="knopfleiste">
<button type="submit" class="knopf primaer">Erinnerung anlegen</button> <button type="submit" class="knopf primaer">Erinnerung anlegen</button>
<button type="submit" class="knopf" formmethod="dialog" formnovalidate>Abbrechen</button>
</div> </div>
</form> </form>
</dialog>
<?php include __DIR__ . '/../layout/fuss.php'; ?> <?php include __DIR__ . '/../layout/fuss.php'; ?>

View file

@ -23,6 +23,10 @@ include __DIR__ . '/../layout/kopf.php';
<a href="/termine/erinnerungen" class="tab">Erinnerungen</a> <a href="/termine/erinnerungen" class="tab">Erinnerungen</a>
</div> </div>
<div class="seitenaktionen">
<button type="button" class="knopf primaer" id="neu-knopf" data-neudialog="neudialog">+ Neu</button>
</div>
<?php if ($vorschau['faellig'] > 0): ?> <?php if ($vorschau['faellig'] > 0): ?>
<div class="seitenaktionen"> <div class="seitenaktionen">
<span class="hinweis"> <span class="hinweis">
@ -217,9 +221,10 @@ include __DIR__ . '/../layout/kopf.php';
</table> </table>
<?php endif; ?> <?php endif; ?>
<dialog id="neudialog" class="splitdialog neudialog">
<form method="post" action="/termine/neu" class="formular breit"> <form method="post" action="/termine/neu" class="formular breit">
<input type="hidden" name="csrf_token" value="<?= View::h($csrfToken) ?>"> <input type="hidden" name="csrf_token" value="<?= View::h($csrfToken) ?>">
<h3>Neue regelmäßige Buchung</h3> <h2>Neue regelmäßige Buchung</h2>
<label for="name">Name</label> <label for="name">Name</label>
<input type="text" id="name" name="name" required placeholder="z. B. Miete"> <input type="text" id="name" name="name" required placeholder="z. B. Miete">
@ -287,8 +292,10 @@ include __DIR__ . '/../layout/kopf.php';
<div class="knopfleiste"> <div class="knopfleiste">
<button type="submit" class="knopf primaer">Reihe anlegen</button> <button type="submit" class="knopf primaer">Reihe anlegen</button>
<button type="submit" class="knopf" formmethod="dialog" formnovalidate>Abbrechen</button>
</div> </div>
</form> </form>
</dialog>
<?php include __DIR__ . '/../layout/fuss.php'; ?> <?php include __DIR__ . '/../layout/fuss.php'; ?>

View file

@ -25,6 +25,10 @@ include __DIR__ . '/../layout/kopf.php';
hinausgeht. hinausgeht.
</p> </p>
<div class="seitenaktionen">
<button type="button" class="knopf primaer" id="neu-knopf" data-neudialog="neudialog">+ Neu</button>
</div>
<form method="get" action="/vertraege/adressen" class="filterleiste"> <form method="get" action="/vertraege/adressen" class="filterleiste">
<label for="suche">Suchen</label> <label for="suche">Suchen</label>
<input type="search" id="suche" name="suche" value="<?= View::h($suche) ?>" <input type="search" id="suche" name="suche" value="<?= View::h($suche) ?>"
@ -126,9 +130,10 @@ include __DIR__ . '/../layout/kopf.php';
</table> </table>
<?php endif; ?> <?php endif; ?>
<dialog id="neudialog" class="splitdialog neudialog">
<form method="post" action="/vertraege/adressen/neu" class="formular breit"> <form method="post" action="/vertraege/adressen/neu" class="formular breit">
<input type="hidden" name="csrf_token" value="<?= View::h($csrfToken) ?>"> <input type="hidden" name="csrf_token" value="<?= View::h($csrfToken) ?>">
<h3>Neue Adresse</h3> <h2>Neue Adresse</h2>
<label for="name">Name</label> <label for="name">Name</label>
<input type="text" id="name" name="name" required> <input type="text" id="name" name="name" required>
@ -176,7 +181,9 @@ include __DIR__ . '/../layout/kopf.php';
<div class="knopfleiste"> <div class="knopfleiste">
<button type="submit" class="knopf primaer">Adresse anlegen</button> <button type="submit" class="knopf primaer">Adresse anlegen</button>
<button type="submit" class="knopf" formmethod="dialog" formnovalidate>Abbrechen</button>
</div> </div>
</form> </form>
</dialog>
<?php include __DIR__ . '/../layout/fuss.php'; ?> <?php include __DIR__ . '/../layout/fuss.php'; ?>

View file

@ -23,6 +23,10 @@ include __DIR__ . '/../layout/kopf.php';
<a href="/vertraege/kredite" class="tab">Kredite</a> <a href="/vertraege/kredite" class="tab">Kredite</a>
</div> </div>
<div class="seitenaktionen">
<button type="button" class="knopf primaer" id="neu-knopf" data-neudialog="neudialog">+ Neu</button>
</div>
<?php if ($fristen !== []): ?> <?php if ($fristen !== []): ?>
<div class="kachel einzeln"> <div class="kachel einzeln">
<header><h2>Kündigungsfristen laufen ab</h2></header> <header><h2>Kündigungsfristen laufen ab</h2></header>
@ -131,9 +135,10 @@ include __DIR__ . '/../layout/kopf.php';
</table> </table>
<?php endif; ?> <?php endif; ?>
<dialog id="neudialog" class="splitdialog neudialog">
<form method="post" action="/vertraege/neu" class="formular breit"> <form method="post" action="/vertraege/neu" class="formular breit">
<input type="hidden" name="csrf_token" value="<?= View::h($csrfToken) ?>"> <input type="hidden" name="csrf_token" value="<?= View::h($csrfToken) ?>">
<h3>Neuer Vertrag</h3> <h2>Neuer Vertrag</h2>
<label for="name">Bezeichnung</label> <label for="name">Bezeichnung</label>
<input type="text" id="name" name="name" required placeholder="z. B. Hausratversicherung"> <input type="text" id="name" name="name" required placeholder="z. B. Hausratversicherung">
@ -204,7 +209,9 @@ include __DIR__ . '/../layout/kopf.php';
<div class="knopfleiste"> <div class="knopfleiste">
<button type="submit" class="knopf primaer">Vertrag anlegen</button> <button type="submit" class="knopf primaer">Vertrag anlegen</button>
<button type="submit" class="knopf" formmethod="dialog" formnovalidate>Abbrechen</button>
</div> </div>
</form> </form>
</dialog>
<?php include __DIR__ . '/../layout/fuss.php'; ?> <?php include __DIR__ . '/../layout/fuss.php'; ?>

View file

@ -21,6 +21,10 @@ include __DIR__ . '/../layout/kopf.php';
<span class="tab aktiv">Kredite</span> <span class="tab aktiv">Kredite</span>
</div> </div>
<div class="seitenaktionen">
<button type="button" class="knopf primaer" id="neu-knopf" data-neudialog="neudialog">+ Neu</button>
</div>
<?php if ($kredite !== []): ?> <?php if ($kredite !== []): ?>
<table class="liste zahlen"> <table class="liste zahlen">
<thead> <thead>
@ -201,9 +205,10 @@ include __DIR__ . '/../layout/kopf.php';
</form> </form>
<?php endif; ?> <?php endif; ?>
<dialog id="neudialog" class="splitdialog neudialog">
<form method="post" action="/vertraege/kredite/neu" class="formular breit"> <form method="post" action="/vertraege/kredite/neu" class="formular breit">
<input type="hidden" name="csrf_token" value="<?= View::h($csrfToken) ?>"> <input type="hidden" name="csrf_token" value="<?= View::h($csrfToken) ?>">
<h3>Neuer Kredit</h3> <h2>Neuer Kredit</h2>
<p class="feldhinweis"> <p class="feldhinweis">
Gerechnet wird als Annuitätendarlehen: gleichbleibende Rate, sinkender Zinsanteil. Gerechnet wird als Annuitätendarlehen: gleichbleibende Rate, sinkender Zinsanteil.
Der Tilgungsplan entsteht aus diesen Angaben und wird nicht gespeichert. Der Tilgungsplan entsteht aus diesen Angaben und wird nicht gespeichert.
@ -252,7 +257,9 @@ include __DIR__ . '/../layout/kopf.php';
<div class="knopfleiste"> <div class="knopfleiste">
<button type="submit" class="knopf primaer">Kredit anlegen</button> <button type="submit" class="knopf primaer">Kredit anlegen</button>
<button type="submit" class="knopf" formmethod="dialog" formnovalidate>Abbrechen</button>
</div> </div>
</form> </form>
</dialog>
<?php include __DIR__ . '/../layout/fuss.php'; ?> <?php include __DIR__ . '/../layout/fuss.php'; ?>

View file

@ -24,6 +24,10 @@ include __DIR__ . '/../layout/kopf.php';
auf dem Konto lag. auf dem Konto lag.
</p> </p>
<div class="seitenaktionen">
<button type="button" class="knopf primaer" id="neu-knopf" data-neudialog="neudialog">+ Neu</button>
</div>
<?php if ($ziele === []): ?> <?php if ($ziele === []): ?>
<p class="platzhalter">Noch kein Sparziel angelegt.</p> <p class="platzhalter">Noch kein Sparziel angelegt.</p>
<?php else: ?> <?php else: ?>
@ -93,9 +97,10 @@ include __DIR__ . '/../layout/kopf.php';
</div> </div>
<?php endif; ?> <?php endif; ?>
<dialog id="neudialog" class="splitdialog neudialog">
<form method="post" action="/vertraege/sparziele/neu" class="formular breit"> <form method="post" action="/vertraege/sparziele/neu" class="formular breit">
<input type="hidden" name="csrf_token" value="<?= View::h($csrfToken) ?>"> <input type="hidden" name="csrf_token" value="<?= View::h($csrfToken) ?>">
<h3>Neues Sparziel</h3> <h2>Neues Sparziel</h2>
<label for="name">Name</label> <label for="name">Name</label>
<input type="text" id="name" name="name" required placeholder="z. B. Neues Auto"> <input type="text" id="name" name="name" required placeholder="z. B. Neues Auto">
@ -132,7 +137,9 @@ include __DIR__ . '/../layout/kopf.php';
<div class="knopfleiste"> <div class="knopfleiste">
<button type="submit" class="knopf primaer">Sparziel anlegen</button> <button type="submit" class="knopf primaer">Sparziel anlegen</button>
<button type="submit" class="knopf" formmethod="dialog" formnovalidate>Abbrechen</button>
</div> </div>
</form> </form>
</dialog>
<?php include __DIR__ . '/../layout/fuss.php'; ?> <?php include __DIR__ . '/../layout/fuss.php'; ?>

View file

@ -9,6 +9,7 @@ include __DIR__ . '/../layout/kopf.php';
?> ?>
<div class="seitenaktionen"> <div class="seitenaktionen">
<button type="button" class="knopf primaer" id="neu-knopf" data-neudialog="neudialog">+ Neu</button>
<a href="/verwaltung" class="knopf">Zurück zur Verwaltung</a> <a href="/verwaltung" class="knopf">Zurück zur Verwaltung</a>
<a href="/verwaltung/import" class="knopf">QIF-Import</a> <a href="/verwaltung/import" class="knopf">QIF-Import</a>
</div> </div>
@ -69,9 +70,10 @@ include __DIR__ . '/../layout/kopf.php';
</table> </table>
<?php endif; ?> <?php endif; ?>
<dialog id="neudialog" class="splitdialog neudialog">
<form method="post" action="/verwaltung/klassen/neu" class="formular breit"> <form method="post" action="/verwaltung/klassen/neu" class="formular breit">
<input type="hidden" name="csrf_token" value="<?= View::h($csrfToken) ?>"> <input type="hidden" name="csrf_token" value="<?= View::h($csrfToken) ?>">
<h3>Neue Klasse</h3> <h2>Neue Klasse</h2>
<label for="name">Name</label> <label for="name">Name</label>
<input type="text" id="name" name="name" required> <input type="text" id="name" name="name" required>
@ -81,7 +83,9 @@ include __DIR__ . '/../layout/kopf.php';
<div class="knopfleiste"> <div class="knopfleiste">
<button type="submit" class="knopf primaer">Klasse anlegen</button> <button type="submit" class="knopf primaer">Klasse anlegen</button>
<button type="submit" class="knopf" formmethod="dialog" formnovalidate>Abbrechen</button>
</div> </div>
</form> </form>
</dialog>
<?php include __DIR__ . '/../layout/fuss.php'; ?> <?php include __DIR__ . '/../layout/fuss.php'; ?>

View file

@ -27,6 +27,10 @@ include __DIR__ . '/../layout/kopf.php';
die Splitzeilen im gleichen Verhältnis mitgezogen. die Splitzeilen im gleichen Verhältnis mitgezogen.
</p> </p>
<div class="seitenaktionen">
<button type="button" class="knopf primaer" id="neu-knopf" data-neudialog="neudialog">+ Neu</button>
</div>
<form method="get" action="/vorlagen" class="filterleiste"> <form method="get" action="/vorlagen" class="filterleiste">
<label for="suche">Suchen</label> <label for="suche">Suchen</label>
<input type="search" id="suche" name="suche" value="<?= View::h($suche) ?>" <input type="search" id="suche" name="suche" value="<?= View::h($suche) ?>"
@ -106,9 +110,10 @@ include __DIR__ . '/../layout/kopf.php';
</table> </table>
<?php endif; ?> <?php endif; ?>
<dialog id="neudialog" class="splitdialog neudialog">
<form method="post" action="/vorlagen/neu" class="formular breit"> <form method="post" action="/vorlagen/neu" class="formular breit">
<input type="hidden" name="csrf_token" value="<?= View::h($csrfToken) ?>"> <input type="hidden" name="csrf_token" value="<?= View::h($csrfToken) ?>">
<h3>Neue Vorlage</h3> <h2>Neue Vorlage</h2>
<label for="name">Name</label> <label for="name">Name</label>
<input type="text" id="name" name="name" required> <input type="text" id="name" name="name" required>
@ -148,7 +153,9 @@ include __DIR__ . '/../layout/kopf.php';
<div class="knopfleiste"> <div class="knopfleiste">
<button type="submit" class="knopf primaer">Vorlage anlegen</button> <button type="submit" class="knopf primaer">Vorlage anlegen</button>
<button type="submit" class="knopf" formmethod="dialog" formnovalidate>Abbrechen</button>
</div> </div>
</form> </form>
</dialog>
<?php include __DIR__ . '/../layout/fuss.php'; ?> <?php include __DIR__ . '/../layout/fuss.php'; ?>

View file

@ -54,8 +54,9 @@ test.describe('Buchungen', () => {
await page.click('.formular button[type="submit"]') await page.click('.formular button[type="submit"]')
await page.goto('/verwaltung/klassen') await page.goto('/verwaltung/klassen')
await page.click('#neu-knopf')
await page.fill('form[action="/verwaltung/klassen/neu"] #name', KLASSE) await page.fill('form[action="/verwaltung/klassen/neu"] #name', KLASSE)
await page.click('form[action="/verwaltung/klassen/neu"] button[type="submit"]') await page.click('form[action="/verwaltung/klassen/neu"] button.primaer')
await page.close() await page.close()
}) })

View file

@ -201,6 +201,7 @@ test.describe('Module der Phasen 4 bis 7', () => {
test('Eine falsche IBAN wird beim Anlegen einer Adresse abgewiesen', async ({ page }) => { test('Eine falsche IBAN wird beim Anlegen einer Adresse abgewiesen', async ({ page }) => {
await page.goto('/vertraege/adressen') await page.goto('/vertraege/adressen')
await page.click('#neu-knopf')
await page.fill('#name', 'E2E-Falschtest') await page.fill('#name', 'E2E-Falschtest')
await page.fill('#iban', 'DE02120300000000202052') await page.fill('#iban', 'DE02120300000000202052')
@ -211,6 +212,7 @@ test.describe('Module der Phasen 4 bis 7', () => {
test('Ein Kredit zeigt seinen gerechneten Tilgungsplan', async ({ page }) => { test('Ein Kredit zeigt seinen gerechneten Tilgungsplan', async ({ page }) => {
await page.goto('/vertraege/kredite') await page.goto('/vertraege/kredite')
await page.click('#neu-knopf')
await page.fill('#name', 'E2E-Darlehen') await page.fill('#name', 'E2E-Darlehen')
await page.fill('#darlehensbetrag', '100000') await page.fill('#darlehensbetrag', '100000')
@ -314,10 +316,11 @@ test.describe('Module der Phasen 4 bis 7', () => {
test('Regelmäßige Buchungen werden per Klick bearbeitbar', async ({ page }) => { test('Regelmäßige Buchungen werden per Klick bearbeitbar', async ({ page }) => {
await page.goto('/termine') await page.goto('/termine')
await page.click('#neu-knopf')
await page.fill('#name', 'E2E-Reihe') await page.fill('#name', 'E2E-Reihe')
await page.fill('#neu_betrag', '-12,50') await page.fill('#neu_betrag', '-12,50')
await page.fill('#neu_buchungstext', 'E2E-Text') await page.fill('#neu_buchungstext', 'E2E-Text')
await page.click('form[action="/termine/neu"] button[type="submit"]') await page.click('form[action="/termine/neu"] button.primaer')
const zeile = page.locator('table.reihen tr', { hasText: 'E2E-Reihe' }) const zeile = page.locator('table.reihen tr', { hasText: 'E2E-Reihe' })
await expect(zeile.locator('input[name="betrag"]')).toBeHidden() await expect(zeile.locator('input[name="betrag"]')).toBeHidden()
@ -398,6 +401,7 @@ test.describe('Module der Phasen 4 bis 7', () => {
// Erst eine Adresse anlegen, damit die Auswahl etwas zu bieten hat. // Erst eine Adresse anlegen, damit die Auswahl etwas zu bieten hat.
await page.goto('/vertraege/adressen') await page.goto('/vertraege/adressen')
await page.click('#neu-knopf')
await page.fill('#name', empfaenger) await page.fill('#name', empfaenger)
await page.fill('#iban', 'DE02120300000000202051') await page.fill('#iban', 'DE02120300000000202051')
await page.click('button:has-text("Adresse anlegen")') await page.click('button:has-text("Adresse anlegen")')

View file

@ -0,0 +1,60 @@
// @ts-check
const { test, expect } = require('@playwright/test')
const BENUTZER = process.env.E2E_USER || 'e2e'
const PASSWORT = process.env.E2E_PASSWORD || 'e2e-testpasswort'
const MARKE = Date.now().toString().slice(-6)
// Alle Listenansichten, in denen „+ Neu“ ein modales Formular zur Neuanlage öffnet.
const ANSICHTEN = [
'/verwaltung/klassen',
'/vorlagen',
'/termine',
'/termine/erinnerungen',
'/vertraege',
'/vertraege/adressen',
'/vertraege/sparziele',
'/vertraege/kredite',
'/banking/regeln',
'/planung/budget/verwaltung',
'/auswertungen/gruppen',
]
async function anmelden(page) {
await page.goto('/login')
await page.fill('#benutzername', BENUTZER)
await page.fill('#passwort', PASSWORT)
await page.click('button[type="submit"]')
await expect(page).toHaveURL(/\/$/)
}
test.describe('„+ Neu“ öffnet den Dialog zur Neuanlage', () => {
test.beforeEach(async ({ page }) => {
await anmelden(page)
})
for (const pfad of ANSICHTEN) {
test(`${pfad}: Dialog erst nach Klick, Abbrechen schließt ihn`, async ({ page }) => {
await page.goto(pfad)
await expect(page.locator('#neudialog')).toBeHidden()
await page.click('#neu-knopf')
await expect(page.locator('#neudialog')).toBeVisible()
await page.locator('#neudialog button', { hasText: 'Abbrechen' }).click()
await expect(page.locator('#neudialog')).toBeHidden()
})
}
test('Klasse anlegen: Dialog verschwindet, Eintrag steht in der Liste', async ({ page }) => {
const name = `E2E Dialogklasse ${MARKE}`
await page.goto('/verwaltung/klassen')
await page.click('#neu-knopf')
await page.fill('#neudialog #name', name)
await page.locator('#neudialog button[type="submit"]', { hasText: 'Klasse anlegen' }).click()
await expect(page.locator('#neudialog')).toBeHidden()
await expect(page.locator(`input[value="${name}"]`).first()).toBeVisible()
})
})

View file

@ -35,6 +35,7 @@ async function anmelden(page) {
*/ */
async function budgetAnlegen(page, name) { async function budgetAnlegen(page, name) {
await page.goto('/planung/budget/verwaltung') await page.goto('/planung/budget/verwaltung')
await page.click('#neu-knopf')
await page.fill('#name', name) await page.fill('#name', name)
await page.fill('#jahr', String(JAHR)) await page.fill('#jahr', String(JAHR))
await page.click('.formular button:has-text("Budget anlegen")') await page.click('.formular button:has-text("Budget anlegen")')

View file

@ -163,9 +163,10 @@ test.describe('Stammdaten', () => {
const name = `E2E Projekt ${MARKE}` const name = `E2E Projekt ${MARKE}`
await page.goto('/verwaltung/klassen') await page.goto('/verwaltung/klassen')
await page.click('#neu-knopf')
await page.fill('.formular #name', name) await page.fill('.formular #name', name)
await page.fill('.formular #beschreibung', 'aus dem E2E-Test') await page.fill('.formular #beschreibung', 'aus dem E2E-Test')
await page.click('.formular button[type="submit"]') await page.click('.formular button:has-text("Klasse anlegen")')
await expect(page.locator('.meldung-erfolg')).toBeVisible() await expect(page.locator('.meldung-erfolg')).toBeVisible()