fix: v2.5.11 — the commit box wraps only when the panel is narrow
The message keeps the row with the commit, Stage all and Unstage all buttons while there is room (a 50/50 split, a full-width panel); in a narrow panel the buttons wrap under it instead of squeezing the message to a few characters. Client 1095/1095 on the committed tree.
This commit is contained in:
@@ -2099,13 +2099,15 @@ export function LaneChangesPanel({
|
||||
{(stagedCount > 0 || toStage.length > 0) && (
|
||||
<div
|
||||
data-testid="lane-changes-actions"
|
||||
className="sticky top-0 z-10 mb-1.5 flex items-center gap-1.5 border-b border-border-light bg-surface-1 pb-2"
|
||||
className="sticky top-0 z-10 mb-1.5 flex flex-wrap items-center gap-1.5 border-b border-border-light bg-surface-1 pb-2"
|
||||
>
|
||||
{/* ONE row: message, commit, then the two bulk index moves. */}
|
||||
{/* One row when there is room; in a narrow panel the buttons
|
||||
wrap below rather than squeeze the message to a few
|
||||
characters (its min width is what triggers the wrap). */}
|
||||
{stagedCount > 0 && (
|
||||
<div
|
||||
data-testid="lane-changes-commit"
|
||||
className="flex min-w-0 flex-1 items-center gap-1.5"
|
||||
className="flex min-w-[14rem] flex-1 items-center gap-1.5"
|
||||
>
|
||||
<input
|
||||
value={message}
|
||||
@@ -2138,63 +2140,69 @@ export function LaneChangesPanel({
|
||||
<Sparkles className="h-3 w-3" aria-hidden />
|
||||
)}
|
||||
</button>
|
||||
<label
|
||||
title={t("changes.amendHint")}
|
||||
className="flex shrink-0 cursor-pointer items-center gap-1 text-[11px] text-fg-secondary"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
data-testid="lane-changes-amend"
|
||||
checked={amend}
|
||||
onChange={(e) => setAmend(e.target.checked)}
|
||||
/>
|
||||
{t("changes.amend")}
|
||||
</label>
|
||||
<button
|
||||
type="button"
|
||||
disabled={busy || suggesting || !(message.trim() || amend)}
|
||||
onClick={() => void commitStaged()}
|
||||
className="shrink-0 flex items-center gap-1 rounded border border-border-light px-1.5 py-0.5 text-[11px] text-fg-secondary hover:bg-surface-2 hover:text-fg-primary disabled:cursor-not-allowed disabled:opacity-40"
|
||||
>
|
||||
{amend
|
||||
? t("changes.amend")
|
||||
: t("changes.commitStaged", { count: stagedCount })}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{toStage.length > 0 && (
|
||||
<button
|
||||
type="button"
|
||||
disabled={busy}
|
||||
onClick={() =>
|
||||
void act(
|
||||
"stage",
|
||||
toStage.map((f) => f.path)
|
||||
)
|
||||
}
|
||||
className="shrink-0 flex items-center gap-1 rounded border border-border-light px-1.5 py-0.5 text-[11px] text-fg-secondary hover:bg-surface-2 hover:text-fg-primary disabled:cursor-not-allowed disabled:opacity-40"
|
||||
>
|
||||
<Plus className="h-3 w-3" />
|
||||
{t("changes.stageAll", { count: toStage.length })}
|
||||
</button>
|
||||
)}
|
||||
{stagedCount > 0 && (
|
||||
<button
|
||||
type="button"
|
||||
data-testid="lane-changes-unstage-all"
|
||||
disabled={busy}
|
||||
onClick={() =>
|
||||
void act(
|
||||
"unstage",
|
||||
files.filter((f) => f.staged).map((f) => f.path)
|
||||
)
|
||||
}
|
||||
className="shrink-0 flex items-center gap-1 rounded border border-border-light px-1.5 py-0.5 text-[11px] text-fg-secondary hover:bg-surface-2 hover:text-fg-primary disabled:cursor-not-allowed disabled:opacity-40"
|
||||
>
|
||||
<Minus className="h-3 w-3" />
|
||||
{t("changes.unstageAll", { count: stagedCount })}
|
||||
</button>
|
||||
)}
|
||||
<div className="flex flex-wrap items-center gap-1.5">
|
||||
{stagedCount > 0 && (
|
||||
<>
|
||||
<label
|
||||
title={t("changes.amendHint")}
|
||||
className="flex shrink-0 cursor-pointer items-center gap-1 text-[11px] text-fg-secondary"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
data-testid="lane-changes-amend"
|
||||
checked={amend}
|
||||
onChange={(e) => setAmend(e.target.checked)}
|
||||
/>
|
||||
{t("changes.amend")}
|
||||
</label>
|
||||
<button
|
||||
type="button"
|
||||
disabled={busy || suggesting || !(message.trim() || amend)}
|
||||
onClick={() => void commitStaged()}
|
||||
className="shrink-0 flex items-center gap-1 rounded border border-border-light px-1.5 py-0.5 text-[11px] text-fg-secondary hover:bg-surface-2 hover:text-fg-primary disabled:cursor-not-allowed disabled:opacity-40"
|
||||
>
|
||||
{amend
|
||||
? t("changes.amend")
|
||||
: t("changes.commitStaged", { count: stagedCount })}
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
{toStage.length > 0 && (
|
||||
<button
|
||||
type="button"
|
||||
disabled={busy}
|
||||
onClick={() =>
|
||||
void act(
|
||||
"stage",
|
||||
toStage.map((f) => f.path)
|
||||
)
|
||||
}
|
||||
className="shrink-0 flex items-center gap-1 rounded border border-border-light px-1.5 py-0.5 text-[11px] text-fg-secondary hover:bg-surface-2 hover:text-fg-primary disabled:cursor-not-allowed disabled:opacity-40"
|
||||
>
|
||||
<Plus className="h-3 w-3" />
|
||||
{t("changes.stageAll", { count: toStage.length })}
|
||||
</button>
|
||||
)}
|
||||
{stagedCount > 0 && (
|
||||
<button
|
||||
type="button"
|
||||
data-testid="lane-changes-unstage-all"
|
||||
disabled={busy}
|
||||
onClick={() =>
|
||||
void act(
|
||||
"unstage",
|
||||
files.filter((f) => f.staged).map((f) => f.path)
|
||||
)
|
||||
}
|
||||
className="shrink-0 flex items-center gap-1 rounded border border-border-light px-1.5 py-0.5 text-[11px] text-fg-secondary hover:bg-surface-2 hover:text-fg-primary disabled:cursor-not-allowed disabled:opacity-40"
|
||||
>
|
||||
<Minus className="h-3 w-3" />
|
||||
{t("changes.unstageAll", { count: stagedCount })}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{/* The work range splits like VS Code's Source Control: what the
|
||||
|
||||
@@ -1069,7 +1069,7 @@ describe("LaneChangesPanel", () => {
|
||||
expect(screen.getByTestId("lane-file-editor")).toHaveValue("xy");
|
||||
});
|
||||
|
||||
it("unstages every staged file in one call, on the same row as Stage all and commit", async () => {
|
||||
it("unstages every staged file in one call, in the same pinned bar as Stage all and commit", async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<LaneChangesPanel laneId={7} />);
|
||||
await screen.findByTestId("lane-changes-overview");
|
||||
|
||||
+4
-3
@@ -733,9 +733,10 @@ in every panel narrow enough to sit beside a console.
|
||||
**Per-file writes are the panel's, per-repo writes are the git bar's.** Staging
|
||||
one file means nothing unless a commit can take the index as it stands, so the
|
||||
overview grows a commit box the moment anything is staged — above the list and
|
||||
pinned while it scrolls, on ONE row with a **Stage all** that stages every listed file
|
||||
the index lacks in one call and an **Unstage all** that unstages every staged one — it sends
|
||||
`only: "staged"`, never `add -A`, and it is absent with a clean index because
|
||||
pinned while it scrolls: the message (and its suggest button), the commit button, a **Stage all** that stages every listed file
|
||||
the index lacks in one call and an **Unstage all** that unstages every staged one — one row when the
|
||||
panel has room, the buttons wrapping under the message when it is narrow. The commit sends
|
||||
`only: "staged"`, never `add -A`, and the box is absent with a clean index because
|
||||
there is nothing it could mean. A file you never want committed (a local note, a scratch folder) can be marked **Never stage** (its row's eye-off button, or right-click): **Stage all** and a folder's stage button then skip it, the row is struck through, and the file is drawn orange in the Files tree (`--kept`, apart from the amber of a modified file). The list is kept in this browser per workspace (`agenthub.changes.neverStage.<lane id>`) and git is never told — nothing is written to the repo, and the file's own Stage still works. It is the dashboard's ONLY commit: the git bar
|
||||
above it has none, so no click can sweep the rest of the tree in with `add -A`. **Discard** is the one
|
||||
irreversible action in the panel: it asks twice in the UI, and the server
|
||||
|
||||
Reference in New Issue
Block a user