diff --git a/src/ClaudeDo.Ui/ViewModels/Islands/Detail/WorkConsoleViewModel.cs b/src/ClaudeDo.Ui/ViewModels/Islands/Detail/WorkConsoleViewModel.cs new file mode 100644 index 0000000..77e3243 --- /dev/null +++ b/src/ClaudeDo.Ui/ViewModels/Islands/Detail/WorkConsoleViewModel.cs @@ -0,0 +1,145 @@ +using System.Collections.ObjectModel; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using ClaudeDo.Ui.ViewModels.Islands; + +namespace ClaudeDo.Ui.ViewModels.Islands.Detail; + +public sealed class WorkConsoleChildOutcomeRowViewModel +{ + public required string Title { get; init; } + public bool HasRoadblock { get; init; } + public string RoadblockText { get; init; } = ""; + public required string StatusLabel { get; init; } +} + +public sealed partial class WorkConsoleViewModel : ViewModelBase +{ + // ── Tab selection ────────────────────────────────────────────── + [ObservableProperty] + [NotifyPropertyChangedFor(nameof(IsOutputTab))] + [NotifyPropertyChangedFor(nameof(IsActionsTab))] + [NotifyPropertyChangedFor(nameof(IsSessionTab))] + private string _selectedTab = "output"; + + public bool IsOutputTab => SelectedTab == "output"; + public bool IsActionsTab => SelectedTab == "actions"; + public bool IsSessionTab => SelectedTab == "session"; + + [RelayCommand] + private void SelectTab(string tab) => SelectedTab = tab; + + // ── Info header ──────────────────────────────────────────────── + [ObservableProperty] private string _model = ""; + + [ObservableProperty] + [NotifyPropertyChangedFor(nameof(TurnsText))] + private int _turns; + + [ObservableProperty] + [NotifyPropertyChangedFor(nameof(DiffAddText))] + private int _diffAdditions; + + [ObservableProperty] + [NotifyPropertyChangedFor(nameof(DiffDelText))] + private int _diffDeletions; + + [ObservableProperty] + [NotifyPropertyChangedFor(nameof(ShowRoadblock))] + private bool _isRunning; + + [ObservableProperty] + [NotifyPropertyChangedFor(nameof(ShowRoadblock))] + private bool _isDone; + + [ObservableProperty] + [NotifyPropertyChangedFor(nameof(ShowRoadblock))] + private bool _isFailed; + + [ObservableProperty] + [NotifyPropertyChangedFor(nameof(ShowRoadblock))] + private bool _isCancelled; + + [ObservableProperty] private string _sessionLabel = ""; + + public string TurnsText => $"{Turns} turns"; + public string DiffAddText => $"+{DiffAdditions}"; + public string DiffDelText => $"-{DiffDeletions}"; + + // ── Roadblock ────────────────────────────────────────────────── + public bool ShowRoadblock => IsFailed || IsCancelled; + + [ObservableProperty] private string _roadblockMessage = ""; + [ObservableProperty] private bool _showContinue; + [ObservableProperty] private bool _showResetAndRetry; + + [RelayCommand] private void Continue() { } + [RelayCommand] private void ResetAndRetry() { } + + // ── Actions tab ──────────────────────────────────────────────── + public ObservableCollection MergeTargetBranches { get; } = new(); + + [ObservableProperty] private string? _selectedMergeTarget; + [ObservableProperty] private bool _canMergeAll; + [ObservableProperty] private string _mergeAllDisabledReason = ""; + [ObservableProperty] private string? _mergeAllError; + + [RelayCommand] private void OpenDiff() { } + [RelayCommand] private void OpenWorktree() { } + [RelayCommand] private void ReviewCombinedDiff() { } + [RelayCommand] private void MergeAll() { } + + // ── Session tab ──────────────────────────────────────────────── + [ObservableProperty] private bool _isWaitingForReview; + [ObservableProperty] private string _reviewFeedback = ""; + + public ObservableCollection ChildOutcomes { get; } = new(); + public bool HasChildOutcomes => ChildOutcomes.Count > 0; + + [RelayCommand] private void ApproveReview() { } + [RelayCommand] private void RejectReview() { } + [RelayCommand] private void ParkReview() { } + [RelayCommand] private void CancelReview() { } + + public ObservableCollection Log { get; } = new(); + + public WorkConsoleViewModel() + { + ChildOutcomes.CollectionChanged += (_, _) => OnPropertyChanged(nameof(HasChildOutcomes)); + + // ── Design-time sample data ──────────────────────────────── + _model = "sonnet"; + _turns = 40; + _diffAdditions = 84; + _diffDeletions = 31; + _isRunning = true; + _sessionLabel = "feat/work-console"; + + MergeTargetBranches.Add("main"); + MergeTargetBranches.Add("develop"); + _selectedMergeTarget = "main"; + _canMergeAll = true; + + Log.Add(new LogLineViewModel { Kind = LogKind.Sys, Text = "Starting claude session…" }); + Log.Add(new LogLineViewModel { Kind = LogKind.Claude, Text = "Reading DetailsIslandView.axaml to understand existing layout." }); + Log.Add(new LogLineViewModel { Kind = LogKind.Tool, Text = "Read(src/ClaudeDo.Ui/Views/Islands/DetailsIslandView.axaml)" }); + Log.Add(new LogLineViewModel { Kind = LogKind.Claude, Text = "Building WorkConsole component with three tabs." }); + Log.Add(new LogLineViewModel { Kind = LogKind.Stdout, Text = "dotnet build succeeded — 0 error(s)" }); + + ChildOutcomes.Add(new WorkConsoleChildOutcomeRowViewModel + { + Title = "Add WorkConsole XAML", + StatusLabel = "Done" + }); + ChildOutcomes.Add(new WorkConsoleChildOutcomeRowViewModel + { + Title = "Wire ViewModel bindings", + HasRoadblock = true, + RoadblockText = "Missing token", + StatusLabel = "Failed" + }); + + // To preview roadblock state: _isFailed = true; _roadblockMessage = "Session ended unexpectedly"; _showResetAndRetry = true; _isRunning = false; + // To preview review state: _isWaitingForReview = true; _isDone = false; _isRunning = false; + } +} diff --git a/src/ClaudeDo.Ui/Views/Islands/Detail/WorkConsole.axaml b/src/ClaudeDo.Ui/Views/Islands/Detail/WorkConsole.axaml new file mode 100644 index 0000000..3399b01 --- /dev/null +++ b/src/ClaudeDo.Ui/Views/Islands/Detail/WorkConsole.axaml @@ -0,0 +1,249 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +