From 217747f46ecdc00b3d2b9183d769749f0fc1b915 Mon Sep 17 00:00:00 2001 From: Michael Chihlas Date: Thu, 23 Apr 2026 15:39:08 -0400 Subject: [PATCH] feat(pilot): banner AI-confirming, Nudge, Collapsed states MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Completes ProposalBanner's state machine. AIConfirming (accent-blue) surfaces the AI's [FIX_OUTCOME] proposal with one-click accept; Nudge is the compact passive-prompt variant for post-apply chats; Collapsed is the 28px expand-hint strip. Adds onSilenceNudge prop so the parent can silence the nudge without collapsing it (Task 11 wires this). Removes the last three stale eslint-disable-next-line comments — all sub-components now use props. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../src/components/pilot/ProposalBanner.tsx | 120 +++++++++++++++++- 1 file changed, 113 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/pilot/ProposalBanner.tsx b/frontend/src/components/pilot/ProposalBanner.tsx index 264213fa..491ae6f8 100644 --- a/frontend/src/components/pilot/ProposalBanner.tsx +++ b/frontend/src/components/pilot/ProposalBanner.tsx @@ -35,6 +35,8 @@ export interface ProposalBannerProps { /** Collapsed variant shown as a thin single-line strip. */ collapsed?: boolean onToggleCollapsed?: () => void + /** Silence the nudge without collapsing it (Task 11 wires this). */ + onSilenceNudge?: () => void } export function ProposalBanner(props: ProposalBannerProps) { @@ -245,12 +247,116 @@ function PartialBanner({ fix, onOutcome, onApply }: ProposalBannerProps) { ) } -// Placeholder renderers — implemented in Task 9. -// eslint-disable-next-line @typescript-eslint/no-unused-vars -function AIConfirmingBanner(_: ProposalBannerProps) { return null } -// eslint-disable-next-line @typescript-eslint/no-unused-vars -function NudgeBanner(_: ProposalBannerProps) { return null } -// eslint-disable-next-line @typescript-eslint/no-unused-vars -function CollapsedBanner(_: ProposalBannerProps) { return null } +function AIConfirmingBanner({ fix, onAcceptAIProposal, onRejectAIProposal }: ProposalBannerProps) { + const proposal = fix.ai_outcome_proposal + if (!proposal) return null + const isSuccess = proposal.outcome === 'success' + const isFailure = proposal.outcome === 'failure' + + const headlineVerb = isSuccess + ? 'resolved the issue' + : isFailure + ? "didn't work" + : 'was partially applied' + + return ( +
+
+
+
+ +
+
+
+ AI detected outcome + + {isSuccess ? 'Success' : isFailure ? 'Failure' : 'Partial'} + +
+
+ AI thinks the fix {headlineVerb} — confirm? +
+
+ {proposal.reason || 'Based on the recent chat. One click either confirms or corrects.'} +
+
+
+ + +
+
+
+ ) +} + +function NudgeBanner({ fix, onOutcome, onSilenceNudge }: ProposalBannerProps) { + return ( +
+
+ + + + + + + Did "{fix.title}" work? + + + + +
+ ) +} + +function CollapsedBanner({ fix, onToggleCollapsed }: ProposalBannerProps) { + return ( + + ) +} export default ProposalBanner