docs(daily-prep): add plan-day-in-log-window plan
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
120
docs/superpowers/plans/2026-06-04-plan-day-in-log-window.md
Normal file
120
docs/superpowers/plans/2026-06-04-plan-day-in-log-window.md
Normal file
@@ -0,0 +1,120 @@
|
||||
# Move "Plan day" into the Prep-Log Window — Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: superpowers:subagent-driven-development. Steps use `- [ ]`.
|
||||
|
||||
**Goal:** Guard daily-prep planning behind a second click. The MyDay header's full-width "Tag vorbereiten" button is removed; instead the user opens the prep-log window (list icon), sees the last run or an empty-state hint, and clicks a **"Plan day"** button inside that window to run the prep.
|
||||
|
||||
**Approved flow:** Header list-icon (`ShowPrepLogCommand`) opens the prep window → if empty, an empty-state hint shows → "Plan day" button in the window runs `RunDailyPrepNowAsync()`.
|
||||
|
||||
**Tech:** Avalonia + CommunityToolkit.Mvvm, xUnit.
|
||||
|
||||
## Build/test
|
||||
```bash
|
||||
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
|
||||
```
|
||||
GUI not headlessly verifiable — note it; human verifies visuals.
|
||||
|
||||
---
|
||||
|
||||
## Task: relocate planning trigger + empty-state
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/ClaudeDo.Ui/ViewModels/Islands/TasksIslandViewModel.cs` (remove PrepareDay)
|
||||
- Modify: `src/ClaudeDo.Ui/Views/Islands/TasksIslandView.axaml` (remove header button)
|
||||
- Modify: `src/ClaudeDo.Ui/ViewModels/Islands/DetailsIslandViewModel.cs` (PlanDayCommand + empty-state)
|
||||
- Modify: `src/ClaudeDo.Ui/Views/Islands/DetailsIslandView.axaml` (prep panel toolbar + empty hint)
|
||||
- Modify: `src/ClaudeDo.Localization/locales/en.json`, `de.json`
|
||||
- Test: `tests/ClaudeDo.Ui.Tests/ViewModels/DetailsIslandPrepModeTests.cs`, and the existing `TasksIslandDailyPrepTests.cs` (remove the obsolete prepare test)
|
||||
|
||||
- [ ] **Step 1: Write/adjust tests first.**
|
||||
- In `DetailsIslandPrepModeTests.cs` add:
|
||||
```csharp
|
||||
[Fact]
|
||||
public async Task PlanDayCommand_calls_worker()
|
||||
{
|
||||
var stub = new StubWorkerClient();
|
||||
var vm = NewDetailsVm(stub);
|
||||
await vm.PlanDayCommand.ExecuteAsync(null);
|
||||
Assert.Equal(1, stub.RunDailyPrepNowCalls);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShowPrepEmptyState_true_when_empty_and_not_running()
|
||||
{
|
||||
var vm = NewDetailsVm(new StubWorkerClient());
|
||||
Assert.True(vm.ShowPrepEmptyState);
|
||||
}
|
||||
```
|
||||
`StubWorkerClient` needs a `RunDailyPrepNowCalls` counter incremented in `RunDailyPrepNowAsync` (add if missing; it currently likely returns `Task.FromResult(true)` — keep that and bump a counter).
|
||||
- In `TasksIslandDailyPrepTests.cs` **remove** `PrepareDayCommand_raises_PrepRequested` (the command is being deleted). Keep `ClearDayCommand_calls_worker`.
|
||||
|
||||
- [ ] **Step 2: Run — expect FAIL/compile error.**
|
||||
|
||||
- [ ] **Step 3: `TasksIslandViewModel` — remove planning trigger.**
|
||||
- Delete the `PrepareDayAsync` `[RelayCommand]` entirely.
|
||||
- Keep the `PrepRequested` event and `ShowPrepLog` command (the list icon still raises `PrepRequested` to open the window).
|
||||
- Grep the VM for any remaining `PrepareDay` references and remove them.
|
||||
|
||||
- [ ] **Step 4: `TasksIslandView.axaml` — remove the header button.** Delete the full-width "Prepare day" `<Button … Command="{Binding PrepareDayCommand}" …>`. Leave the Notes pinned-row button, and the header icon buttons (broom = ClearDay, list = ShowPrepLog) untouched.
|
||||
|
||||
- [ ] **Step 5: `DetailsIslandViewModel` — add PlanDayCommand + empty-state.**
|
||||
- Add:
|
||||
```csharp
|
||||
[RelayCommand]
|
||||
private async Task PlanDayAsync()
|
||||
{
|
||||
if (_worker is null) return;
|
||||
try { await _worker.RunDailyPrepNowAsync(); }
|
||||
catch { /* worker offline; PrepStarted/PrepLine will reconcile */ }
|
||||
}
|
||||
|
||||
public bool ShowPrepEmptyState => !IsPrepRunning && PrepLog.Count == 0;
|
||||
```
|
||||
- Notify `ShowPrepEmptyState`: in the constructor add `PrepLog.CollectionChanged += (_, _) => OnPropertyChanged(nameof(ShowPrepEmptyState));`, and add `partial void OnIsPrepRunningChanged(bool value) => OnPropertyChanged(nameof(ShowPrepEmptyState));`.
|
||||
|
||||
- [ ] **Step 6: `DetailsIslandView.axaml` — prep panel toolbar + empty hint.** In the `<Panel IsVisible="{Binding IsPrepMode}">`, wrap the existing `SessionTerminalView` in a `DockPanel`; dock a top toolbar row with the Plan-day button, and overlay/stack an empty-state hint:
|
||||
```xml
|
||||
<Panel IsVisible="{Binding IsPrepMode}">
|
||||
<DockPanel>
|
||||
<Border DockPanel.Dock="Top" Padding="12,8">
|
||||
<Button Classes="btn primary"
|
||||
Command="{Binding PlanDayCommand}"
|
||||
IsEnabled="{Binding !IsPrepRunning}"
|
||||
Content="{loc:Tr details.planDay}"/>
|
||||
</Border>
|
||||
<Panel>
|
||||
<islands:SessionTerminalView
|
||||
Entries="{Binding PrepLog}" Label="daily-prep"
|
||||
IsRunning="{Binding IsPrepRunning}"/>
|
||||
<TextBlock IsVisible="{Binding ShowPrepEmptyState}"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource TextMuteBrush}"
|
||||
Text="{loc:Tr details.prepEmpty}"/>
|
||||
</Panel>
|
||||
</DockPanel>
|
||||
</Panel>
|
||||
```
|
||||
(Match the surrounding view's class names/brushes; use the existing button class style seen elsewhere, e.g. `Classes="btn"` — verify `primary` exists, else plain `btn`.)
|
||||
|
||||
- [ ] **Step 7: Locales.** Add `details.planDay` (en "Plan day", de "Tag planen") and `details.prepEmpty` (en "No prep run today yet — click Plan day", de "Heute noch keine Vorbereitung — klick Tag planen") to both json files. Remove the now-unused `tasks.prepareDay` key from both (grep first to confirm no other reference). Keep en/de key parity.
|
||||
|
||||
- [ ] **Step 8: Build + tests.**
|
||||
```bash
|
||||
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
|
||||
```
|
||||
|
||||
- [ ] **Step 9: Manual smoke (human):** on MyDay there is no "Tag vorbereiten" button; the list icon opens the prep window showing the empty hint; "Plan day" runs the prep and streams; the hint disappears while running; after restart the persisted last run shows and "Plan day" is available to re-run.
|
||||
|
||||
- [ ] **Step 10: Commit:**
|
||||
```bash
|
||||
git commit -m "feat(daily-prep): trigger planning from inside the prep-log window with an empty-state hint"
|
||||
```
|
||||
|
||||
## Notes / risks
|
||||
- `PrepRequested` and `ShowPrepLogCommand` stay — only `PrepareDayCommand` and its header button are removed.
|
||||
- `ShowPrepEmptyState` must re-notify on both `PrepLog` changes and `IsPrepRunning` changes, else the hint won't hide when a run starts or lines arrive.
|
||||
- Removing `tasks.prepareDay`: confirm via grep it has no remaining references before deleting (keep locale parity or the Localization.Tests parity check fails).
|
||||
Reference in New Issue
Block a user