diff --git a/frontend/src/components/l1/L1EscalationsSection.tsx b/frontend/src/components/l1/L1EscalationsSection.tsx new file mode 100644 index 00000000..5640a7e8 --- /dev/null +++ b/frontend/src/components/l1/L1EscalationsSection.tsx @@ -0,0 +1,77 @@ +import { useEffect, useState } from 'react' +import { l1Api } from '@/api/l1' +import type { WalkSession } from '@/types/l1' + +/** + * Engineer-visible list of escalated L1 sessions (the Phase 2A handoff queue). + * Backed by GET /l1/escalations (engineer-or-above). Pollable, dependency-free — + * each row expands to show the walked path summary. Renders nothing if empty. + */ +export function L1EscalationsSection() { + const [rows, setRows] = useState([]) + const [loaded, setLoaded] = useState(false) + const [expanded, setExpanded] = useState(null) + + useEffect(() => { + l1Api + .escalations() + .then(setRows) + .catch(() => setRows([])) + .finally(() => setLoaded(true)) + }, []) + + if (!loaded || rows.length === 0) return null + + return ( +
+
+

L1 escalations

+

+ Tickets an L1 tech escalated mid-walk — pick one up to continue. +

+
+
+ {rows.map((s) => { + const isOpen = expanded === s.id + return ( +
+ + {isOpen && ( +
+ {s.walked_path.length === 0 ? ( +

No steps recorded.

+ ) : ( +
    + {s.walked_path.map((step, i) => ( +
  1. + {step.question} + {step.answer && ( + → {step.answer} + )} +
  2. + ))} +
+ )} +
+ )} +
+ ) + })} +
+
+ ) +} diff --git a/frontend/src/types/flow-proposal.ts b/frontend/src/types/flow-proposal.ts index 6005e1ff..e0e83aa3 100644 --- a/frontend/src/types/flow-proposal.ts +++ b/frontend/src/types/flow-proposal.ts @@ -10,7 +10,10 @@ export interface FlowProposalSummary { supporting_session_count: number status: 'pending' | 'approved' | 'modified' | 'rejected' | 'dismissed' | 'auto_reinforced' target_flow_id: string | null - source_session_id: string + // Exactly one source is set: source_session_id (FlowPilot ai_session) XOR + // l1_session_id (L1 ai_build walk). Both nullable on the backend (Phase 2A). + source_session_id: string | null + l1_session_id: string | null created_at: string }