feat(l1): L1WalkPage tree variant with Resolve/Escalate modals

Replaces the T20 stub. WalkPage dispatches by session_kind:
- 'flow' / 'proposal' → L1WalkTreeVariant (this commit)
- 'adhoc' → placeholder until T23

L1WalkTreeVariant: sticky header with back link + AI-built badge +
persistent Escalate/Resolve buttons; two-pane body (current step
yes/no card on left, walked-path transcript on right). ResolveModal
and EscalateModal extracted to shared WalkModals.tsx (T23 reuses).

Phase 1 caveat: this surface isn't reached by user-driven intake
(which creates adhoc sessions only). It's exercised via direct URL
or integration tests until Phase 2 wires match_or_build.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-28 14:17:02 -04:00
parent 4e9610c252
commit c0bddc289e
3 changed files with 356 additions and 7 deletions

View File

@@ -1,13 +1,68 @@
import { useEffect, useState } from 'react'
import { useParams, useNavigate } from 'react-router-dom'
import { PageMeta } from '@/components/common/PageMeta'
import { l1Api } from '@/api/l1'
import { L1WalkTreeVariant } from '@/components/l1/L1WalkTreeVariant'
import type { WalkSession } from '@/types/l1'
export default function L1WalkPage() {
return (
<div className="overflow-y-auto h-full">
<PageMeta title="L1 Walk" />
<div className="max-w-4xl mx-auto px-6 pt-12 pb-12">
<h1 className="font-heading text-2xl font-bold">L1 Walk</h1>
<p className="text-muted-foreground mt-2">Loading</p>
const { sessionId } = useParams<{ sessionId: string }>()
const navigate = useNavigate()
const [session, setSession] = useState<WalkSession | null>(null)
const [error, setError] = useState<string | null>(null)
useEffect(() => {
if (!sessionId) return
l1Api.getSession(sessionId)
.then(setSession)
.catch((err) => {
const msg = err?.response?.data?.detail || err?.message || 'Failed to load session'
setError(typeof msg === 'string' ? msg : 'Failed to load session')
})
}, [sessionId])
if (error) {
return (
<div className="overflow-y-auto h-full">
<PageMeta title="L1 Walk" />
<div className="max-w-4xl mx-auto px-6 pt-12 text-muted-foreground">
{error}
</div>
</div>
</div>
)
}
if (!session) {
return (
<div className="overflow-y-auto h-full">
<PageMeta title="L1 Walk" />
<div className="max-w-4xl mx-auto px-6 pt-12 text-muted-foreground">Loading</div>
</div>
)
}
const handleDone = () => navigate('/l1')
// Phase 1: adhoc variant (T23) handles session_kind='adhoc'. Tree variant handles flow/proposal.
// For T22, only the tree variant is implemented. Adhoc sessions render a placeholder until T23 lands.
if (session.session_kind === 'adhoc') {
return (
<div className="overflow-y-auto h-full">
<PageMeta title="L1 Walk" />
<div className="max-w-4xl mx-auto px-6 pt-12 text-muted-foreground">
Ad-hoc walker pending (T23).
</div>
</div>
)
}
return (
<>
<PageMeta title="L1 Walk" />
<L1WalkTreeVariant
session={session}
onSessionUpdate={setSession}
onDone={handleDone}
/>
</>
)
}