Skip to content

Commit 593d744

Browse files
authored
feat(branch-selector): show trunk + loading row in the open cloud picker
Seed the known default ("trunk") branch as a real, pickable list item in the cloud branch picker while the remote branch list is still loading, with a "Loading branches…" row rendered directly below it. This makes the open dropdown usable for the common "start on trunk" case with zero wait, and signals that the rest of the branches are still on the way. Only seeds when there's no active search — once the user types, the list is purely what the remote returns. Generated-By: PostHog Code Task-Id: 562fb90f-d823-425d-b53c-5f482b55a8b2
1 parent 2504d1d commit 593d744

2 files changed

Lines changed: 68 additions & 1 deletion

File tree

packages/ui/src/features/git-interaction/components/BranchSelector.test.tsx

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,50 @@ describe("BranchSelector cloud mode", () => {
7575
expect(screen.getByRole("combobox", { name: "Branch" })).toBeEnabled();
7676
});
7777

78+
it("seeds the default branch as a pickable item with a loading row while the cloud list loads", async () => {
79+
const user = userEvent.setup();
80+
renderInTheme(
81+
<BranchSelector
82+
repoPath="owner/repo"
83+
currentBranch={null}
84+
defaultBranch="main"
85+
workspaceMode="cloud"
86+
cloudBranches={[]}
87+
cloudBranchesLoading={true}
88+
cloudSearchQuery=""
89+
selectedBranch="main"
90+
onBranchSelect={vi.fn()}
91+
onCloudSearchChange={vi.fn()}
92+
/>,
93+
);
94+
95+
await user.click(screen.getByRole("combobox", { name: "Branch" }));
96+
97+
expect(await screen.findByRole("option", { name: "main" })).toBeVisible();
98+
expect(screen.getByText("Loading branches…")).toBeVisible();
99+
});
100+
101+
it("does not seed the default branch once the user is searching", async () => {
102+
const user = userEvent.setup();
103+
renderInTheme(
104+
<BranchSelector
105+
repoPath="owner/repo"
106+
currentBranch={null}
107+
defaultBranch="main"
108+
workspaceMode="cloud"
109+
cloudBranches={[]}
110+
cloudBranchesLoading={true}
111+
cloudSearchQuery="feat"
112+
onBranchSelect={vi.fn()}
113+
onCloudSearchChange={vi.fn()}
114+
/>,
115+
);
116+
117+
await user.click(screen.getByRole("combobox", { name: "Branch" }));
118+
119+
expect(screen.queryByRole("option", { name: "main" })).toBeNull();
120+
});
121+
78122
it("surfaces the 'Use input as branch name' action when the typed value is new", async () => {
79123
const user = userEvent.setup();
80124
renderInTheme(

packages/ui/src/features/git-interaction/components/BranchSelector.tsx

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,12 +175,28 @@ export function BranchSelector({
175175
return byBranch;
176176
}, [repoCheckouts]);
177177

178-
const branches = isCloudMode ? (cloudBranches ?? []) : localBranches;
178+
const liveBranches = isCloudMode ? (cloudBranches ?? []) : localBranches;
179179
const effectiveLoading = loading || (isCloudMode && cloudBranchesLoading);
180180
const branchListLoading = isCloudMode
181181
? !!cloudBranchesLoading
182182
: localBranchesLoading;
183183

184+
// On a cold start the live cloud branch list is still empty while the (slow)
185+
// remote fetch runs. Surface the known default ("trunk") branch as a real
186+
// list item straight away — with a loading row rendered below it — so the
187+
// common "start on trunk" case is pickable with zero wait. Only when there's
188+
// no active search: once the user types, the results should be purely what
189+
// the remote returns.
190+
const seededDefaultBranch =
191+
isCloudMode &&
192+
branchListLoading &&
193+
liveBranches.length === 0 &&
194+
!!defaultBranch &&
195+
!(cloudSearchQuery ?? "").trim()
196+
? defaultBranch
197+
: null;
198+
const branches = seededDefaultBranch ? [seededDefaultBranch] : liveBranches;
199+
184200
const checkoutMutation = useMutation({
185201
...trpc.git.checkoutBranch.mutationOptions(),
186202
onSuccess: () => {
@@ -519,6 +535,13 @@ export function BranchSelector({
519535
}}
520536
</ComboboxList>
521537

538+
{/*
539+
Cold start: the default ("trunk") branch is seeded as the only list
540+
item while the remote list loads. A loading row directly below it
541+
makes clear the rest of the branches are still on the way.
542+
*/}
543+
{seededDefaultBranch ? <LoadingRow label="Loading branches…" /> : null}
544+
522545
{isCloudMode && cloudBranchesHasMore ? (
523546
<ComboboxListFooter>
524547
<div className="px-2 pb-2">

0 commit comments

Comments
 (0)