From 111dd0fb0d4c457c192168b272b2aacb3b96b98d Mon Sep 17 00:00:00 2001 From: mika kuns Date: Fri, 21 Aug 2026 15:25:04 +0200 Subject: [PATCH] =?UTF-8?q?feat(ui):=20Erststart-Banner=20und=20Textkette?= =?UTF-8?q?=20Repo=E2=86=92Task=E2=86=92Queue=E2=86=92Review=20(UX-Struktu?= =?UTF-8?q?r=20C)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HasNoLinkedRepo on ListsIslandViewModel drives a dismiss-less banner under the Lists-Island header when no User list has a linked repo; recomputed on load and after list CRUD / list-settings save. Sharpens the #192 empty-state texts into one readable chain (banner → no-repo list → repo-linked list) and adds a line to the WorkConsole review gate spelling out that Approve also merges the whole unit. --- src/ClaudeDo.Localization/locales/de.json | 9 +- src/ClaudeDo.Localization/locales/en.json | 9 +- .../Islands/ListsIslandViewModel.cs | 12 ++ .../Views/Islands/Detail/WorkConsole.axaml | 17 +- .../Views/Islands/ListsIslandView.axaml | 18 ++ .../ListsIslandHasNoLinkedRepoTests.cs | 192 ++++++++++++++++++ 6 files changed, 244 insertions(+), 13 deletions(-) create mode 100644 tests/ClaudeDo.Ui.Tests/ViewModels/ListsIslandHasNoLinkedRepoTests.cs diff --git a/src/ClaudeDo.Localization/locales/de.json b/src/ClaudeDo.Localization/locales/de.json index 458872dc..2d03796d 100644 --- a/src/ClaudeDo.Localization/locales/de.json +++ b/src/ClaudeDo.Localization/locales/de.json @@ -221,8 +221,8 @@ "rerun": "Erneut ausführen", "refineTip": "Aufgabe mit Claude verfeinern", "refiningTip": "Claude verfeinert diese Aufgabe…", - "emptyHint": "Noch keine Aufgaben. Oben eine hinzufügen oder in die Warteschlange einreihen, wenn du bereit bist.", - "emptyHintNoWorkingDir": "Verknüpfe ein Repo in den Listeneinstellungen, um Warteschlange, „Claude machen lassen" und die Schnell-Sitzung zu aktivieren." + "emptyHint": "Noch keine Aufgaben. Lege eine an und wähle per Rechtsklick „In Warteschlange einreihen" — Claude bearbeitet sie in einem eigenen Worktree.", + "emptyHintNoWorkingDir": "Diese Liste hat kein Repo — in den Listeneinstellungen verknüpfen, um die Warteschlange zu aktivieren." }, "lists": { "heading": "Listen", @@ -237,7 +237,9 @@ "contextOpenFindings": "Findings-Ordner öffnen", "contextSettings": "Einstellungen…", "newList": "Neue Liste", - "addReposTip": "Repos als Listen hinzufügen" + "addReposTip": "Repos als Listen hinzufügen", + "noRepoBannerText": "Noch kein Repo verknüpft. ClaudeDo führt Tasks in einem Git-Repo aus.", + "noRepoBannerButton": "Repo importieren" }, "details": { "deleteTaskTip": "Aufgabe löschen", @@ -309,6 +311,7 @@ "reviewContinueTip": "Dieses Feedback senden und die Aufgabe erneut ausführen", "reviewResetTip": "Alle Änderungen verwerfen und die Aufgabe auf Leerlauf zurücksetzen", "mergeDrainHint": "Merge zieht Subtasks ein — Abbrechen entsperrt sich danach", + "approveMergesUnitHint": "Approve mergt das gleich in den Zielbranch — danach folgt kein separater Merge-Schritt.", "continueNoSessionTip": "Setzt den letzten Lauf fort — benötigt eine vorherige Session", "resetAndRetryInteractiveTip": "Interaktive Sitzung ist offen — erst schließen", "reviewFeedbackPlaceholder": "Feedback für nächsten Lauf" diff --git a/src/ClaudeDo.Localization/locales/en.json b/src/ClaudeDo.Localization/locales/en.json index 7d2dd51e..c92cf11b 100644 --- a/src/ClaudeDo.Localization/locales/en.json +++ b/src/ClaudeDo.Localization/locales/en.json @@ -221,8 +221,8 @@ "rerun": "Re-run", "refineTip": "Refine this task with Claude", "refiningTip": "Claude is refining this task…", - "emptyHint": "No tasks yet. Add one above, or send it to the queue once you're ready.", - "emptyHintNoWorkingDir": "Link a repo in List Settings to enable the queue, Let Claude handle it, and Quick session." + "emptyHint": "No tasks yet. Add one, then right-click it and choose \"Send to queue\" — Claude works it in its own worktree.", + "emptyHintNoWorkingDir": "This list has no repo yet — link one in List Settings to enable the queue." }, "lists": { "heading": "Lists", @@ -237,7 +237,9 @@ "contextOpenFindings": "Open findings folder", "contextSettings": "Settings…", "newList": "New list", - "addReposTip": "Add repos as lists" + "addReposTip": "Add repos as lists", + "noRepoBannerText": "No repo linked yet. ClaudeDo runs tasks in a git repo.", + "noRepoBannerButton": "Import repo" }, "details": { "deleteTaskTip": "Delete task", @@ -310,6 +312,7 @@ "reviewResetTip": "Discard all changes and reset the task to Idle", "reviewFeedbackPlaceholder": "Feedback for next run", "mergeDrainHint": "Merge is draining subtasks — Cancel unlocks once it finishes", + "approveMergesUnitHint": "Approve also merges this into the target branch right away — there's no separate merge step after it.", "continueNoSessionTip": "Resumes the last run — needs a previous session to continue", "resetAndRetryInteractiveTip": "Interactive session is open — close it first" }, diff --git a/src/ClaudeDo.Ui/ViewModels/Islands/ListsIslandViewModel.cs b/src/ClaudeDo.Ui/ViewModels/Islands/ListsIslandViewModel.cs index 414e7bfd..ebeba0de 100644 --- a/src/ClaudeDo.Ui/ViewModels/Islands/ListsIslandViewModel.cs +++ b/src/ClaudeDo.Ui/ViewModels/Islands/ListsIslandViewModel.cs @@ -186,6 +186,14 @@ public sealed partial class ListsIslandViewModel : ViewModelBase, IDisposable [ObservableProperty] private string _searchText = ""; [ObservableProperty] private ListNavItemViewModel? _selectedList; + /// True whenever no User list has a linked WorkingDir — drives the no-repo + /// banner. Smart/Virtual lists never count. Recomputed after every load and every + /// list CRUD / list-settings save; never persisted, no dismiss state. + [ObservableProperty] private bool _hasNoLinkedRepo = true; + + private void RecomputeHasNoLinkedRepo() => + HasNoLinkedRepo = UserLists.All(r => string.IsNullOrWhiteSpace(r.WorkingDir)); + public string UserName { get; } = Environment.UserName; public string MachineName { get; } = Environment.MachineName; public string MachineNameLocal => Loc.T("vm.lists.localSuffix", MachineName); @@ -291,6 +299,7 @@ public sealed partial class ListsIslandViewModel : ViewModelBase, IDisposable } finally { OperationTiming.Shared.Record("db", "ListsIsland.LoadAsync", sw.Elapsed, ok); } + RecomputeHasNoLinkedRepo(); await RefreshCountsAsync(ct); SelectedList = Items.FirstOrDefault(); } @@ -372,6 +381,7 @@ public sealed partial class ListsIslandViewModel : ViewModelBase, IDisposable Items.Add(item); UserLists.Add(item); SelectedList = item; + RecomputeHasNoLinkedRepo(); if (Dialogs is not null && _services is not null) { @@ -474,6 +484,7 @@ public sealed partial class ListsIslandViewModel : ViewModelBase, IDisposable row.DefaultCommitType = entity.DefaultCommitType; row.IsManual = entity.IsManual; row.FindingsTracked = entity.FindingsTracked; + RecomputeHasNoLinkedRepo(); } catch { /* best-effort refresh */ } } @@ -505,5 +516,6 @@ public sealed partial class ListsIslandViewModel : ViewModelBase, IDisposable UserLists.Insert(insertAt, item); Items.Insert(SmartLists.Count + insertAt, item); + RecomputeHasNoLinkedRepo(); } } diff --git a/src/ClaudeDo.Ui/Views/Islands/Detail/WorkConsole.axaml b/src/ClaudeDo.Ui/Views/Islands/Detail/WorkConsole.axaml index 572aee89..3af8552c 100644 --- a/src/ClaudeDo.Ui/Views/Islands/Detail/WorkConsole.axaml +++ b/src/ClaudeDo.Ui/Views/Islands/Detail/WorkConsole.axaml @@ -371,13 +371,16 @@ IsVisible="{Binding Merge.ShowMergeSection}" /> - - - + + + + + + + + + +