UI-Entwurf umgesetzt, Rocket.Chat-Tool, Deploymentcenter 2.4
Sicherungspunkt vor dem Aufraeumen. Buendelt die Arbeit, die seit dem Abschluss der Avalonia-Portierung im Arbeitsverzeichnis lag. Oberflaeche - Entwurf aus Mockup/ umgesetzt: Theme.axaml (Farben je Thema, Barlow als mitgelieferte Schrift), Icons.axaml (Symbolgeometrien), Shell.axaml (eigene ControlThemes statt Fluent umzufaerben). - Neue Steuerelemente StrokeIcon und BlueprintFrame, Seiten fuer Token-Verbrauch und Agenten-Chats, Werkzeug-Einstellungen als Seite statt eigenem Fenster, Texteditor-Fenster. - ThemeManager mit hellem und dunklem Thema; die beiden Pinsel-Konverter entfallen, weil ein fester Farbwert den Themenwechsel nicht ueberlebt. Rocket.Chat - Neues Tool-Projekt (Client, Konfiguration, Workspace-Dateien) nach der Bauform des Telegram-Tools: rocketchat_poll als Tool-Job, geweckt wird nur, wenn wirklich etwas anliegt. - send_file ist freigabepflichtig, send_message bewusst nicht: Der Raum ist Arbeitsraum, der Schutz sitzt an der Raum-Allowlist. - Konzept-Doc um die Messung gegen die echte Instanz 8.7 ergaenzt; drei Annahmen waren falsch und sind korrigiert. Deploymentcenter - DC6 (Update anwenden) und DC7 (Erstinstallation ueber setup.json) erledigt, DC3 fuer win-x64/dev; deploy/publish.py als Release-Strecke. - AppHost.DisposeAsync gegen doppeltes Herunterfahren gesperrt - sonst ueberschreibt eine zweite Abmeldung den Wartungszustand am Watchdog. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,21 +7,52 @@ using CommunityToolkit.Mvvm.Input;
|
||||
namespace ClawdDotNet.Desktop.ViewModels;
|
||||
|
||||
/// <summary>
|
||||
/// Auswahl der Instanz beim Start — der erste Rückruf, den <c>AppHost</c> erfragt.
|
||||
/// Eine Instanz in der Auswahl.
|
||||
///
|
||||
/// Die WinForms-Fassung mischte Datenzugriff, Spaltenformatierung und Meldungsfenster in
|
||||
/// einem Formular. Hier steht nur, <em>was</em> geschieht; das <em>wie</em> es aussieht
|
||||
/// <para>Das Monogramm und der Punkt stammen aus dem Entwurf. Der Punkt zeigt bewusst
|
||||
/// <em>Bereitschaft</em> und nicht „läuft": Ob eine andere Instanz gerade läuft, weiß
|
||||
/// diese Anwendung nicht — jede Instanz ist ein eigener Prozess, und einen
|
||||
/// instanzübergreifenden Status gibt es noch nicht. Ein grüner Punkt für „läuft" wäre
|
||||
/// hier schlicht geraten.</para>
|
||||
/// </summary>
|
||||
public sealed class InstanceChoiceViewModel(InstanceInfo info, bool isCurrent)
|
||||
{
|
||||
public InstanceInfo Info { get; } = info;
|
||||
|
||||
public string InstanceName => Info.InstanceName;
|
||||
public string FolderPath => Info.FolderPath;
|
||||
|
||||
/// <summary>Erste zwei Buchstaben, gross — wie im Entwurf.</summary>
|
||||
public string Monogram => Info.InstanceName.Length >= 2
|
||||
? Info.InstanceName[..2].ToUpperInvariant()
|
||||
: Info.InstanceName.ToUpperInvariant();
|
||||
|
||||
public string Summary => $"{Info.AgentCount} Agenten · API-Key {Info.ApiKeyStatus.ToLowerInvariant()}";
|
||||
|
||||
/// <summary>Ohne API-Key kann die Instanz keine Agenten starten.</summary>
|
||||
public bool IsReady => Info.ApiKeyStatus.Equals("Konfiguriert", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>Die gerade laufende Instanz — traegt im Entwurf das Etikett „Aktiv".</summary>
|
||||
public bool IsCurrent { get; } = isCurrent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Auswahl der Instanz — beim Start und beim Wechseln aus der laufenden Anwendung.
|
||||
///
|
||||
/// <para>Die WinForms-Fassung mischte Datenzugriff, Spaltenformatierung und Meldungsfenster
|
||||
/// in einem Formular. Hier steht nur, <em>was</em> geschieht; das <em>wie</em> es aussieht
|
||||
/// liegt in der Ansicht, und Rückfragen laufen über <see cref="ConfirmError"/> statt über
|
||||
/// einen direkten Dialogaufruf — so bleibt das Ansichtsmodell ohne Fensterbezug prüfbar.
|
||||
/// einen direkten Dialogaufruf — so bleibt das Ansichtsmodell ohne Fensterbezug prüfbar.</para>
|
||||
/// </summary>
|
||||
public sealed partial class InstancePickerViewModel : ViewModelBase
|
||||
{
|
||||
private readonly InstanceDirectoryManager _directories;
|
||||
private readonly TaskCompletionSource<string?> _completion = new();
|
||||
private readonly string? _currentInstancePath;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyCanExecuteChangedFor(nameof(StartCommand))]
|
||||
private InstanceInfo? _selected;
|
||||
private InstanceChoiceViewModel? _selected;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _newInstanceName = "";
|
||||
@@ -30,16 +61,38 @@ public sealed partial class InstancePickerViewModel : ViewModelBase
|
||||
[ObservableProperty]
|
||||
private string _errorText = "";
|
||||
|
||||
public ObservableCollection<InstanceInfo> Instances { get; } = [];
|
||||
public ObservableCollection<InstanceChoiceViewModel> Instances { get; } = [];
|
||||
|
||||
/// <summary>Der gewählte Pfad, oder <c>null</c> bei Abbruch.</summary>
|
||||
public Task<string?> Result => _completion.Task;
|
||||
|
||||
public string InstancesDirectory => _directories.InstancesDirectory;
|
||||
|
||||
public InstancePickerViewModel(InstanceDirectoryManager directories)
|
||||
/// <summary>
|
||||
/// Beim Start heisst die Schaltflaeche „Starten", aus der laufenden Anwendung heraus
|
||||
/// „Wechseln" — und dann steht der Hinweis dabei, dass dafuer neu gestartet wird.
|
||||
/// </summary>
|
||||
public bool IsSwitchMode => _currentInstancePath is not null;
|
||||
|
||||
public string ConfirmLabel => IsSwitchMode ? "Wechseln" : "Starten";
|
||||
|
||||
/// <summary>Ueberschrift des Dialogs — nicht aus ConfirmLabel zusammengesetzt,
|
||||
/// sonst stuende dort „Instanz Starten".</summary>
|
||||
public string Title => IsSwitchMode ? "Instanz wechseln" : "Instanz wählen";
|
||||
|
||||
public string Hint => IsSwitchMode
|
||||
? "Jede Instanz läuft unabhängig mit eigenen Agenten und Daten. "
|
||||
+ "Wechseln startet ClawdDotNet mit der gewählten Instanz neu."
|
||||
: "Jede Instanz läuft unabhängig mit eigenen Agenten und Daten.";
|
||||
|
||||
/// <param name="currentInstancePath">
|
||||
/// Pfad der laufenden Instanz, oder <c>null</c> beim Start. Steuert Beschriftung und
|
||||
/// das Etikett „Aktiv" in der Liste.
|
||||
/// </param>
|
||||
public InstancePickerViewModel(InstanceDirectoryManager directories, string? currentInstancePath = null)
|
||||
{
|
||||
_directories = directories;
|
||||
_currentInstancePath = currentInstancePath;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
@@ -49,11 +102,17 @@ public sealed partial class InstancePickerViewModel : ViewModelBase
|
||||
Instances.Clear();
|
||||
|
||||
foreach (var instance in _directories.ListInstances())
|
||||
Instances.Add(instance);
|
||||
{
|
||||
var isCurrent = _currentInstancePath is not null
|
||||
&& string.Equals(instance.FolderPath, _currentInstancePath,
|
||||
StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
Instances.Add(new InstanceChoiceViewModel(instance, isCurrent));
|
||||
}
|
||||
|
||||
// Eine einzelne Instanz gleich vorwählen — der häufigste Fall, und ein Klick
|
||||
// weniger bei jedem Start.
|
||||
Selected ??= Instances.FirstOrDefault();
|
||||
Selected ??= Instances.FirstOrDefault(i => i.IsCurrent) ?? Instances.FirstOrDefault();
|
||||
}
|
||||
|
||||
private bool CanStart => Selected is not null;
|
||||
@@ -61,7 +120,16 @@ public sealed partial class InstancePickerViewModel : ViewModelBase
|
||||
[RelayCommand(CanExecute = nameof(CanStart))]
|
||||
private void Start() => _completion.TrySetResult(Selected!.FolderPath);
|
||||
|
||||
/// <summary>Abbruch — der Aufrufer beendet die Anwendung.</summary>
|
||||
/// <summary>Waehlt eine Zeile und bestaetigt in einem Zug — die Schaltflaeche je Zeile.</summary>
|
||||
[RelayCommand]
|
||||
private void Activate(InstanceChoiceViewModel? choice)
|
||||
{
|
||||
if (choice is null) return;
|
||||
Selected = choice;
|
||||
_completion.TrySetResult(choice.FolderPath);
|
||||
}
|
||||
|
||||
/// <summary>Abbruch — der Aufrufer beendet die Anwendung oder schliesst den Dialog.</summary>
|
||||
[RelayCommand]
|
||||
private void Cancel() => _completion.TrySetResult(null);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user