From 5784dbee949ac482740afd07ce38582ee54feb29 Mon Sep 17 00:00:00 2001 From: Mika Kuns Date: Wed, 22 Apr 2026 13:27:05 +0200 Subject: [PATCH] feat(ui): open ListSettingsModal via context menu and gear button Co-Authored-By: Claude Sonnet 4.6 --- src/ClaudeDo.App/Program.cs | 3 +- .../Islands/ListNavItemViewModel.cs | 2 + .../Islands/ListsIslandViewModel.cs | 40 ++++++++++++++++++- .../Views/Islands/ListsIslandView.axaml | 25 ++++++++++-- .../Views/Islands/ListsIslandView.axaml.cs | 8 ++++ 5 files changed, 73 insertions(+), 5 deletions(-) diff --git a/src/ClaudeDo.App/Program.cs b/src/ClaudeDo.App/Program.cs index 16ff568..e82cbc8 100644 --- a/src/ClaudeDo.App/Program.cs +++ b/src/ClaudeDo.App/Program.cs @@ -85,7 +85,8 @@ sealed class Program sc.AddSingleton(sp => new ListsIslandViewModel( sp.GetRequiredService>(), - sp)); + sp, + sp.GetRequiredService())); sc.AddSingleton(sp => new TasksIslandViewModel(sp.GetRequiredService>())); sc.AddSingleton(sp => diff --git a/src/ClaudeDo.Ui/ViewModels/Islands/ListNavItemViewModel.cs b/src/ClaudeDo.Ui/ViewModels/Islands/ListNavItemViewModel.cs index f6969c1..082ec33 100644 --- a/src/ClaudeDo.Ui/ViewModels/Islands/ListNavItemViewModel.cs +++ b/src/ClaudeDo.Ui/ViewModels/Islands/ListNavItemViewModel.cs @@ -9,6 +9,8 @@ public sealed partial class ListNavItemViewModel : ViewModelBase public required ListKind Kind { get; init; } [ObservableProperty] private int _count; [ObservableProperty] private bool _isActive; + [ObservableProperty] private string? _workingDir; + [ObservableProperty] private string _defaultCommitType = "chore"; public string? IconKey { get; init; } public string? DotColorKey { get; init; } } diff --git a/src/ClaudeDo.Ui/ViewModels/Islands/ListsIslandViewModel.cs b/src/ClaudeDo.Ui/ViewModels/Islands/ListsIslandViewModel.cs index 1de2f36..aaa5b41 100644 --- a/src/ClaudeDo.Ui/ViewModels/Islands/ListsIslandViewModel.cs +++ b/src/ClaudeDo.Ui/ViewModels/Islands/ListsIslandViewModel.cs @@ -3,6 +3,7 @@ using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using ClaudeDo.Data; using ClaudeDo.Data.Repositories; +using ClaudeDo.Ui.Services; using ClaudeDo.Ui.ViewModels.Modals; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; @@ -15,12 +16,14 @@ public sealed partial class ListsIslandViewModel : ViewModelBase { private readonly IDbContextFactory _dbFactory; private readonly IServiceProvider? _services; + private readonly WorkerClient? _worker; public event EventHandler? SelectionChanged; public event EventHandler? FocusSearchRequested; public void RequestFocusSearch() => FocusSearchRequested?.Invoke(this, EventArgs.Empty); public Func? ShowSettingsModal { get; set; } + public Func? ShowListSettingsModal { get; set; } [RelayCommand] private async Task OpenSettings() @@ -31,6 +34,16 @@ public sealed partial class ListsIslandViewModel : ViewModelBase await ShowSettingsModal(settingsVm); } + [RelayCommand] + private async System.Threading.Tasks.Task OpenListSettingsAsync(ListNavItemViewModel? row) + { + if (row is null || ShowListSettingsModal is null || _services is null) return; + var vm = _services.GetRequiredService(); + await vm.LoadAsync(row.Id, row.Name, row.WorkingDir, row.DefaultCommitType); + await ShowListSettingsModal(vm); + await RefreshRowAsync(row.Id); + } + public ObservableCollection Items { get; } = new(); public ObservableCollection SmartLists { get; } = new(); public ObservableCollection UserLists { get; } = new(); @@ -42,16 +55,20 @@ public sealed partial class ListsIslandViewModel : ViewModelBase public string MachineName { get; } = Environment.MachineName; public string UserInitials { get; } - public ListsIslandViewModel(IDbContextFactory dbFactory, IServiceProvider? services = null) + public ListsIslandViewModel(IDbContextFactory dbFactory, IServiceProvider? services = null, WorkerClient? worker = null) { _dbFactory = dbFactory; _services = services; + _worker = worker; var parts = Environment.UserName.Split('.', '_', '-', ' '); UserInitials = parts.Length >= 2 ? $"{parts[0][0]}{parts[1][0]}".ToUpperInvariant() : Environment.UserName.Length >= 2 ? Environment.UserName[..2].ToUpperInvariant() : Environment.UserName.ToUpperInvariant(); + + if (_worker is not null) + _worker.ListUpdatedEvent += id => _ = RefreshRowAsync(id); } public async Task LoadAsync(CancellationToken ct = default) @@ -85,6 +102,8 @@ public sealed partial class ListsIslandViewModel : ViewModelBase Kind = ListKind.User, IconKey = "Folder", DotColorKey = dotColors[idx % dotColors.Length], + WorkingDir = l.WorkingDir, + DefaultCommitType = l.DefaultCommitType, }; Items.Add(item); UserLists.Add(item); @@ -109,4 +128,23 @@ public sealed partial class ListsIslandViewModel : ViewModelBase foreach (var i in Items) i.IsActive = ReferenceEquals(i, value); SelectionChanged?.Invoke(this, EventArgs.Empty); } + + private async System.Threading.Tasks.Task RefreshRowAsync(string rowId) + { + try + { + var rawId = rowId.StartsWith("user:") ? rowId["user:".Length..] : rowId; + var row = UserLists.FirstOrDefault(r => r.Id == rowId); + if (row is null) return; + + await using var ctx = await _dbFactory.CreateDbContextAsync(); + var lists = new ListRepository(ctx); + var entity = await lists.GetByIdAsync(rawId); + if (entity is null) return; + + row.WorkingDir = entity.WorkingDir; + row.DefaultCommitType = entity.DefaultCommitType; + } + catch { /* best-effort refresh */ } + } } diff --git a/src/ClaudeDo.Ui/Views/Islands/ListsIslandView.axaml b/src/ClaudeDo.Ui/Views/Islands/ListsIslandView.axaml index 963e174..c82fffb 100644 --- a/src/ClaudeDo.Ui/Views/Islands/ListsIslandView.axaml +++ b/src/ClaudeDo.Ui/Views/Islands/ListsIslandView.axaml @@ -66,7 +66,7 @@