refactor(run): drop the lane progress bar, iconify pane layout, and one-row the run setup

Four more spots that spent height saying what was already visible or
saying too much of it.

**LaneCard** drops the progress bar and percent entirely — the pipeline
map right below the card already draws the same number as named,
coloured nodes, and a bar beside it was a worse second telling of it.

**SplitLayoutToggle** (Workspace) swaps "1 pane" / "2 pane" / "4 pane"
text buttons for the conventional square / two-column / 2x2-grid icons
(`Square`, `Columns2`, `Grid2x2`) most apps use for this. The words move
to `aria-label` and `title` rather than disappearing.

**RunSetup** merges the fresh/resume source picker onto the same row as
the Working directory / Model / Permission mode / Thinking effort fields
instead of a second row above them — settings left, New/Resume session
right. The session picker for an active resume still gets its own row
below, since it only appears in that one state.

**LaneConsolePane**'s "Run Claude" header goes from a two-row title +
wrapped blurb to one row (smaller icon and title), and the blurb itself
is trimmed to one short sentence, hidden below `sm` where it would wrap
again anyway.

`docs/LANES.md` updated to match (split-view description, lane-card
field list, and `agenthub stage`'s progress-bar wording).

Verification: `tsc --noEmit` clean, `npx vitest run` 508/508 (2 stale
progress-bar assertions in LaneCard.test.tsx replaced with one asserting
the bar is gone), `npm run build` clean, screens.snapshot diff reviewed
before regenerating (icon buttons + new blurb + reordered DOM only), file
headers audit clean.
This commit is contained in:
2026-09-17 11:37:01 +07:00
parent 229002cc2b
commit 7fae2f48c0
9 changed files with 394 additions and 311 deletions
+32 -16
View File
@@ -42,7 +42,7 @@
import { useCallback, useEffect, useState, useSyncExternalStore } from "react";
import { useTranslation } from "react-i18next";
import { Plus } from "lucide-react";
import { Plus, Square, Columns2, Grid2x2 } from "lucide-react";
import { api } from "../lib/api";
import type { CwdSuggestion, RunListResponse } from "../lib/api";
import type {
@@ -72,6 +72,14 @@ import type { SplitViewState, SplitLayout } from "../lib/splitViewStorage";
// ── Page ──────────────────────────────────────────────────────────────
/** One pane, two side by side, four in a grid — the conventional icons for
* each, so the toggle reads at a glance without spending three words on it. */
const LAYOUT_CHOICES = [
{ n: 1 as const, Icon: Square },
{ n: 2 as const, Icon: Columns2 },
{ n: 4 as const, Icon: Grid2x2 },
];
function SplitLayoutToggle({
splitView,
setLayout,
@@ -83,21 +91,29 @@ function SplitLayoutToggle({
return (
<div className="flex items-center gap-1.5">
{([1, 2, 4] as const).map((n) => (
<button
key={n}
type="button"
aria-pressed={splitView.layout === n}
onClick={() => setLayout(n)}
className={`rounded border px-2 py-1 text-xs ${
splitView.layout === n
? "border-accent bg-accent/15 text-accent"
: "border-border text-fg-secondary hover:border-border-light"
}`}
>
{tLanes("splitView.paneCount", { count: n })}
</button>
))}
{LAYOUT_CHOICES.map(({ n, Icon }) => {
// The count still reaches assistive tech and the tooltip — only the
// rendered word is gone, and the icon says the same thing in the
// shape every other app uses for it.
const label = tLanes("splitView.paneCount", { count: n });
return (
<button
key={n}
type="button"
aria-pressed={splitView.layout === n}
aria-label={label}
title={label}
onClick={() => setLayout(n)}
className={`rounded border p-1.5 ${
splitView.layout === n
? "border-accent bg-accent/15 text-accent"
: "border-border text-fg-secondary hover:border-border-light"
}`}
>
<Icon className="h-3.5 w-3.5" />
</button>
);
})}
</div>
);
}