feat(pilot): EscalateInterceptDialog popover

Anchored above the Escalate button, captures fix outcome before the
engineer hands off the ticket. Defaults to 'didn't work' on Enter
(the common case). Alternatives: 'worked, escalating for another
reason' (preserves success) and 'never actually applied' (dismiss).

Task 11 will wire this to AssistantChatPage's Escalate handler.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-23 15:48:33 -04:00
parent 217747f46e
commit 075b0fc1d8

View File

@@ -0,0 +1,76 @@
/**
* EscalateInterceptDialog — popover anchored above the Escalate button.
*
* Fires when the engineer clicks Escalate while a fix is in Verifying or
* Partial state. Captures the fix outcome before the escalation so the
* handoff narrative is honest for whoever picks up the ticket.
*
* Visual reference: docs/FlowAssist_Migration/mockups/07-verify-states.html
* (panel C).
*/
import { X, AlertCircle, Check } from 'lucide-react'
import type { FixOutcome } from '@/api/sessionSuggestedFixes'
export type InterceptChoice = FixOutcome | 'never_applied'
export interface EscalateInterceptDialogProps {
fixTitle: string
onChoose: (choice: InterceptChoice) => void
onClose: () => void
}
export function EscalateInterceptDialog({
fixTitle,
onChoose,
onClose,
}: EscalateInterceptDialogProps) {
return (
<>
<div
className="fixed inset-0 z-40"
onClick={onClose}
aria-hidden="true"
/>
<div
role="dialog"
aria-label="Capture fix outcome before escalating"
className="absolute bottom-full mb-2 left-0 z-50 w-[340px] rounded-lg border border-white/15 bg-card p-3.5 shadow-[0_18px_40px_rgba(0,0,0,0.55)]"
>
<div className="font-heading font-semibold text-[13px] text-heading mb-1">
Before escalating what happened with the fix?
</div>
<div className="text-[12px] text-muted-foreground leading-[1.5] mb-3">
&ldquo;{fixTitle}&rdquo; is still in the Verifying state. Tag its outcome so
the senior picking this up knows what&apos;s been tried.
</div>
<div className="flex flex-col gap-1.5">
<button
autoFocus
onClick={() => onChoose('applied_failed')}
className="flex items-center gap-2.5 px-3 py-2.5 rounded-lg border border-danger/30 bg-danger-dim text-[12.5px] text-primary hover:bg-danger-dim/80 hover:border-danger transition-colors text-left"
>
<X size={13} strokeWidth={2.5} className="text-danger" />
<span className="flex-1">The fix didn&apos;t work</span>
<span className="text-[10.5px] text-muted-foreground font-mono px-1.5 py-[2px] rounded bg-white/[0.05]"></span>
</button>
<button
onClick={() => onChoose('applied_success')}
className="flex items-center gap-2.5 px-3 py-2.5 rounded-lg border border-white/10 bg-elevated text-[12.5px] text-primary hover:bg-sidebar transition-colors text-left"
>
<Check size={13} strokeWidth={2} />
<span className="flex-1">It worked escalating for another reason</span>
</button>
<button
onClick={() => onChoose('never_applied')}
className="flex items-center gap-2.5 px-3 py-2.5 rounded-lg border border-white/10 bg-elevated text-[12.5px] text-primary hover:bg-sidebar transition-colors text-left"
>
<AlertCircle size={13} strokeWidth={2} />
<span className="flex-1">Never actually applied it</span>
</button>
</div>
</div>
</>
)
}
export default EscalateInterceptDialog