From 094ebe164a035164e184240c95695e4b4f3d93d1 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Thu, 7 May 2026 14:26:10 -0700 Subject: [PATCH] feat(web): add Send interrupt and Send steering actions to the run menu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds two new items to the run-detail Actions dropdown, always present and disabled when unavailable. Send interrupt is wired to POST /api/v1/runs/{id}/interrupt and gated on running status. Send steering… focuses the bottom-dock steer textarea via a new forwardRef handle on SteerBar; gated on running status with no pending questions. Bumps the separator after the new pair to render whenever any later group exists. Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/fabro-web/app/components/steer-bar.tsx | 27 ++++++- apps/fabro-web/app/lib/mutations.ts | 18 +++++ apps/fabro-web/app/routes/run-detail.test.ts | 1 + apps/fabro-web/app/routes/run-detail.tsx | 78 ++++++++++++++++++-- 4 files changed, 116 insertions(+), 8 deletions(-) diff --git a/apps/fabro-web/app/components/steer-bar.tsx b/apps/fabro-web/app/components/steer-bar.tsx index 0745fe9eb..db3bb5bb7 100644 --- a/apps/fabro-web/app/components/steer-bar.tsx +++ b/apps/fabro-web/app/components/steer-bar.tsx @@ -1,13 +1,33 @@ -import { useState, type FormEvent, type KeyboardEvent } from "react"; +import { + forwardRef, + useImperativeHandle, + useRef, + useState, + type FormEvent, + type KeyboardEvent, +} from "react"; import { CheckIcon } from "@heroicons/react/16/solid"; export interface SteerBarProps { runId: string; } -export function SteerBar({ runId: _runId }: SteerBarProps) { +export interface SteerBarHandle { + focus(): void; +} + +export const SteerBar = forwardRef(function SteerBar( + { runId: _runId }, + ref, +) { const [text, setText] = useState(""); const [interrupt, setInterrupt] = useState(false); + const textareaRef = useRef(null); + useImperativeHandle(ref, () => ({ + focus() { + textareaRef.current?.focus(); + }, + })); const trimmed = text.trim(); const canSubmit = trimmed.length > 0; @@ -33,6 +53,7 @@ export function SteerBar({ runId: _runId }: SteerBarProps) { className="mx-auto flex max-w-4xl items-end gap-2 px-4 py-3 sm:px-6 lg:px-8" >