Files
resolutionflow/docs/archive/2026-02-13-ux-improvements-implementation.md
chihlasm 350c977eda feat: add procedural flows with intake forms, navigation, and seed templates
Adds a new "procedural" tree type for linear step-by-step project workflows
(domain controller setup, M365 onboarding, VPN config, etc). Includes intake
form builder, two-panel step navigation, variable resolution, procedural
exports, 3 seed templates, and UI rename from "Trees" to "Flows".

Also archives 19 implemented plan docs and creates deferred features backlog.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 04:13:52 -05:00

195 lines
8.6 KiB
Markdown

# UX Improvements — Implementation Plan (Merged)
## Context
Five frontend UX improvements for tree navigation, my-trees, and app layout. Changes are primarily frontend with minimal backend updates for session rewind tracking. Single branch: `feat/ux-improvements`.
## Locked Decisions
- Breadcrumb rewind **persists immediately** via API call.
- Rewound steps are **soft-abandoned** (history preserved via rewind markers, never deleted).
- Shortcuts modal is **global from AppLayout** and **route-aware**.
- Follow existing **monochrome design system** with subtle keycap/hint styling.
- `sessions.decisions` is JSONB — no DB migration needed for rewind marker fields.
---
## Step 1: Command Copy UX (Quick Win)
**Files:** `TreeNavigationPage.tsx`
### Changes
- Add a copy-to-clipboard button next to every command block:
- Action node commands (`currentNode.commands`)
- Custom step commands (`currentCustomStep.step_data.content.commands`)
- Command output textarea (when content exists)
- Button styling: `opacity-0 group-hover:opacity-100` with `Clipboard` icon, positioned `absolute top-1.5 right-1.5` inside a `group relative` wrapper.
- On click: `navigator.clipboard.writeText(text)`, swap icon to `Check` for 2 seconds.
- Track copied state with `copiedCommand: string | null`.
- Show toast only on copy failure to avoid noisy UX on success.
- **Refactor** duplicate command block rendering into a single local render helper to keep behavior consistent across action/custom-step sections.
---
## Step 2: Keyboard Hints + Global Shortcuts Modal (Quick Win)
**Files:** `AppLayout.tsx`, `TreeNavigationPage.tsx`, new `shortcutCatalog.ts`
### In-Page Hints (TreeNavigationPage.tsx)
- Add keycap-style badges (`[1]`, `[2]`, etc.) next to decision option buttons. Style: `kbd` look, lower contrast, subtle.
- Add `[Esc]` hint next to the Back button label.
### Global Shortcuts Modal (AppLayout.tsx)
- Add `?` icon button in the app header (desktop + mobile drawer).
- Opens a modal (reuse existing `Modal` component).
- Modal is **route-aware** using `location.pathname` via a `shortcutCatalog.ts` file:
- **Tree Navigation routes:** `1-9` Select option, `Esc` Go back, `Enter` Continue.
- **Tree Editor routes:** `Ctrl+S` Save, `Ctrl+Z` Undo, `Ctrl+Shift+Z` Redo.
- **Other routes:** Minimal generic navigation shortcuts.
- **Do NOT bind `?` as a keyboard shortcut** — it conflicts with text inputs. The modal is click-driven only.
### Keyboard Listener (TreeNavigationPage.tsx)
- Add `useEffect` keydown listener on `document`.
- Keys `1-9`: If current node is a decision node with options, call `handleSelectOption` for the corresponding option (index = key - 1).
- `Escape`: Trigger back/rewind navigation (same handler as breadcrumb rewind — see Step 3).
- Guards:
- Only active when `currentNode?.type === 'decision'` and options exist.
- Ignore if `selectingOption` is truthy (loading state).
- Ignore if any modal is open.
- Cleanup: Return removal function for the listener.
---
## Step 3: Interactive Breadcrumbs with Soft-Abandon Rewind (Medium)
**Files:** `TreeNavigationPage.tsx`, `session.py`, `session_to_tree.py`, `export_service.py`, `SessionDetailPage.tsx`, `SessionHistoryPage.tsx`
### Public Interface Changes
Extend `DecisionRecord` in `session.py` and `session.ts` with optional fields:
```
decision_kind?: 'step' | 'rewind_marker' (default 'step')
rewind_source?: 'breadcrumb' | 'back_button'
rewind_from_node_id?: string
rewind_to_node_id?: string
abandoned_path_segment?: string[]
```
No DB migration required — `sessions.decisions` is JSONB and stores these optional fields directly.
### Frontend Changes (TreeNavigationPage.tsx)
- Replace static breadcrumb `<span>` elements with `<button>` for all non-current crumbs.
- Styling: `text-white/40 hover:text-white/70 hover:underline cursor-pointer` for clickable items. Current item remains `font-medium text-white` as a `<span>`.
- Introduce a **unified rewind handler** used by both:
- Breadcrumb click
- Back button / `Esc` key
- **Rewind algorithm:**
1. Compute `newPath = pathTaken.slice(0, targetIndex + 1)`.
2. Append a `rewind_marker` decision with: `decision_kind`, `rewind_source`, `rewind_from_node_id`, `rewind_to_node_id`, `abandoned_path_segment` (nodes removed from active path), and `timestamp`.
3. Persist immediately via `sessionsApi.update(session.id, { path_taken: newPath, decisions: newDecisions })`.
4. On API failure: restore previous local state and show error toast.
- Clear any custom step state if active (`customStepFlow.setCurrentCustomStep(null)`).
- Session continues accumulating steps naturally from the jumped-to node.
### Backend/Downstream Compatibility
- `save_as_tree` conversion: **Ignore** records where `decision_kind === 'rewind_marker'`.
- Export generators (Markdown, Text, HTML): **Skip** rewind marker records in step numbering and output.
- Session detail/timeline pages: **Display** rewind markers as explicit timeline events (e.g., "Rewound from Step 6 to Step 3").
- Session "decision count" in `SessionHistoryPage.tsx`: **Exclude** rewind markers from the count.
---
## Step 4: Prominent "Create Tree" CTA (Quick Win)
**Files:** `MyTreesPage.tsx`
### Header Update
- Convert header to flex row with action button:
- Left: Title + subtitle.
- Right: "Create Tree" button with `Plus` icon, linking to `/trees/new`.
- Permission-aware: Only show for users with create permission (use existing role checks / `usePermissions` hook). Viewers cannot see it.
### Empty State Update
- Replace single "Browse Trees" link with two actions:
- **Primary** (white bg, higher visual weight): "Browse Library" → links to `/trees`.
- **Secondary** (outline/border style): "Create from Scratch" with `Plus` icon → links to `/trees/new`.
- "Create from Scratch" is also permission-gated.
---
## Step 5: Timer Visibility + Action Loading Feedback (Quick Win)
**Files:** `TreeNavigationPage.tsx`
### Timer Enhancement
- Change timer from plain `text-white/40` to a pill/badge style:
```
rounded-full bg-white/10 px-2.5 py-0.5 text-sm text-white/60
```
- Slightly larger icon: `h-4 w-4` (from `h-3.5 w-3.5`).
- More visible but still secondary to tree name.
### Action Loading Feedback
- Add `selectingOption: string | null` state (stores option ID being selected).
- When an option is being processed:
- The active option button shows an inline spinner replacing the number badge.
- All other option buttons get `opacity-50 pointer-events-none`.
- **Keyboard shortcuts are disabled** to prevent double-submits.
- Add similar feedback for "Continue" button with a "Continuing..." label.
- Preserve existing `isCompleting` behavior for completion flow.
---
## Files Modified Summary
| File | Steps |
|------|-------|
| `TreeNavigationPage.tsx` | 1, 2, 3, 5 |
| `MyTreesPage.tsx` | 4 |
| `AppLayout.tsx` | 2 (global shortcuts modal + `?` button) |
| `shortcutCatalog.ts` (new) | 2 (route → shortcut definitions) |
| `session.py` | 3 (accept rewind marker fields in decisions) |
| `session_to_tree.py` | 3 (ignore rewind markers) |
| `export_service.py` | 3 (skip rewind markers in export output) |
| `SessionDetailPage.tsx` | 3 (display rewind events in timeline) |
| `SessionHistoryPage.tsx` | 3 (exclude rewind markers from decision count) |
---
## Verification
### Build
```bash
cd frontend && npm run build # clean build, no type errors
cd backend && pytest --override-ini="addopts="
```
### Manual Testing
- [ ] Copy button appears on hover over all command blocks; copies correctly; shows check feedback; failure shows toast.
- [ ] Keycap hints `[1]`, `[2]`, etc. visible next to decision options; `[Esc]` visible near back button.
- [ ] Number keys 1-9 select decision options; Esc triggers rewind; shortcuts disabled during loading.
- [ ] `?` icon in app header opens global shortcuts modal with route-aware content.
- [ ] `?` is NOT bound as a keyboard shortcut (no conflict with text inputs).
- [ ] Clicking a previous breadcrumb rewinds to that point, persists immediately, and adds a rewind marker to session decisions.
- [ ] Back button uses the same rewind marker flow as breadcrumbs.
- [ ] Session detail page shows rewind events in timeline; decision count excludes rewind markers.
- [ ] Exports (Markdown, Text, HTML) skip rewind markers and render only actual steps.
- [ ] `save_as_tree` ignores rewind markers.
- [ ] Timer displays as a visible pill badge.
- [ ] Option/continue buttons show spinner + disable siblings during loading.
- [ ] MyTreesPage header shows "Create Tree" button (hidden for viewers).
- [ ] Empty state shows both "Browse Library" (primary) and "Create from Scratch" (secondary, permission-gated).