Skip to content
Merged
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
16 changes: 16 additions & 0 deletions apps/web/src/components/GitActionsControl.logic.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
requiresDefaultBranchConfirmation,
resolveAutoFeatureBranchName,
resolveDefaultBranchActionDialogCopy,
resolveFeatureBranchUnavailableReason,
resolveGitActionProgressPresentation,
resolveGitActionResultToastTiming,
resolveLiveThreadBranchUpdate,
Expand Down Expand Up @@ -1025,6 +1026,21 @@ describe("resolveDefaultBranchActionDialogCopy", () => {
});
});

describe("resolveFeatureBranchUnavailableReason", () => {
it("blocks the feature branch when there is nothing to commit", () => {
assert.equal(
resolveFeatureBranchUnavailableReason({ branchName: "main", hasWorkingTreeChanges: false }),
"There are no changes to commit, so a feature branch can't be named. Create a branch yourself or continue on main.",
);
});

it("allows the feature branch when there are changes to commit", () => {
assert.isNull(
resolveFeatureBranchUnavailableReason({ branchName: "main", hasWorkingTreeChanges: true }),
);
});
});

describe("buildGitActionProgressStages", () => {
it("shows only push progress for explicit push actions", () => {
const stages = buildGitActionProgressStages({
Expand Down
12 changes: 12 additions & 0 deletions apps/web/src/components/GitActionsControl.logic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,18 @@ export function resolveDefaultBranchActionDialogCopy(input: {
};
}

/**
* Why the default-ref dialog cannot check out a feature branch, or null when it can.
* The server names that branch from the uncommitted changes, so a clean tree cannot use it.
*/
export function resolveFeatureBranchUnavailableReason(input: {
branchName: string;
hasWorkingTreeChanges: boolean;
}): string | null {
if (input.hasWorkingTreeChanges) return null;
return `There are no changes to commit, so a feature branch can't be named. Create a branch yourself or continue on ${input.branchName}.`;
}

export function resolveThreadBranchUpdate(
result: GitRunStackedActionResult,
): { branch: string } | null {
Expand Down
15 changes: 14 additions & 1 deletion apps/web/src/components/GitActionsControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import {
type DefaultBranchConfirmableAction,
requiresDefaultBranchConfirmation,
resolveDefaultBranchActionDialogCopy,
resolveFeatureBranchUnavailableReason,
resolveGitActionProgressPresentation,
resolveGitActionResultToastTiming,
resolveLiveThreadBranchUpdate,
Expand Down Expand Up @@ -1224,6 +1225,15 @@ export default function GitActionsControl({
terminology: changeRequestTerminology,
})
: null;
// Follows the live status so the button tracks the tree while the dialog is open. Until the
// status loads, keep the option enabled: the server stays the authority and rejects a stale
// request with its own error.
const featureBranchUnavailableReason = pendingDefaultBranchAction
? resolveFeatureBranchUnavailableReason({
branchName: pendingDefaultBranchAction.branchName,
hasWorkingTreeChanges: gitStatus?.hasWorkingTreeChanges ?? true,
})
: null;

useEffect(() => {
if (gitCwd === null) {
Expand Down Expand Up @@ -2117,6 +2127,9 @@ export default function GitActionsControl({
{pendingDefaultBranchActionCopy?.title ?? "Run action on default branch?"}
</DialogTitle>
<DialogDescription>{pendingDefaultBranchActionCopy?.description}</DialogDescription>
{featureBranchUnavailableReason && (
<p className="text-xs text-muted-foreground">{featureBranchUnavailableReason}</p>
)}
</DialogHeader>
<DialogFooter variant="bare" className="sm:flex-wrap sm:items-center">
<Button
Expand All @@ -2140,7 +2153,7 @@ export default function GitActionsControl({
className="w-full max-w-full sm:w-auto"
size="sm-multiline"
onClick={checkoutFeatureBranchAndContinuePendingAction}
disabled={!canChangeThreadBranch}
disabled={!canChangeThreadBranch || featureBranchUnavailableReason !== null}
>
Check out feature branch & continue
</Button>
Expand Down
Loading