diff --git a/docs/superpowers/plans/2026-08-20-ux-struktur.md b/docs/superpowers/plans/2026-08-20-ux-struktur.md new file mode 100644 index 00000000..ac11ea58 --- /dev/null +++ b/docs/superpowers/plans/2026-08-20-ux-struktur.md @@ -0,0 +1,122 @@ +# UX-Struktur — Vorgaben für die Umsetzung + +**Design:** `docs/superpowers/specs/2026-08-20-ux-struktur-design.md`. Dort stehen die +Entscheidungen und Belege; dieses Dokument wiederholt sie nicht, es schneidet die Arbeit. + +**Ausführungsmodell: eine strikte Kette.** Alle drei Pakete ändern `locales/en.json` und +`locales/de.json` — die überlappen immer. Deshalb läuft nichts parallel. + +``` +#189 → #190 → #191 → #192 (mechanische Audit-Fixes, bereits delegiert) + │ + └── A Task-Zeile + Kontextmenü + │ + └── B Settings-Sidebar + │ + └── C Erststart-Banner + Textkette +``` + +Jedes Paket hängt per `dependsOn` am Vorgänger. Der Picker holt es erst, wenn der Vorgänger +**Done** (also gemergt) ist. + +## Datei-Eigentum (bindend) + +| Paket | Besitzt | Darf **nicht** anfassen | +|---|---|---| +| **A** | `Ui/Views/Islands/TaskRowView.axaml(.cs)`, `Ui/ViewModels/Islands/TaskRowViewModel.cs`, `Ui/Views/Islands/Detail/TaskHeaderBar.axaml`, `locales/*` | `WorkConsole.axaml`, Settings-Dateien, `ListsIsland*` | +| **B** | `Ui/Views/Modals/SettingsModalView.axaml(.cs)`, `Ui/ViewModels/Modals/SettingsModalViewModel.cs`, `Ui/ViewModels/Modals/Settings/*`, `locales/*` | alles im Islands-Ordner | +| **C** | `Ui/Views/Islands/ListsIslandView.axaml(.cs)`, `Ui/ViewModels/Islands/ListsIslandViewModel.cs`, `Ui/Views/Islands/Detail/WorkConsole.axaml` (nur die eine Approve-Gate-Zeile), `Ui/Views/Islands/TasksIslandView.axaml` (nur Empty-State-Texte aus #192 nachschärfen), `locales/*` | `TaskRowView*`, Settings-Dateien | + +Alle drei dürfen `tests/ClaudeDo.Ui.Tests` erweitern — aber nur eigene neue Testdateien bzw. +eigene neue Testmethoden anlegen, keine fremden umschreiben. + +## Vorgaben für alle drei Pakete + +- **Modell:** `sonnet`. **`maxTurns` explizit 200** — `model_presets` ist NULL, sonst gibt es + 30 Turns und „exited with code 1 and no result". +- **Bauen** (`.slnx` scheitert auf .NET 8, laufender Worker sperrt `Debug`): + ``` + dotnet build src/ClaudeDo.App/ClaudeDo.App.csproj -c Release + dotnet test tests/ClaudeDo.Ui.Tests/ClaudeDo.Ui.Tests.csproj -c Release + dotnet test tests/ClaudeDo.Localization.Tests/ClaudeDo.Localization.Tests.csproj -c Release + ``` +- **Nur eigene Dateien stagen** (`git commit -- `), nie `git add -A` — der `main`-Checkout + ist mit parallelen Sessions geteilt. +- **Keine Funktion still entfernen.** Wo etwas aus einer Oberfläche verschwindet, im + Abschlussbericht benennen, wo es jetzt liegt. +- **Locale-Parity** ist Testsache (Localization.Tests) — beide Dateien im gleichen Commit. +- **Visuelle Verifikation im Abschlussbericht als offen markieren.** Mika macht den visuellen + Pass; kein Task darf behaupten, die UI sei geprüft. + +--- + +## Paket A — Task-Zeile + Kontextmenü + +Themen 1 und 3 des Designs zusammen, weil sie dieselben drei Dateien anfassen. + +- [ ] **A1 Kontextmenü umbauen.** Gruppe 1 (Send to queue, Remove from queue, Cancel execution, + Open quick session, Refine task) immer sichtbar, bei nicht erfüllter Bedingung + `IsEnabled=false` + Grund. Untermenüs „Mark as", „Planning", „Schedule" nach der Tabelle im + Design; Untermenü-Kopf disabled wenn leer. Der „Delete task…"-Eintrag aus #191 bleibt als + abgesetzte Gruppe unten. `MakeItem` bekommt einen `reason`-Parameter. +- [ ] **A2 Disabled-Gründe am VM.** `SendToQueueDisabledReason`, `CancelDisabledReason`, + `QuickSessionDisabledReason`, `RefineDisabledReason`, `PlanningDisabledReason` (`string?`) + auf `TaskRowViewModel`, mit Change-Notification an den passenden Stellen. Unit-Tests pro + Zustand. +- [ ] **A3 Tooltip-Fähigkeit verifizieren.** Headless prüfen, ob Avalonia 12 einen `ToolTip` auf + einem `IsEnabled=false` MenuItem anzeigt. Ja → Tooltip. Nein → Grund als Suffix im Header. + Das Ergebnis gehört in den Abschlussbericht (es ist eine Projekt-Erkenntnis, kein Detail). +- [ ] **A4 Hover-/Selektions-Aktionen.** `IsHovered` + `ShowRowActions => IsHovered || IsSelected` + am `TaskRowViewModel`; `PointerEntered`/`PointerExited` in `TaskRowView.axaml.cs`. + Refine-Button, ungesetzter Star und Dequeue-X werden damit AND-verknüpft; `IsRefining`-Spinner + bleibt ausgenommen. Grid-Spalten unverändert lassen, damit die Zeile nicht springt. +- [ ] **A5 Branch verlagern.** Branch-Chip aus `TaskRowView.axaml` entfernen und den Branch-Namen + in `TaskHeaderBar.axaml` als Meta-Zeile aufnehmen (er steht bisher nirgends im Detail-Pane). + Ohne A5 darf der Chip nicht entfernt werden. + +**Fertig, wenn:** Build grün, Ui.Tests + Localization.Tests grün, und der Bericht sagt für jedes +verschwundene Zeilen-Element, wo es jetzt erreichbar ist. + +--- + +## Paket B — Settings-Sidebar + +- [ ] **B1 Host umbauen.** TabStrip des bestehenden `TabControl` ausblenden, links eine + Sidebar-`ListBox` mit Gruppen-Labels BASIS/ERWEITERT, die `SelectedIndex` bindet. + Panel-Inhalte bleiben, wo sie sind. Fensterbreite 580 → 700. + `SettingsCategory(Key, Label, Group, IsVisible, RequiresRepo)` + `Categories` + + `SelectedCategory` am `SettingsModalViewModel`. +- [ ] **B2 General aufteilen.** „Allgemein" (Sprache, Accent, Default-Instructions) und + „Ausführung" (Model, Permission, Model-Presets, MaxTurns-Ceiling, Parallelität, Usage-Gate). + Kategorie „Berichte" neu mit Standup-Wochentag + Report-Excluded-Paths. Reihenfolge der + Kategorien: Allgemein, Ausführung, Prime Claude | Worktrees, Dateien & Prompts, + Session Skills, Berichte, Online Inbox. +- [ ] **B3 Session Skills zusammenlegen.** Checkbox-Liste aus General entfernen; in der Kategorie + „Session Skills" pro installiertem Skill eine Zeile mit Checkbox (global aktiv) + + Update/Remove, darunter das Install-Feld. **Speichern/Laden der Auswahl muss nachweislich + unverändert funktionieren** — Test dafür ist Pflicht, das ist die einzige echte + Regressionsstelle des Pakets. +- [ ] **B4 Repo-Hinweis.** `HasLinkedRepo` am `SettingsModalViewModel` (keine Liste mit + `WorkingDir` → false). Hinweisstreifen oben in Worktrees, Prime Claude, Session Skills und + Berichte: „Wirkt erst mit verknüpftem Repo" + Link, der den Repo-Import öffnet. + +**Fertig, wenn:** Build grün, Tests grün, jede der acht Kategorien einmal aufrufbar, und Save → +Reopen zeigt alle Werte unverändert (inkl. Skill-Auswahl). + +--- + +## Paket C — Erststart-Banner + Textkette + +- [ ] **C1 Banner.** `HasNoLinkedRepo` am `ListsIslandViewModel` (true, solange keine User-Liste + ein `WorkingDir` hat; neu berechnet beim Listen-Load und nach List-CRUD/List-Settings-Save). + Banner unter dem Lists-Island-Header, optisch wie das Update-Banner des Shells, Button ruft + `OpenRepoImportCommand`. Kein Dismiss. +- [ ] **C2 Textkette abstimmen.** Die Empty-State-Texte aus #192 so nachschärfen, dass Banner → + „Liste ohne Repo" → „Liste mit Repo, aber leer" als ein Weg lesbar sind; der letzte nennt + „Send to queue" und den Worktree. +- [ ] **C3 Review-Zeile.** Am Approve-Gate-Hinweis in `WorkConsole.axaml` (den #190 baut) eine + Zeile ergänzen, die sagt, dass Approve gleichzeitig das Mergen der ganzen Einheit ist. + Nur diese eine Stelle in der Datei anfassen. + +**Fertig, wenn:** Build grün, Tests grün, und die vier Texte im Bericht als zusammenhängende +Kette zitiert sind (damit Mika sie ohne App lesen kann). diff --git a/docs/superpowers/specs/2026-08-20-ux-struktur-design.md b/docs/superpowers/specs/2026-08-20-ux-struktur-design.md new file mode 100644 index 00000000..a615e775 --- /dev/null +++ b/docs/superpowers/specs/2026-08-20-ux-struktur-design.md @@ -0,0 +1,227 @@ +# UX-Struktur: Kontextmenü, Settings, Task-Zeile, Erststart — Design + +**Stand:** 2026-08-20 · Codestand `f9a8ed7` · Freigegeben von Mika im Brainstorming + +Die vier strukturellen Themen aus dem UX-Audit vom 2026-08-20. Die *mechanischen* Befunde +desselben Audits laufen bereits als Tasks **#189** (Silent No-Ops → Footer-Fehler), **#190** +(Precondition-Hinweise), **#191** (Aktions-/Bestätigungs-Konsistenz), **#192** (Empty States). +Dieses Design setzt auf deren Ergebnis auf und wiederholt es nicht. + +**Was hier nicht drinsteht:** die Audit-Befunde selbst (Memory `ux_audit_2026_08_20.md`) und die +Mechanik von Review/Merge (`docs/explore-notes/review-merge.md`). + +--- + +## Gemeinsame Randbedingungen + +- Alle drei Umsetzungs-Tasks laufen **nach #192**. Sie fassen dieselben Views an, und #189–#192 + ändern Locale-Dateien, `TaskRowView.axaml.cs`, `DetailsIslandViewModel` und die Empty-State-Keys. +- **Keine Funktion verschwindet still.** Wo etwas aus einer Oberfläche verschwindet, muss dieses + Design sagen, wo es stattdessen erreichbar ist — und der Task muss das belegen. +- Neue Texte immer als Keys in `locales/en.json` **und** `locales/de.json` (Localization.Tests + erzwingt Parity). +- Visuelle Verifikation macht Mika. Jeder Task markiert sie im Abschlussbericht als offen. + +--- + +## 1. Task-Kontextmenü restrukturieren + +**Problem.** `TaskRowView.axaml.cs` baut ~18 flache MenuItems mit vier Separatoren. Kernaktionen +(Queue rein/raus, Abbrechen) stehen visuell gleichwertig neben Planning-Session-Lifecycle und +My-Day-Verwaltung. Zusätzlich werden Einträge bei nicht erfüllter Bedingung komplett ausgeblendet +— das Menü hat je Zustand ein anderes Layout, und der User erfährt nie, dass eine Aktion +existiert. + +**Entscheidung: gruppieren und verschachteln.** Das Menü bleibt die vollständige Action-Surface +für einen Task (keine Verlagerung ins Detail-Pane — das ist selbst schon dicht). + +``` +Send to queue [disabled + Grund] +Remove from queue [disabled + Grund] +Cancel execution [disabled + Grund] +Open quick session [disabled + Grund] +Refine task [disabled + Grund] ← neu (siehe Thema 3) +───────────────────────────── +Mark as ▸ Done · Cancelled · ─ · Mark manual / Mark as Claude task +Planning ▸ Open · Resume · Finalize · Discard +Schedule ▸ Schedule for… · Clear schedule · ─ · Add to My Day / Remove from My Day +───────────────────────────── +Delete task… (aus #191, bleibt unten abgesetzt) +``` + +**Sichtbarkeitsregeln.** + +| Ebene | Regel | +|---|---| +| Gruppe 1 (5 Einträge) | **Immer sichtbar**, Position fix. Bedingung nicht erfüllt → `IsEnabled=false` + Grund. | +| Untermenü-Einträge | Heutige Ausblende-Logik bleibt — die Auswahl ist dort exklusiv (Manual ⇄ Claude-Task, Add ⇄ Remove My Day). | +| Untermenü-Kopf | `IsEnabled=false`, wenn er leer wäre (z.B. „Planning" auf einem Manual-Task). | +| Delete | Wie #191 es baut, nur eigene Gruppe unten. | + +**Grund-Anzeige.** Primär `ToolTip.Tip` am disabled MenuItem. **Verifikationspflicht:** Der Task +muss headless prüfen, ob Avalonia 12 Tooltips auf `IsEnabled=false` MenuItems überhaupt anzeigt. +Wenn nicht → Grund als Suffix im Header (`"Send to queue — kein Repo verknüpft"`). Kein +stillschweigendes Weglassen; wenn beides nicht geht, muss der Task es als Befund melden. + +**Wo die Gründe herkommen.** Neue berechnete Properties auf `TaskRowViewModel` neben den +bestehenden `CanX`, z.B. `SendToQueueDisabledReason`, `CancelDisabledReason`, +`QuickSessionDisabledReason`, `RefineDisabledReason`, `PlanningDisabledReason` (jeweils `string?`, +`null` = kein Grund nötig). Keine Bedingungslogik in der View. + +**Struktur im Code.** Das Menü wird weiterhin erst beim Öffnen gebaut (kein Rendering-Overhead +pro Zeile). `MakeItem` bekommt einen optionalen `reason`-Parameter und schaltet auf `IsEnabled` +statt `IsVisible` um, wenn der Aufrufer das verlangt. + +**Ergebnis:** 18 flache Einträge → 9 Top-Level-Zeilen, davon 5 mit fixer Position. + +--- + +## 2. Settings-Modal entzerren + +**Problem.** Der General-Tab mischt 10+ Konzeptgruppen (Sprache, Accent, Default-Instructions, +Model, Permission, Model-Presets-Tabelle, MaxTurns-Ceiling, Parallelität, Usage-Gate-Prozente, +Report-Excluded-Paths, Standup-Wochentag, Session-Skills-Checkboxen). Session Skills stehen +**doppelt** (Auswahl in General, Verwaltung im Skills-Tab). Und die sechs Tabs füllen den +580 px breiten TabStrip bereits aus — ein siebter passt nicht. + +**Entscheidung: Sidebar-Navigation mit zwei Gruppen.** + +``` +┌ Einstellungen ─────────────────────────────────────────┐ +│ BASIS │ [Panel der gewählten Kategorie] │ +│ Allgemein │ │ +│ Ausführung │ │ +│ Prime Claude │ │ +│ │ │ +│ ERWEITERT │ │ +│ Worktrees │ │ +│ Dateien & Prompts │ │ +│ Session Skills │ │ +│ Berichte │ │ +│ Online Inbox │ (nur wenn ShowOnlineInbox) │ +└────────────────────┴───────────────────────────────────┘ + [Abbrechen] [Speichern] +``` + +**Kategorien-Inhalt.** + +| Kategorie | Inhalt | Herkunft | +|---|---|---| +| Allgemein | Sprache, Accent-Preset, Default-Claude-Instructions | General | +| Ausführung | Default-Model, Permission-Mode, Model-Presets-Tabelle, MaxTurns-Ceiling, Max parallele Ausführungen, Usage-Gate (5h/7d %) | General | +| Prime Claude | Schedules + Daily-Prep-Max-Tasks | unverändert | +| Worktrees | Strategie, Root, Auto-Cleanup, Cleanup-/Reset-Aktionen | unverändert | +| Dateien & Prompts | Agents-Restore, Prompt-Pfade, Customized-Prompts | unverändert (Files) | +| Session Skills | **zusammengelegt**: je installierter Skill eine Zeile mit Checkbox (global aktiv) + Update/Remove; darunter Install-URL | Skills-Tab + Checkbox-Liste aus General | +| Berichte | Standup-Wochentag, Report-Excluded-Paths | General (neu herausgelöst) | +| Online Inbox | unverändert, weiter an `ShowOnlineInbox` gekoppelt | unverändert | + +**Session-Skills-Zusammenlegung.** Die Checkbox-Liste im General-Tab entfällt. Beide VMs +(`GeneralSettingsTabViewModel.SessionSkills`, `SessionSkillsSettingsTabViewModel`) speisen künftig +**eine** Liste; die Auswahl (global aktive Skills) wird weiterhin über denselben Pfad gespeichert +wie heute. Der Task muss belegen, dass Speichern/Laden der Auswahl unverändert funktioniert — +das ist die einzige Stelle mit echtem Regressionsrisiko. + +**Repo-Hinweis statt Verstecken.** Nichts wird ausgeblendet (verschwindende Einstellungen +irritieren in einem Power-Tool mehr als Dichte). Stattdessen zeigen **Worktrees, Prime Claude, +Session Skills und Berichte** oben einen Hinweisstreifen, solange keine Liste ein `WorkingDir` +hat: *„Wirkt erst mit verknüpftem Repo"* + Link, der den Repo-Import öffnet. Dafür eine neue +Property `HasLinkedRepo` am `SettingsModalViewModel`. + +**Umsetzung risikoarm.** Das `TabControl` **bleibt** als Content-Host: nur der TabStrip wird +ausgeblendet, und eine Sidebar-`ListBox` bindet `SelectedIndex`. Die vorhandenen Panel-Inhalte +wandern damit nahezu unverändert mit (General wird gesplittet, Skills gemerged, Berichte neu). +Keine Neuschrift der 556 AXAML-Zeilen, compiled bindings bleiben intakt. Sidebar-Modell: +`SettingsCategory(Key, Label, Group, IsVisible, RequiresRepo)` in `SettingsModalViewModel.Categories`. +Fensterbreite 580 → 700. + +--- + +## 3. TaskRow-Dichte + +**Problem.** Eine Zeile kann 16 Elemente zeigen. Die Maximaldichte trifft real fast nur einen +`WaitingForReview`-Task in einer Smart-List (Status-, List-, Branch-, Diff-Chip plus Icons und +Buttons) — aber genau dort ist die Zeile am schwersten zu lesen. + +**Entscheidung: Zustand bleibt, Aktionen auf Hover-oder-Selektion, reine Metadaten raus.** + +| Klasse | Elemente | +|---|---| +| **Immer sichtbar (Zustand)** | Chevron (Planning-Parent), Done-Toggle, `#Nummer`, Titel, die vier Badges (DRAFT/PLANNED/Planning/MANUAL), Roadblock-Icon, Agent-Suggested-Icon, Status-Chip (bleibt tappbar → Mission Control), Diff-Chip, List-Chip (nur Smart-Lists, wie heute), Chain-Chip/Chain-Step-Badge, **gesetzter** Star | +| **Hover ODER Selektion (Aktion)** | Refine-Button, **ungesetzter** Star, Dequeue-X | +| **Aus der Zeile raus** | Branch-Chip | + +**Kein Funktionsverlust.** Refine, Star und Dequeue bleiben über das Kontextmenü erreichbar — +„Remove from queue" existiert dort, „Refine task" wird in Thema 1 neu ergänzt. Selektion als +zweiter Trigger deckt Tastaturbedienung ab. + +**Ausnahme.** Der Refine-**Spinner** (`IsRefining`) bleibt immer sichtbar. Ein laufender Refine +darf nicht verschwinden, wenn die Maus die Zeile verlässt. + +**Branch-Chip: Verlagerung, nicht Löschung.** Der Branch-Name steht heute **nirgends** im +Detail-Pane (geprüft gegen `DetailsIslandView.axaml` und `Views/Islands/Detail/*.axaml` — +kein Treffer außer der Merge-Target-ComboBox). Er muss deshalb im selben Task in die +`TaskHeaderBar` als Meta-Zeile aufgenommen werden. `WorkConsole.axaml` fasst dieser Task +**nicht** an (Datei-Eigentum, siehe Plan). + +**Umsetzung.** `TaskRowViewModel` bekommt `IsHovered` (gesetzt über `PointerEntered`/ +`PointerExited` in `TaskRowView.axaml.cs`) und ein berechnetes +`ShowRowActions => IsHovered || IsSelected`. Die neuen Sichtbarkeiten sind **AND**-Verknüpfungen +mit den bestehenden `CanRefine` / `CanRemoveFromQueue` / `IsStarred` — keine bestehende Bedingung +wird ersetzt. Layout-Sprünge vermeiden: die Buttons behalten ihre Grid-Spalten +(`Auto,Auto,32`), es wechselt nur die Sichtbarkeit innerhalb fester Breite. + +**Ergebnis:** Worst case ohne Hover 16 → 9 Elemente. + +--- + +## 4. Erststart + +**Problem.** Nach dem Seeding existieren nur My Day / Important / Planned und kein Repo. Es gibt +kein Onboarding; die Empty States aus #192 beschreiben den Ist-Zustand, aber nicht die Reihenfolge +Repo → Liste → Task → Queue → Review. + +**Entscheidung: kein Onboarding-Konstrukt.** Ein zustandsgetriebenes Banner plus eine abgestimmte +Textkette. Explizit **kein** Wizard, **kein** Willkommens-Modal, **kein** Onboarding-Zustand in +DB oder Config. + +**Banner** im Lists-Island direkt unter dem Header, optisch wie das bestehende Update-Banner des +Shells (kein neues Stil-Vokabular): + +``` +┌──────────────────────────────────────────────┐ +│ Noch kein Repo verknüpft. ClaudeDo führt │ +│ Tasks in einem Git-Repo aus. │ +│ [ Repo importieren ] │ +└──────────────────────────────────────────────┘ +``` + +- Sichtbar, solange **keine User-Liste ein `WorkingDir` hat**. Neue Property `HasNoLinkedRepo` + am `ListsIslandViewModel`, neu berechnet beim Listen-Load und nach List-CRUD / + List-Settings-Save. +- **Kein Dismiss, kein persistierter Zustand.** Wer sein einziges Repo entfernt, bekommt den Weg + zurück wieder gezeigt. +- Der Button ruft das vorhandene `OpenRepoImportCommand` (dritter Einstieg neben dem Header-Button + und `Menü → Add repos`). + +**Textkette.** Die Stellen müssen als ein Weg lesbar sein. Die Keys aus #192 existieren zu diesem +Zeitpunkt schon und werden nur nachgeschärft: + +1. Banner → *Repo importieren* +2. Task-Liste leer, Liste **ohne** Repo (#192) → *Diese Liste hat kein Repo; in den List-Settings + verknüpfen* +3. Task-Liste leer, Liste **mit** Repo (#192) → *Task anlegen, dann Rechtsklick → „Send to queue" — + Claude arbeitet ihn in einem eigenen Worktree ab* +4. Review-Stufe: am Approve-Gate-Hinweis (den #190 in `WorkConsole.axaml` baut) **eine** Zeile + ergänzen, die sagt, dass Approve gleichzeitig das Mergen ist. + +Punkt 3 erklärt die Queue genau dort, wo der erste Task entsteht. Punkt 4 schließt die Lücke, +dass der erste fertige Run in einem Zustand landet, den nichts ankündigt. + +--- + +## Nicht Teil dieses Designs + +- Der WorkConsole-Git-Tab (laut Audit das dichteste Panel der App) — eigenes Thema. +- Mission Control und der Diff-Viewer. +- Alles, was #189–#192 schon abdecken.