UX-Update 2.0, Neues Dashboard

This commit is contained in:
2026-08-29 00:45:19 +02:00
parent 229ef79e75
commit 9b04d7eb98
14 changed files with 774 additions and 355 deletions
@@ -11,6 +11,22 @@ namespace LehrerApp.Desktop.Tests;
/// (offene Aufgaben, ...).
public sealed class DashboardViewModelTests
{
[Fact]
public void LeereHinweisbereiche_WerdenAusgeblendetUndZusammenfassungBleibtKompakt()
{
var group = new LearningGroup { Name = "9c" };
var today = DateOnly.FromDateTime(DateTime.Today);
var vm = BuildVm(group, new Lesson { GroupId = group.Id, Date = today });
Assert.False(vm.ExcusesCard.EffectiveIsVisible);
Assert.False(vm.CorrectionsCard.EffectiveIsVisible);
Assert.False(vm.AlertsCard.EffectiveIsVisible);
Assert.Equal("0 offene Punkte", vm.AttentionSummary);
Assert.True(vm.TodayCard.EffectiveIsVisible);
Assert.True(vm.CalendarCard.EffectiveIsVisible);
}
private static PeriodScheduleService NewPeriodSchedule()
{
var tempPath = System.IO.Path.Combine(
@@ -0,0 +1,74 @@
using LehrerApp.Core.Models;
using LehrerApp.Desktop.ViewModels;
using Xunit;
namespace LehrerApp.Desktop.Tests;
public sealed class GlobalSearchViewModelTests
{
[Fact]
public void LeereSuche_ZeigtSchnellaktionen()
{
var vm = BuildVm();
Assert.Collection(vm.Results,
item => Assert.Equal(GlobalSearchAction.NewTask, item.Action),
item => Assert.Equal(GlobalSearchAction.NewReminder, item.Action),
item => Assert.Equal(GlobalSearchAction.NewStudent, item.Action));
Assert.Same(vm.Results[0], vm.SelectedResult);
}
[Fact]
public void Suche_FindetSchuelerGruppeKlausurUndAufgabe()
{
var group = new LearningGroup { Name = "9 Chemie", SchoolYear = "2026/27", GradeLevel = 9 };
var student = new Student { FirstName = "Mia", LastName = "Chemie" };
var exam = new Exam { GroupId = group.Id, Title = "Chemie-Test", Date = new DateOnly(2026, 9, 1) };
var tasks = new FakeWorkTasks();
tasks.Add(new WorkTask { GroupId = group.Id, Title = "Chemie-Klausur korrigieren" });
var vm = BuildVm([student], [group], [exam], tasks);
vm.Query = "Chemie";
Assert.Contains(vm.Results, x => x.Kind == GlobalSearchResultKind.Student && x.EntityId == student.Id);
Assert.Contains(vm.Results, x => x.Kind == GlobalSearchResultKind.Group && x.EntityId == group.Id);
Assert.Contains(vm.Results, x => x.Kind == GlobalSearchResultKind.Exam && x.EntityId == exam.Id);
Assert.Contains(vm.Results, x => x.Kind == GlobalSearchResultKind.Task && x.Title.Contains("korrigieren"));
}
[Fact]
public async Task TrefferAusfuehren_NavigiertUndSchliesstPalette()
{
var student = new Student { FirstName = "Mia", LastName = "Muster" };
var vm = BuildVm([student]);
vm.Query = "Muster";
var result = Assert.Single(vm.Results, x => x.Kind == GlobalSearchResultKind.Student);
GlobalSearchResult? navigated = null;
var closed = false;
vm.OnNavigate = x => navigated = x;
vm.OnClose = () => closed = true;
await vm.ExecuteCommand.ExecuteAsync(result);
Assert.Same(result, navigated);
Assert.True(closed);
}
[Fact]
public async Task ErinnerungSchnellErfassen_StartetDialogAlsErinnerung()
{
var vm = BuildVm();
bool? reminder = null;
vm.OnQuickAddTask = value => { reminder = value; return Task.CompletedTask; };
var action = vm.Results.Single(x => x.Action == GlobalSearchAction.NewReminder);
await vm.ExecuteCommand.ExecuteAsync(action);
Assert.True(reminder);
}
private static GlobalSearchViewModel BuildVm(List<Student>? students = null,
List<LearningGroup>? groups = null, List<Exam>? exams = null, FakeWorkTasks? tasks = null) =>
new(new FakeStudents(students ?? []), new FakeGroups(groups ?? []),
new FakeExams(exams ?? []), tasks ?? new FakeWorkTasks());
}
@@ -5,76 +5,69 @@ using Xunit;
namespace LehrerApp.Desktop.Tests;
/// Tests für den Schnellüberblick im Auswahl-Panel der Gruppenliste (Nutzer-Feedback:
/// "oberhalb der Buttonliste ein paar Daten auswerfen. Nächste Stunde, nächste Arbeit,
/// wichtige Todos").
/// <summary>Tests für die direkte, einlagige Lerngruppen-Navigation.</summary>
public sealed class GroupListViewModelTests
{
private static GroupListViewModel BuildVm(LearningGroup group, FakeLessons? lessons = null,
FakeExams? exams = null, FakeWorkTasks? tasks = null) =>
new(new FakeGroups([group]), new FakeSubjects([]), new SchoolYearService(),
lessons ?? new FakeLessons(), exams ?? new FakeExams([]), tasks ?? new FakeWorkTasks());
private static GroupListViewModel BuildVm(params LearningGroup[] groups) =>
new(new FakeGroups([.. groups]), new FakeSubjects([]), new SchoolYearService());
[Fact]
public void SelectedGroup_OhneDatenZeigtKeinenSchnellueberblick()
public void Gruppenkarte_OeffnetDirektDieUebersicht()
{
var group = new LearningGroup { Name = "9c" };
var group = CurrentGroup("9c");
var vm = BuildVm(group);
Guid? openedId = null;
int? openedTab = null;
vm.OnNavigateToDetail = (id, tab) => { openedId = id; openedTab = tab; };
vm.SelectedGroup = vm.Groups.Count > 0 ? vm.Groups[0] : new GroupListItem(group, "");
Assert.Single(vm.Groups).OpenCommand.Execute(null);
Assert.False(vm.QuickHasAnything);
Assert.Equal(group.Id, openedId);
Assert.Equal(0, openedTab);
}
[Fact]
public void SelectedGroup_ZeigtNaechsteGeplanteStundeUndKlausur()
public async Task Verwaltungsmenue_BearbeitetDieGewaehlteKarteOhneZwischenauswahl()
{
var group = new LearningGroup { Name = "9c" };
var today = DateOnly.FromDateTime(DateTime.Today);
var lessons = new FakeLessons();
lessons.Add(new Lesson { GroupId = group.Id, Date = today.AddDays(3), Topic = "Redox", Status = LessonStatus.Planned });
var exams = new FakeExams([new Exam { GroupId = group.Id, Date = today.AddDays(10), Title = "Klausur 1" }]);
var vm = BuildVm(group, lessons: lessons, exams: exams);
var first = CurrentGroup("9a");
var second = CurrentGroup("9b");
var vm = BuildVm(first, second);
Guid? editedId = null;
vm.OnEditGroup = id => { editedId = id; return Task.CompletedTask; };
var secondItem = vm.Groups.Single(x => x.Id == second.Id);
vm.SelectedGroup = new GroupListItem(group, "");
await secondItem.EditCommand.ExecuteAsync(null);
Assert.True(vm.QuickHasNextLesson);
Assert.Contains("Redox", vm.QuickNextLessonLabel);
Assert.True(vm.QuickHasNextExam);
Assert.Contains("Klausur 1", vm.QuickNextExamLabel);
Assert.True(vm.QuickHasAnything);
Assert.Equal(second.Id, editedId);
}
[Fact]
public void SelectedGroup_ZeigtOffeneAufgabenDieserGruppeSortiertNachFaelligkeit()
public void Suche_FiltertWeiterhinNachGruppenname()
{
var group = new LearningGroup { Name = "9c" };
var today = DateOnly.FromDateTime(DateTime.Today);
var tasks = new FakeWorkTasks();
tasks.Add(new WorkTask { GroupId = group.Id, Title = "Bald fällig", DueDate = today.AddDays(1), Status = WorkTaskStatus.Open });
tasks.Add(new WorkTask { GroupId = group.Id, Title = "Erledigt", DueDate = today, Status = WorkTaskStatus.Done });
tasks.Add(new WorkTask { GroupId = Guid.NewGuid(), Title = "Andere Gruppe", DueDate = today, Status = WorkTaskStatus.Open });
var vm = BuildVm(group, tasks: tasks);
var vm = BuildVm(CurrentGroup("9 Chemie"), CurrentGroup("10 Mathematik"));
vm.SelectedGroup = new GroupListItem(group, "");
vm.SearchText = "Chemie";
Assert.True(vm.QuickHasTasks);
Assert.Equal("Bald fällig", Assert.Single(vm.QuickTasks).Title);
Assert.Equal("9 Chemie", Assert.Single(vm.Groups).Name);
}
[Fact]
public void SelectedGroup_Zuruecksetzen_LeertSchnellueberblick()
public void Archivieren_WirktAufDieKarteUndEntferntSieAusDerAktivenListe()
{
var group = new LearningGroup { Name = "9c" };
var today = DateOnly.FromDateTime(DateTime.Today);
var exams = new FakeExams([new Exam { GroupId = group.Id, Date = today.AddDays(10), Title = "Klausur 1" }]);
var vm = BuildVm(group, exams: exams);
vm.SelectedGroup = new GroupListItem(group, "");
Assert.True(vm.QuickHasAnything);
var group = CurrentGroup("9c");
var vm = BuildVm(group);
var item = Assert.Single(vm.Groups);
vm.SelectedGroup = null;
item.ToggleArchiveCommand.Execute(null);
Assert.False(vm.QuickHasAnything);
Assert.Empty(vm.QuickTasks);
Assert.False(group.IsActive);
Assert.Empty(vm.Groups);
}
private static LearningGroup CurrentGroup(string name) => new()
{
Name = name,
SchoolYear = new SchoolYearService().CurrentSchoolYear(),
IsActive = true,
};
}