feat: Importkonflikte gesammelt übernehmen

This commit is contained in:
2026-08-18 00:52:05 +02:00
parent 99efa3a0fe
commit 65c2211dab
4 changed files with 69 additions and 2 deletions
@@ -30,6 +30,7 @@ public partial class StudentImportDialogViewModel : ObservableObject
public ObservableCollection<StudentImportConflictItem> Conflicts { get; } = [];
public bool HasMessages => Messages.Count > 0;
public bool HasConflicts => Conflicts.Count > 0;
public bool CanUseExistingForAll => Conflicts.Any(conflict => conflict.HasSingleExistingStudentOption);
public bool IsReadyWithoutConflicts => !HasConflicts && _preview.CanApply;
public bool HasBlockingErrors => !_preview.CanApply;
public bool CanApply => _preview.CanApply && !IsBusy;
@@ -65,6 +66,16 @@ public partial class StudentImportDialogViewModel : ObservableObject
.ToList()
.AsReadOnly();
/// <summary>
/// Wählt für alle eindeutigen Schüler-Konflikte den jeweils vorhandenen Datensatz.
/// Mehrdeutige Treffer und Lerngruppen-Konflikte bleiben unverändert.
/// </summary>
public void UseExistingForAll()
{
foreach (var conflict in Conflicts)
conflict.TrySelectSingleExistingStudent();
}
public async Task<bool> TryApplyAsync()
{
Error = "";
@@ -116,6 +127,8 @@ public sealed class StudentImportMessageItem
public partial class StudentImportConflictItem : ObservableObject
{
private const string ExistingStudentOptionPrefix = "existing:";
[ObservableProperty] private StudentImportConflictOptionItem _selectedOption;
public string Id { get; }
@@ -125,6 +138,11 @@ public partial class StudentImportConflictItem : ObservableObject
public string ExistingValue { get; }
public string SourceReference { get; }
public IReadOnlyList<StudentImportConflictOptionItem> Options { get; }
public bool HasSingleExistingStudentOption => ExistingStudentOptions.Count == 1;
private IReadOnlyList<StudentImportConflictOptionItem> ExistingStudentOptions => Options
.Where(option => option.Id.StartsWith(ExistingStudentOptionPrefix, StringComparison.Ordinal))
.ToList();
public StudentImportConflictItem(ImportConflict conflict)
{
@@ -141,6 +159,14 @@ public partial class StudentImportConflictItem : ObservableObject
.AsReadOnly();
_selectedOption = Options.First(option => option.Id == conflict.DefaultOptionId);
}
public bool TrySelectSingleExistingStudent()
{
var options = ExistingStudentOptions;
if (options.Count != 1) return false;
SelectedOption = options[0];
return true;
}
}
public sealed record StudentImportConflictOptionItem(