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:
@@ -11,7 +11,7 @@ public class LiteDbContext : IDisposable
|
||||
/// Aktuelle Schema-Version. Migrationsschritte werden versioniert unter
|
||||
/// <see cref="RunVersionedMigrations"/> ergänzt, statt bei jedem Start erneut
|
||||
/// (idempotent, aber unnötig) über alle Daten zu laufen.
|
||||
private const int CurrentSchemaVersion = 3;
|
||||
private const int CurrentSchemaVersion = 4;
|
||||
|
||||
private readonly LiteDatabase _db;
|
||||
|
||||
@@ -56,6 +56,7 @@ public class LiteDbContext : IDisposable
|
||||
public ILiteCollection<Subject> Subjects => _db.GetCollection<Subject>("subjects");
|
||||
public ILiteCollection<CompetencyDomain> CompetencyDomains => _db.GetCollection<CompetencyDomain>("competency_domains");
|
||||
public ILiteCollection<ShorthandCode> ShorthandCodes => _db.GetCollection<ShorthandCode>("shorthand_codes");
|
||||
public ILiteCollection<AlternativeLessonPath> AlternativeLessonPaths => _db.GetCollection<AlternativeLessonPath>("alternative_lesson_paths");
|
||||
|
||||
public void Checkpoint() => _db.Checkpoint();
|
||||
|
||||
@@ -94,6 +95,11 @@ public class LiteDbContext : IDisposable
|
||||
MigrateLessonShorthand();
|
||||
version = 3;
|
||||
}
|
||||
if (version < 4)
|
||||
{
|
||||
MigrateLessonAlternativePaths();
|
||||
version = 4;
|
||||
}
|
||||
WriteSchemaVersion(version);
|
||||
}
|
||||
|
||||
@@ -258,6 +264,46 @@ public class LiteDbContext : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
/// Führt das anfangs freie Textfeld für den alternativen Ablauf einer Phase
|
||||
/// (<c>AlternativePath</c>, String) in einen Verweis auf einen Katalogeintrag
|
||||
/// (<see cref="LessonPhaseStep.AlternativePathId"/>) über — pro bisher verwendetem, distinktem
|
||||
/// Namen wird ein <see cref="AlternativeLessonPath"/> angelegt (bzw. ein gleichnamiger
|
||||
/// wiederverwendet) und referenziert. Die neue Collection ist von dieser Migration selbst nicht
|
||||
/// betroffen (keine Altstruktur), daher direkter Zugriff über die typisierte Collection.
|
||||
private void MigrateLessonAlternativePaths()
|
||||
{
|
||||
var lessons = _db.GetCollection<BsonDocument>("lessons");
|
||||
var nameToId = new Dictionary<string, Guid>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var existing in AlternativeLessonPaths.FindAll()) nameToId[existing.Name] = existing.Id;
|
||||
|
||||
foreach (var lesson in lessons.FindAll().ToList())
|
||||
{
|
||||
if (!lesson.TryGetValue(nameof(Lesson.Phases), out var phasesValue) || !phasesValue.IsArray) continue;
|
||||
|
||||
var changed = false;
|
||||
foreach (var phaseValue in phasesValue.AsArray)
|
||||
{
|
||||
if (phaseValue is not BsonDocument phase) continue;
|
||||
if (!phase.TryGetValue("AlternativePath", out var oldVal) || !oldVal.IsString) continue;
|
||||
|
||||
var name = oldVal.AsString.Trim();
|
||||
phase.Remove("AlternativePath");
|
||||
changed = true;
|
||||
if (name.Length == 0) continue;
|
||||
|
||||
if (!nameToId.TryGetValue(name, out var id))
|
||||
{
|
||||
var entry = new AlternativeLessonPath { Name = name };
|
||||
AlternativeLessonPaths.Insert(entry);
|
||||
id = entry.Id;
|
||||
nameToId[name] = id;
|
||||
}
|
||||
phase[nameof(LessonPhaseStep.AlternativePathId)] = id;
|
||||
}
|
||||
if (changed) lessons.Update(lesson);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveRedundantLegacyFields()
|
||||
{
|
||||
RemoveFields("exams", "Subject");
|
||||
@@ -322,6 +368,7 @@ public class LiteDbContext : IDisposable
|
||||
CompetencyDomains.EnsureIndex(x => x.SubjectId);
|
||||
CompetencyDomains.EnsureIndex(x => x.GradeLevel);
|
||||
ShorthandCodes.EnsureIndex("ux_shorthand_code", BsonExpression.Create("LOWER(TRIM($.Code))"), unique: true);
|
||||
AlternativeLessonPaths.EnsureIndex("ux_alt_lesson_path_name", BsonExpression.Create("LOWER(TRIM($.Name))"), unique: true);
|
||||
}
|
||||
|
||||
public void Dispose() => _db.Dispose();
|
||||
|
||||
@@ -367,6 +367,25 @@ public class ShorthandCodeRepository(LiteDbContext db) : IShorthandCodeRepositor
|
||||
public void Delete(Guid id) => db.ShorthandCodes.Delete(id);
|
||||
}
|
||||
|
||||
public class AlternativeLessonPathRepository(LiteDbContext db) : IAlternativeLessonPathRepository
|
||||
{
|
||||
public List<AlternativeLessonPath> GetAll() => db.AlternativeLessonPaths.FindAll().OrderBy(p => p.Name).ToList();
|
||||
public AlternativeLessonPath? GetById(Guid id) => db.AlternativeLessonPaths.FindById(id);
|
||||
public void Save(AlternativeLessonPath p)
|
||||
{
|
||||
p.Name = p.Name.Trim();
|
||||
p.Description = string.IsNullOrWhiteSpace(p.Description) ? null : p.Description.Trim();
|
||||
if (p.Name.Length == 0) throw new ArgumentException("Der Name darf nicht leer sein.");
|
||||
var duplicate = db.AlternativeLessonPaths.FindAll()
|
||||
.FirstOrDefault(x => string.Equals(x.Name, p.Name, StringComparison.OrdinalIgnoreCase));
|
||||
if (duplicate is not null && duplicate.Id != p.Id)
|
||||
throw new InvalidOperationException("Ein alternativer Ablauf mit diesem Namen existiert bereits.");
|
||||
p.UpdatedAt = DateTime.UtcNow;
|
||||
db.AlternativeLessonPaths.Upsert(p);
|
||||
}
|
||||
public void Delete(Guid id) => db.AlternativeLessonPaths.Delete(id);
|
||||
}
|
||||
|
||||
public class CompetencyDomainRepository(LiteDbContext db) : ICompetencyDomainRepository
|
||||
{
|
||||
public List<CompetencyDomain> GetBySubjectAndGrade(Guid subjectId, int gradeLevel) =>
|
||||
|
||||
Reference in New Issue
Block a user