From b997af442316b014e2323060d3779b2a8a38f6b3 Mon Sep 17 00:00:00 2001 From: mika kuns Date: Fri, 21 Aug 2026 10:34:46 +0200 Subject: [PATCH] fix(ui): notify IsTasksEmptyRepoHintVisible on every list switch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IsTasksEmptyRepoHintVisible reads _currentList?.Kind directly, but Kind isn't itself observed — the NotifyPropertyChangedFor chain only fires when IsLetClaudeVisible's value actually changes. Switching from a Smart list to an empty User list without a WorkingDir changes Kind while IsLetClaudeVisible (and Has*) stay false in both, so the hint never notified and stayed stale. --- .../Islands/TasksIslandViewModel.cs | 7 +++++ .../ViewModels/TasksIslandEmptyStateTests.cs | 27 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/src/ClaudeDo.Ui/ViewModels/Islands/TasksIslandViewModel.cs b/src/ClaudeDo.Ui/ViewModels/Islands/TasksIslandViewModel.cs index e1625721..a77150ed 100644 --- a/src/ClaudeDo.Ui/ViewModels/Islands/TasksIslandViewModel.cs +++ b/src/ClaudeDo.Ui/ViewModels/Islands/TasksIslandViewModel.cs @@ -387,6 +387,13 @@ public sealed partial class TasksIslandViewModel : ViewModelBase, IDisposable if (_currentList is not null) _currentList.PropertyChanged += OnCurrentListPropertyChanged; + // IsTasksEmptyRepoHintVisible reads _currentList?.Kind directly, but Kind isn't itself an + // observed property — the [NotifyPropertyChangedFor] chain only fires when IsLetClaudeVisible's + // *value* changes. Switching between two lists that both resolve IsLetClaudeVisible to the + // same bool (e.g. a Smart list -> an empty User list without a WorkingDir) changes Kind + // without ever notifying, leaving the hint stale. Force it explicitly on every list switch. + OnPropertyChanged(nameof(IsTasksEmptyRepoHintVisible)); + Items.Clear(); Rows.Clear(); HasOverdue = false; diff --git a/tests/ClaudeDo.Ui.Tests/ViewModels/TasksIslandEmptyStateTests.cs b/tests/ClaudeDo.Ui.Tests/ViewModels/TasksIslandEmptyStateTests.cs index 6ee7d48c..e6023a2c 100644 --- a/tests/ClaudeDo.Ui.Tests/ViewModels/TasksIslandEmptyStateTests.cs +++ b/tests/ClaudeDo.Ui.Tests/ViewModels/TasksIslandEmptyStateTests.cs @@ -109,4 +109,31 @@ public class TasksIslandEmptyStateTests : IDisposable Assert.False(vm.IsTasksEmptyHintVisible); Assert.False(vm.IsTasksEmptyRepoHintVisible); } + + // Regression: switching from an empty Smart list (never eligible for the repo hint) to an + // empty User list without a WorkingDir changes the correct value of + // IsTasksEmptyRepoHintVisible from false to true, but IsLetClaudeVisible stays false in both + // cases (Smart lists are never User) and HasOverdue/HasOpen/HasCompleted stay false in both + // cases (both lists are empty) — so the [NotifyPropertyChangedFor] chain alone never fires. + [Fact] + public async Task IsTasksEmptyRepoHintVisible_notifies_on_switch_from_smart_list_to_empty_user_list_without_working_dir() + { + await using var db = NewContext(); + db.Lists.Add(new ListEntity { Id = "L4", Name = "Work", CreatedAt = DateTime.UtcNow }); + await db.SaveChangesAsync(); + + var vm = NewVm(); + vm.LoadForList(new ListNavItemViewModel { Id = "smart:important", Name = "Important", Kind = ListKind.Smart, WorkingDir = null }); + await vm.LoadTask!; + Assert.False(vm.IsTasksEmptyRepoHintVisible); + + var raisedProperties = new List(); + vm.PropertyChanged += (_, e) => raisedProperties.Add(e.PropertyName); + + vm.LoadForList(new ListNavItemViewModel { Id = "user:L4", Name = "Work", Kind = ListKind.User, WorkingDir = null }); + await vm.LoadTask!; + + Assert.Contains(nameof(TasksIslandViewModel.IsTasksEmptyRepoHintVisible), raisedProperties); + Assert.True(vm.IsTasksEmptyRepoHintVisible); + } }