feat: unbenutzte Sitzplätze ausblenden können

Manche Räume sind unregelmäßig bestückt (z.B. eine Klasse mit 3 Reihen, in zwei davon fehlt ein
Einzeltisch) - das feste Rows x Columns-Raster kennt aber keine per-Reihe abweichende Spaltenzahl.

Neues Feld SeatingPlan.HiddenSeats für Plätze ohne physischen Tisch. Ein ausgeblendeter Platz
bleibt Teil des Rasters (für die Spalten-/Reihenausrichtung von SeatingPlanPanel), wird im
Ansichtsmodus aber nicht gerendert; im Bearbeitungsmodus bleibt er sichtbar (abgeblendet) mit
einem Umschalt-Button direkt auf dem Platz. Nur leere Plätze lassen sich ausblenden; Zuweisen/
Verschieben eines Schülers auf einen ausgeblendeten Platz wird sowohl im ViewModel als auch im
Drag&Drop-Ziel-Check verhindert. SeatingPlanRepository.Save filtert HiddenSeats zusätzlich auf
das gültige Raster und blendet einen Platz automatisch wieder ein, falls er trotzdem belegt wird.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-20 12:06:26 +02:00
co-authored by Claude Sonnet 5
parent 391628ae36
commit c5a1157a7d
8 changed files with 334 additions and 8 deletions
+52
View File
@@ -303,6 +303,58 @@ public sealed class RepositoryTests
Assert.Throws<InvalidOperationException>(() => new SeatingPlanRepository(db).Save(plan));
}
[Fact]
public void SeatingPlanRepository_FiltertAusgeblendetePlaetzeAusserhalbDesRasters()
{
using var db = NewInMemoryContext();
var group = new LearningGroup { Name = "8a", SchoolYear = "2025/26" };
new GroupRepository(db).Save(group);
var plan = new SeatingPlan
{
GroupId = group.Id, Name = "Standard", Rows = 2, Columns = 2,
HiddenSeats =
[
new HiddenSeat { Row = 0, Column = 1 },
new HiddenSeat { Row = 5, Column = 5 }, // außerhalb des 2x2-Rasters
],
};
new SeatingPlanRepository(db).Save(plan);
var saved = db.SeatingPlans.FindById(plan.Id);
Assert.NotNull(saved);
var hidden = Assert.Single(saved.HiddenSeats);
Assert.Equal((0, 1), (hidden.Row, hidden.Column));
}
/// Ein ausgeblendeter Platz darf nie belegt sein - die Zuordnung eines Schülers ist wertvoller
/// als das Ausblenden. SeatingPlanTabViewModel verhindert das Belegen ausgeblendeter Plätze
/// bereits in der UI; diese Absicherung greift für Daten, die diesen Weg umgehen (z. B. Sync
/// von einem älteren Client).
[Fact]
public void SeatingPlanRepository_BlendetPlatzWiederEinWennErBelegtWird()
{
using var db = NewInMemoryContext();
var group = new LearningGroup { Name = "8a", SchoolYear = "2025/26" };
new GroupRepository(db).Save(group);
var student = new Student { FirstName = "Anna", LastName = "A" };
db.Students.Insert(student);
db.Memberships.Insert(new GroupMembership { GroupId = group.Id, StudentId = student.Id });
var plan = new SeatingPlan
{
GroupId = group.Id, Name = "Standard", Rows = 2, Columns = 2,
HiddenSeats = [new HiddenSeat { Row = 0, Column = 0 }],
Assignments = [new SeatAssignment { Row = 0, Column = 0, StudentId = student.Id }],
};
new SeatingPlanRepository(db).Save(plan);
var saved = db.SeatingPlans.FindById(plan.Id);
Assert.NotNull(saved);
Assert.Empty(saved.HiddenSeats);
Assert.Equal(student.Id, saved.Assignments.Single().StudentId);
}
[Fact]
public void SeatingPlanRepository_AktualisiertPlanMitFehlendemOptionalenRaum()
{