feat: Sitzungsfreigabe für MCP-Bestätigungen + LessonStatus.Cancelled

Sitzungsfreigabe: McpConfirmDialog bietet zwei Checkboxen ("diese Art
von Aktion" / "alle KI-Aktionen für den Rest der Sitzung nicht mehr
nachfragen"), nur beim Bestätigen wirksam. IMcpConfirmationService.
ConfirmAsync bekommt einen per [CallerMemberName] automatisch
befüllten operationKey - kein bestehender Aufruf musste geändert
werden. Freigaben leben als In-Memory-Bookkeeping auf der
Confirmation-Service-Instanz, gelten bis App-Ende, werden aber trotzdem
geloggt, damit stillschweigende Bestätigungen nicht spurlos bleiben.
Grund: 17 identische Bestätigungen in Folge für eine neu generierte
Unterrichtseinheit sind unzumutbar.

LessonStatus.Cancelled ("Ausgefallen") als Alternative zu
delete_lesson für Stunden, die nur ausgefallen sind (Exkursion,
Feiertag), aber als Ereignis dokumentiert bleiben sollen. Als
Cancelled=4 angehängt (bestehende LiteDB-Werte 0/1 sind fix). Konsistent
wie "bereits durchgeführt" behandelt an allen Stellen, die bisher nur
auf Conducted prüften: Terminverschiebung, Fortschrittsanzeige,
Hausaufgabe-kontrollieren-Erinnerung, "nächste Stunde"-Vorschlag.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-12 02:25:45 +02:00
co-authored by Claude Sonnet 5
parent a4733c156b
commit 19aa302487
16 changed files with 231 additions and 25 deletions
@@ -6,7 +6,7 @@
Width="520" MinHeight="240" SizeToContent="Height"
CanResize="True" WindowStartupLocation="CenterOwner"
Topmost="True" ShowInTaskbar="True">
<Grid RowDefinitions="Auto,*,Auto">
<Grid RowDefinitions="Auto,*,Auto,Auto">
<Border Grid.Row="0" Background="#FFF4E5" BorderBrush="#D97706" BorderThickness="0,0,0,3" Padding="24,16">
<StackPanel Spacing="4">
<TextBlock Text="Vorschlag deines KI-Assistenten — bitte prüfen" FontSize="12" FontWeight="SemiBold" Foreground="#8A5A00"/>
@@ -16,7 +16,13 @@
<ScrollViewer Grid.Row="1" MaxHeight="380" Margin="24,18">
<TextBlock Text="{Binding Message}" TextWrapping="Wrap" FontSize="14" LineHeight="20"/>
</ScrollViewer>
<Grid Grid.Row="2" ColumnDefinitions="*,10,*" Margin="24,0,24,20">
<StackPanel Grid.Row="2" Margin="24,0,24,14" Spacing="6">
<CheckBox x:Name="TrustOperationCheck" FontSize="12"
Content="Diese Art von Aktion für den Rest der Sitzung nicht mehr nachfragen"/>
<CheckBox x:Name="TrustAllCheck" FontSize="12"
Content="Alle KI-Aktionen für den Rest der Sitzung nicht mehr nachfragen"/>
</StackPanel>
<Grid Grid.Row="3" ColumnDefinitions="*,10,*" Margin="24,0,24,20">
<Button Grid.Column="0" Content="Ablehnen" HorizontalAlignment="Stretch" Padding="0,12" FontSize="14" Click="OnCancel"/>
<Button Grid.Column="2" Content="{Binding ConfirmText}" HorizontalAlignment="Stretch" Padding="0,12" FontSize="14"
FontWeight="SemiBold" Background="#D97706" Foreground="White" Click="OnConfirm"/>
@@ -7,6 +7,9 @@ public partial class McpConfirmDialog : Window
{
public McpConfirmDialog() => InitializeComponent();
private void OnConfirm(object? sender, RoutedEventArgs e) => Close(true);
private void OnCancel(object? sender, RoutedEventArgs e) => Close(false);
private void OnConfirm(object? sender, RoutedEventArgs e) =>
Close(new McpConfirmDialogResult(true, TrustOperationCheck.IsChecked == true, TrustAllCheck.IsChecked == true));
// Checkbox-Zustand wird beim Ablehnen bewusst ignoriert (siehe McpConfirmDialogResult).
private void OnCancel(object? sender, RoutedEventArgs e) => Close(McpConfirmDialogResult.Rejected);
}
@@ -0,0 +1,10 @@
namespace LehrerApp.Desktop.Views.Mcp;
/// <summary>Ergebnis von <see cref="McpConfirmDialog"/>. <see cref="TrustOperation"/>/
/// <see cref="TrustAll"/> sind nur bei <see cref="Approved"/>=true aussagekräftig — beim Ablehnen
/// werden sie ignoriert (siehe McpConfirmDialog.axaml.cs), Ablehnen + "nicht mehr nachfragen" wäre
/// widersprüchlich.</summary>
public record McpConfirmDialogResult(bool Approved, bool TrustOperation, bool TrustAll)
{
public static McpConfirmDialogResult Rejected { get; } = new(false, false, false);
}