diff --git a/apps/fabro-web/app/components/run-dock.test.tsx b/apps/fabro-web/app/components/run-dock.test.tsx
index 56c5a1599..045b41445 100644
--- a/apps/fabro-web/app/components/run-dock.test.tsx
+++ b/apps/fabro-web/app/components/run-dock.test.tsx
@@ -9,7 +9,7 @@ import {
import TestRenderer, { act } from "react-test-renderer";
import { setupReactTestEnv } from "../lib/test-utils";
-import { DockComposer } from "./run-dock";
+import { DockComposer, RunDockShell } from "./run-dock";
const mountedRenderers: TestRenderer.ReactTestRenderer[] = [];
let teardownReactEnv: (() => void) | undefined;
@@ -26,6 +26,69 @@ afterEach(() => {
teardownReactEnv = undefined;
});
+describe("RunDockShell", () => {
+ function mountShell(
+ collapsed: boolean,
+ onCollapsedChange: (collapsed: boolean) => void,
+ ) {
+ let renderer!: TestRenderer.ReactTestRenderer;
+ act(() => {
+ renderer = TestRenderer.create(
+ }
+ />,
+ );
+ });
+ mountedRenderers.push(renderer);
+ return renderer;
+ }
+
+ function clickableDivs(renderer: TestRenderer.ReactTestRenderer) {
+ return renderer.root.findAll(
+ (node) => node.type === "div" && node.props.onClick !== undefined,
+ );
+ }
+
+ test("the whole collapsed bar is a click target that expands it", () => {
+ const onCollapsedChange = mock((_collapsed: boolean) => undefined);
+ const renderer = mountShell(true, onCollapsedChange);
+
+ const [header] = clickableDivs(renderer);
+ expect(header).toBeDefined();
+ act(() => header.props.onClick({ target: { closest: () => null } }));
+ expect(onCollapsedChange).toHaveBeenCalledWith(false);
+ });
+
+ test("clicks on header buttons do not also expand the bar", () => {
+ const onCollapsedChange = mock((_collapsed: boolean) => undefined);
+ const renderer = mountShell(true, onCollapsedChange);
+
+ const [header] = clickableDivs(renderer);
+ act(() => header.props.onClick({ target: { closest: () => ({}) } }));
+ expect(onCollapsedChange).not.toHaveBeenCalled();
+ });
+
+ test("clicks with a non-element target still expand the bar", () => {
+ const onCollapsedChange = mock((_collapsed: boolean) => undefined);
+ const renderer = mountShell(true, onCollapsedChange);
+
+ const [header] = clickableDivs(renderer);
+ act(() => header.props.onClick({ target: {} }));
+ expect(onCollapsedChange).toHaveBeenCalledWith(false);
+ });
+
+ test("the expanded header is not a click target", () => {
+ const onCollapsedChange = mock((_collapsed: boolean) => undefined);
+ const renderer = mountShell(false, onCollapsedChange);
+ expect(clickableDivs(renderer)).toHaveLength(0);
+ });
+});
+
describe("DockComposer", () => {
test("describes its keyboard behavior to assistive technology", () => {
let renderer!: TestRenderer.ReactTestRenderer;
diff --git a/apps/fabro-web/app/components/run-dock.tsx b/apps/fabro-web/app/components/run-dock.tsx
index 4e26daa3a..cb2a89c0e 100644
--- a/apps/fabro-web/app/components/run-dock.tsx
+++ b/apps/fabro-web/app/components/run-dock.tsx
@@ -99,7 +99,25 @@ export function RunDockShell({
className,
)}
>
-
+ {/* While collapsed, the whole bar expands on click. Clicks that land on
+ a button (Interrupt, the chevron) keep their own behavior. The
+ chevron button stays the keyboard/assistive-tech toggle. */}
+
{
+ if ((event.target as HTMLElement | null)?.closest?.("button")) {
+ return;
+ }
+ onCollapsedChange(false);
+ }
+ : undefined
+ }
+ >
{/* A live region: the dock changing to a state that needs the
operator has to reach assistive tech, not only the eye. */}
diff --git a/apps/fabro-web/app/components/steer-bar.test.tsx b/apps/fabro-web/app/components/steer-bar.test.tsx
index b13498af6..583a68750 100644
--- a/apps/fabro-web/app/components/steer-bar.test.tsx
+++ b/apps/fabro-web/app/components/steer-bar.test.tsx
@@ -98,11 +98,7 @@ describe("SteerBar", () => {
});
mountedRenderers.push(renderer);
- act(() => {
- renderer.root
- .findByProps({ "aria-label": "Collapse Steer running agent" })
- .props.onClick();
- });
+ // The dock starts collapsed by default.
expect(
renderer.root.findByProps({
"aria-label": "Expand Steer running agent",
diff --git a/apps/fabro-web/app/components/steer-bar.tsx b/apps/fabro-web/app/components/steer-bar.tsx
index 1b6e61f7c..4ec85bbcb 100644
--- a/apps/fabro-web/app/components/steer-bar.tsx
+++ b/apps/fabro-web/app/components/steer-bar.tsx
@@ -57,7 +57,9 @@ export function SteerBar({
ref,
}: SteerBarProps) {
const [errorMessage, setErrorMessage] = useState(null);
- const [collapsePreferred, setCollapsePreferred] = useState(false);
+ // Steering is an occasional control, so the dock starts collapsed and
+ // stays out of the way until the operator opens it.
+ const [collapsePreferred, setCollapsePreferred] = useState(true);
const textareaRef = useRef(null);
const steer = useSteerRun(runId);
const interrupt = useInterruptRun(runId);