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>
8.6 KiB
8.6 KiB
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.decisionsis 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)
- Action node commands (
- Button styling:
opacity-0 group-hover:opacity-100withClipboardicon, positionedabsolute top-1.5 right-1.5inside agroup relativewrapper. - On click:
navigator.clipboard.writeText(text), swap icon toCheckfor 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:kbdlook, 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
Modalcomponent). - Modal is route-aware using
location.pathnamevia ashortcutCatalog.tsfile:- Tree Navigation routes:
1-9Select option,EscGo back,EnterContinue. - Tree Editor routes:
Ctrl+SSave,Ctrl+ZUndo,Ctrl+Shift+ZRedo. - Other routes: Minimal generic navigation shortcuts.
- Tree Navigation routes:
- Do NOT bind
?as a keyboard shortcut — it conflicts with text inputs. The modal is click-driven only.
Keyboard Listener (TreeNavigationPage.tsx)
- Add
useEffectkeydown listener ondocument. - Keys
1-9: If current node is a decision node with options, callhandleSelectOptionfor 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
selectingOptionis truthy (loading state). - Ignore if any modal is open.
- Only active when
- 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-pointerfor clickable items. Current item remainsfont-medium text-whiteas a<span>. - Introduce a unified rewind handler used by both:
- Breadcrumb click
- Back button /
Esckey
- Rewind algorithm:
- Compute
newPath = pathTaken.slice(0, targetIndex + 1). - Append a
rewind_markerdecision with:decision_kind,rewind_source,rewind_from_node_id,rewind_to_node_id,abandoned_path_segment(nodes removed from active path), andtimestamp. - Persist immediately via
sessionsApi.update(session.id, { path_taken: newPath, decisions: newDecisions }). - On API failure: restore previous local state and show error toast.
- Compute
- 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_treeconversion: Ignore records wheredecision_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
Plusicon, linking to/trees/new.
- Permission-aware: Only show for users with create permission (use existing role checks /
usePermissionshook). 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
Plusicon → links to/trees/new.
- Primary (white bg, higher visual weight): "Browse Library" → links to
- "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/40to 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(fromh-3.5 w-3.5). - More visible but still secondary to tree name.
Action Loading Feedback
- Add
selectingOption: string | nullstate (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
isCompletingbehavior 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
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_treeignores 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).