Move completed plan docs to docs/plans/archive/. Add survey migration 046 and reference HTML/plan files. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
5.4 KiB
AI Builder UX Improvements
Date: 2026-02-24 Branch: frontend-standardization (PR #88) Status: Approved for implementation
Overview
Three focused UX improvements to the AI Flow Builder and tree editor:
- Publish always available — remove unnecessary
!isDirtygate on the Publish button - Generate All branches — one-click auto-generation of all branch details sequentially
- Honest activity messages — replace spinner-only loading with rotating status messages
Feature 1: Publish Button Always Available
Problem
The Publish button in TreeEditorPage.tsx is disabled when !isDirty. This prevents publishing a freshly AI-generated draft that landed in the editor already saved — the tree is valid and ready, but the button is greyed out because nothing has been locally changed.
This same issue affects any future import/ingestion pathway where a draft arrives pre-saved.
Solution
Remove !isDirty from the Publish button's disabled condition. Keep it disabled only for isSaving || hasBlockingErrors.
The Save Draft button retains its !isDirty guard (no reason to re-save an unchanged draft).
Change
File: frontend/src/pages/TreeEditorPage.tsx
Line: ~654
Before: disabled={isSaving || !isDirty || hasBlockingErrors}
After: disabled={isSaving || hasBlockingErrors}
Feature 2: Generate All Branches
Problem
With 4–7 branches, users must click "Generate Detail" for each branch individually, wait for it to complete, then click the next. For 6 branches this is 6 separate interactions with wait time between each.
Solution
Add a "Generate All" button that auto-generates all undetailed branches sequentially without user intervention.
Store changes (aiFlowBuilderStore.ts)
Add:
isGeneratingAll: boolean— true while auto-run is in progressstopGeneratingAll: boolean— flag set by user to cancel mid-rungenerateAllBranchDetails(): Promise<void>— sequential loopcancelGenerateAll(): void— sets stop flag
generateAllBranchDetails() logic:
- Set
isGeneratingAll: true,stopGeneratingAll: false - Loop through
selectedBranchesin order, skipping branches that already havesteps - For each: set
currentBranchIndexto the active branch (so tabs show live progress), callgenerateBranchDetail(branch.name) - After each call, check
stopGeneratingAll— if true, break - On
generateBranchDetailfailure: stop loop, setisGeneratingAll: false, leave error state on that branch (existing error handling handles display) - On complete: set
isGeneratingAll: false
UI changes (BranchDetailView.tsx)
- Add "Generate All" button above branch tabs, visible when ≥1 branch has no
stepsand!isGeneratingAll - During a run: button becomes "Stop" (calls
cancelGenerateAll) - Individual "Generate Detail" and "Skip" buttons disabled during
isGeneratingAll - Branch tabs show
currentBranchIndexhighlight during run so user can see which is active - When
isGeneratingAll, show "Branch X of Y" context in the generating animation
Error handling
On failure mid-run: stop at the failed branch, show the existing error indicator on that branch tab (red instead of green check), display the error message. User can retry that branch individually or skip it. No global abort.
Feature 3: Honest Activity Messages
Problem
GeneratingAnimation shows a spinner with static text. For waits of 5–30+ seconds this gives no sense of progress.
Solution
Replace the static text in GeneratingAnimation with rotating messages tied to elapsed time. Messages are always-true descriptions of what the system is doing at a high level.
Message sequence
| Elapsed | Message |
|---|---|
| 0–4s | "Setting up your flow..." |
| 4–12s | "Building diagnostic paths..." |
| 12–20s | "Putting the pieces in place..." |
| 20s+ | "Almost there..." |
Messages advance on a timer that resets each time generation starts. They use useEffect with setInterval — no new dependencies needed.
Generate All context
When isGeneratingAll is true, show "Branch X of Y" as a small label above the rotating message. This comes from the store's currentBranchIndex and selectedBranches.length.
Change
File: frontend/src/components/ai-builder/GeneratingAnimation.tsx
Replace static text with a useEffect-driven message cycler. Accept optional branchContext?: { current: number; total: number } prop.
BranchDetailView.tsx passes branchContext when isGeneratingAll is true.
Files Changed
| File | Change |
|---|---|
frontend/src/pages/TreeEditorPage.tsx |
Remove !isDirty from Publish disabled condition |
frontend/src/store/aiFlowBuilderStore.ts |
Add isGeneratingAll, stopGeneratingAll, generateAllBranchDetails, cancelGenerateAll |
frontend/src/components/ai-builder/BranchDetailView.tsx |
Add Generate All / Stop button, disable controls during run, pass branch context |
frontend/src/components/ai-builder/GeneratingAnimation.tsx |
Add rotating activity messages with elapsed timer, accept branchContext prop |
No backend changes required.
Non-Goals
- SSE/streaming status from backend (deferred, would be needed for accurate retry messaging)
- Parallel branch generation (rate limit risk, sequential is safer and shows progress)
- Persisting generate-all state across modal close (not needed, user can re-run)