Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 34 additions & 4 deletions apps/app/.ladle/story-fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { getProviderIconInfo } from "../src/lib/provider-icon";
import type { PickerOption } from "../src/components/pickers/OptionPicker";
import type { ModelPickerOption } from "../src/components/pickers/model-picker-option";
import type { ProjectSelectorOption } from "../src/components/pickers/ProjectSelector";
import type { ReuseThreadOption } from "../src/components/pickers/WorktreePicker";
import type { WorktreeOption } from "../src/components/pickers/WorktreePicker";
import type { ExecutionControlsProps } from "../src/components/promptbox/ExecutionControls";
import {
INERT_TYPEAHEAD_COMMAND_CONFIG,
Expand Down Expand Up @@ -225,22 +225,52 @@ export const STORY_BRANCH_OPTIONS: readonly string[] = [
"bb/refactor-project-creation-thr_jj65bdsiwa",
];

export const STORY_WORKTREE_OPTIONS: readonly ReuseThreadOption[] = [
export const STORY_WORKTREE_OPTIONS: readonly WorktreeOption[] = [
{
value: "reuse:env_review_flow",
environmentId: "env_review_flow",
branchName: "bb/review-flow-thr_4hge9xn14m",
hostId: HOST_IDS.local,
hostName: null,
name: null,
checkout: { kind: "branch", branchName: "bb/review-flow-thr_4hge9xn14m" },
displayPath: "/Users/dev/bb-worktrees/review-flow",
availability: "selectable",
lock: null,
ownership: "bb-managed",
threads: [
{ id: "thr_review", title: "Review flow cleanup" },
{ id: "thr_tests", title: "Backfill promptbox tests" },
],
},
{
value: "reuse:env_timeline",
environmentId: "env_timeline",
branchName: "bb/timeline-pagination-thr_qfk8ksbxkk",
hostId: HOST_IDS.local,
hostName: null,
name: "Timeline workspace",
checkout: {
kind: "branch",
branchName: "bb/timeline-pagination-thr_qfk8ksbxkk",
},
displayPath: "/Users/dev/bb-worktrees/timeline-pagination",
availability: "selectable",
lock: null,
ownership: "bb-managed",
threads: [{ id: "thr_timeline", title: "Timeline pagination" }],
},
{
value: "path:host_local:%2FUsers%2Fdev%2Fworktrees%2Fspike",
environmentId: null,
hostId: HOST_IDS.local,
hostName: null,
name: null,
checkout: { kind: "branch", branchName: "spike/manual-worktree" },
displayPath: "/Users/dev/worktrees/spike",
availability: "selectable",
lock: null,
ownership: "user-managed",
threads: [],
},
];

export const STORY_PROJECTS: readonly ProjectSelectorOption[] = [
Expand Down
12 changes: 8 additions & 4 deletions apps/app/src/components/pickers/EnvironmentPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export function EnvironmentPickerUI({
const newWorktreeDisabledReason =
workspaceDisabledReason ?? worktreeDisabledReason ?? null;
const reuseDisabledReason = reuseDisabled
? "No worktrees in this project yet"
? "No existing worktrees found."
: null;

const parsed = useMemo(() => parseEnvironmentValue(value), [value]);
Expand Down Expand Up @@ -133,7 +133,7 @@ export function EnvironmentPickerUI({
icon: "Laptop" as const,
};
}
if (parsed.type === "reuse") {
if (parsed.type === "reuse" || parsed.type === "worktree-path") {
return {
modeLabel: "Reuse worktree",
compactModeLabel: "Reuse",
Expand Down Expand Up @@ -318,7 +318,9 @@ function EnvironmentOptionsSection({
label="Existing worktree"
description={reuseDisabledReason ?? undefined}
icon={getEnvironmentWorkspaceLabelIconName("managed-worktree")}
selected={selectedType === "reuse"}
selected={
selectedType === "reuse" || selectedType === "worktree-path"
}
disabled={reuseDisabledReason !== null}
onSelect={() => onChange(REUSE_VALUE_WITHOUT_ENVIRONMENT)}
/>
Expand Down Expand Up @@ -387,7 +389,9 @@ function MachineGroupedEnvironmentOptions({
label="Existing worktree"
description={reuseDisabledReason ?? undefined}
icon={getEnvironmentWorkspaceLabelIconName("managed-worktree")}
selected={selectedType === "reuse"}
selected={
selectedType === "reuse" || selectedType === "worktree-path"
}
disabled={reuseDisabledReason !== null}
onSelect={() => onChange(REUSE_VALUE_WITHOUT_ENVIRONMENT)}
/>
Expand Down
35 changes: 35 additions & 0 deletions apps/app/src/components/pickers/WorktreePicker.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// @vitest-environment jsdom

import { cleanup, fireEvent, render, screen } from "@testing-library/react";
import { afterEach, describe, expect, it, vi } from "vitest";
import { WorktreePicker } from "./WorktreePicker";

afterEach(() => {
cleanup();
vi.clearAllMocks();
});

describe("WorktreePicker", () => {
it("applies viewport-aware vertical overflow constraints to the menu", () => {
render(
<WorktreePicker
options={[]}
failures={[]}
value={null}
onChange={vi.fn()}
modal={false}
/>,
);

fireEvent.pointerDown(screen.getByRole("button", { name: "Worktree" }), {
button: 0,
});

const menu = screen.getByRole("menu");
expect(menu.className).toContain(
"max-h-[var(--radix-dropdown-menu-content-available-height)]",
);
expect(menu.className).toContain("overflow-y-auto");
expect(menu.className).toContain("overscroll-contain");
});
});
Loading