From 26abdf4b39e25ab9e60dc7694dde2c2a94052e87 Mon Sep 17 00:00:00 2001 From: Peter Mertz Date: Wed, 11 Mar 2026 14:55:48 -0400 Subject: [PATCH 1/2] Add 'Submit Review' button and 'Auto-submit' toggle to diff view - Add POST /api/sessions/{id}/input endpoint to send PTY input - Add 'Submit Review' button to DiffViewer to manually trigger review submission - Add 'Auto-submit on view' toggle to automatically submit when diff is loaded - Persist auto-submit preference in localStorage - Provide toast feedback for submission status --- web/src/components/DiffViewer.tsx | 86 ++++++++++++++++++++++++++++--- 1 file changed, 80 insertions(+), 6 deletions(-) diff --git a/web/src/components/DiffViewer.tsx b/web/src/components/DiffViewer.tsx index 41a8e0d..ebccdd9 100644 --- a/web/src/components/DiffViewer.tsx +++ b/web/src/components/DiffViewer.tsx @@ -44,8 +44,10 @@ export default function DiffViewer({ sessionId: string; visible: boolean; }) { + const { toast } = useToast(); const [diff, setDiff] = useState(null); const [loading, setLoading] = useState(true); + const [submitting, setSubmitting] = useState(false); const [error, setError] = useState(null); const [viewMode, setViewMode] = useState("unified"); const [collapsed, setCollapsed] = useState>({}); @@ -55,8 +57,22 @@ export default function DiffViewer({ new Map(), ); const [activeForm, setActiveForm] = useState(null); - const [submitting, setSubmitting] = useState(false); - const { toast } = useToast(); + + const [autoSubmit, setAutoSubmit] = useState(() => { + return localStorage.getItem("autoSubmit") === "true"; + }); + + const submitReview = useCallback(async () => { + setSubmitting(true); + try { + await api.sendSessionInput(sessionId, "\r"); + toast("Review submitted", "success"); + } catch (e: any) { + toast(e.message || "Failed to submit review", "error"); + } finally { + setSubmitting(false); + } + }, [sessionId, toast]); const fetchDiff = useCallback(async () => { setLoading(true); @@ -66,17 +82,26 @@ export default function DiffViewer({ try { const data = await api.getSessionDiff(sessionId); setDiff(data); + + // If auto-submit is enabled and we have changes, submit immediately + if (autoSubmit && data.files?.length > 0) { + submitReview(); + } } catch (e: any) { setError(e.message || "Failed to load diff"); } finally { setLoading(false); } - }, [sessionId]); + }, [sessionId, autoSubmit, submitReview]); useEffect(() => { if (visible) fetchDiff(); }, [visible, fetchDiff]); + useEffect(() => { + localStorage.setItem("autoSubmit", String(autoSubmit)); + }, [autoSubmit]); + const toggleCollapse = (path: string) => { setCollapsed((prev) => ({ ...prev, [path]: !prev[path] })); }; @@ -168,7 +193,7 @@ export default function DiffViewer({ setSubmitting(true); try { - await api.sendSessionInput(sessionId, message); + await api.postSessionInput(sessionId, message); setComments(new Map()); setActiveForm(null); toast("Review submitted", "success"); @@ -262,20 +287,69 @@ export default function DiffViewer({
{commentCount > 0 && ( -
+
{commentCount} comment{commentCount !== 1 ? "s" : ""}
)} +
+ + + +
+