Stundenverlaufsplan: Viewer und Alternativpfad-Katalog (Kapitel 4.2 Nachtrag)

Schreibgeschützter LessonViewerDialog (größere Schrift, ohne Bearbeitungs-/Verlängern-/
Verschieben-Funktion) für den Einsatz während des Unterrichtens, erreichbar über "Anzeigen"
im Stunden-Toolbar.

Alternative Unterrichtsabläufe (z.B. Kurzversion bei Zeitmangel) laufen jetzt über einen
echten Katalog (neues Modell AlternativeLessonPath: Name + Beschreibung) statt Freitext direkt
an der Phase: im Verlaufsplan-Editor eine kompakte, farbig unterstützte Checkbox statt einer
durchgehend sichtbaren Eingabespalte, Zuordnung/Neuanlage über einen eigenen Dialog. Der Viewer
gruppiert Phasen entsprechend und zeigt die hinterlegte Beschreibung. Schema-Migration v3→v4
führt bestehende Freitextwerte verlustfrei in Katalogeinträge über.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-14 01:53:12 +02:00
co-authored by Claude Sonnet 5
parent de6ea001e7
commit ee1a47641e
22 changed files with 904 additions and 33 deletions
+56 -2
View File
@@ -121,7 +121,7 @@ public sealed class LiteDbContextTests
using var temp = new TempDatabase();
using var context = new LiteDbContext(temp.Path);
Assert.Equal(3, context.SchemaVersion);
Assert.Equal(4, context.SchemaVersion);
}
[Fact]
@@ -132,7 +132,7 @@ public sealed class LiteDbContextTests
using var second = new LiteDbContext(temp.Path);
Assert.Equal(3, second.SchemaVersion);
Assert.Equal(4, second.SchemaVersion);
}
[Fact]
@@ -224,6 +224,60 @@ public sealed class LiteDbContextTests
Assert.False(rawPhases[0].AsDocument.ContainsKey("ShorthandTo"));
}
[Fact]
public void MigrateLessonAlternativePaths_ErzeugtKatalogEintraegeUndVerweistDarauf()
{
using var temp = new TempDatabase();
var lesson1Id = Guid.NewGuid();
var lesson2Id = Guid.NewGuid();
using (var legacy = new LiteDatabase(temp.Path))
{
legacy.GetCollection<BsonDocument>("lessons").Insert(new BsonDocument
{
["_id"] = lesson1Id,
[nameof(Lesson.UnitId)] = Guid.NewGuid(),
[nameof(Lesson.GroupId)] = Guid.NewGuid(),
[nameof(Lesson.Phases)] = new BsonArray
{
new BsonDocument { ["AlternativePath"] = "Kurzversion" },
new BsonDocument { ["AlternativePath"] = "" }, // Hauptweg, kein Katalogeintrag
new BsonDocument { }, // gar kein Feld, unangetastet
},
});
legacy.GetCollection<BsonDocument>("lessons").Insert(new BsonDocument
{
["_id"] = lesson2Id,
[nameof(Lesson.UnitId)] = Guid.NewGuid(),
[nameof(Lesson.GroupId)] = Guid.NewGuid(),
[nameof(Lesson.Phases)] = new BsonArray
{
new BsonDocument { ["AlternativePath"] = "Kurzversion" }, // gleicher Name -> gleicher Katalogeintrag
},
});
}
using (var context = new LiteDbContext(temp.Path))
{
var catalog = context.AlternativeLessonPaths.FindAll().ToList();
var entry = Assert.Single(catalog);
Assert.Equal("Kurzversion", entry.Name);
var lesson1 = context.Lessons.FindById(lesson1Id)!;
Assert.Equal(entry.Id, lesson1.Phases[0].AlternativePathId);
Assert.Null(lesson1.Phases[1].AlternativePathId);
Assert.Null(lesson1.Phases[2].AlternativePathId);
var lesson2 = context.Lessons.FindById(lesson2Id)!;
Assert.Equal(entry.Id, lesson2.Phases[0].AlternativePathId); // wiederverwendeter Katalogeintrag
}
using var migrated = new LiteDatabase(temp.Path);
var rawLesson1 = migrated.GetCollection<BsonDocument>("lessons").FindById(lesson1Id);
var rawPhases = rawLesson1["Phases"].AsArray;
Assert.False(rawPhases[0].AsDocument.ContainsKey("AlternativePath"));
}
private sealed class TempDatabase : IDisposable
{
private readonly string _directory = System.IO.Path.Combine(