fix: show Push button when task has open PR and unpushed commits (#537)

This commit is contained in:
Carlos Florêncio
2026-04-03 15:03:05 +01:00
committed by GitHub
parent 7e97e07c2d
commit 12310e12ba
3 changed files with 355 additions and 20 deletions
+50 -20
View File
@@ -27,6 +27,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from "@kandev/ui/tooltip";
import { useSessionGit } from "@/hooks/domains/session/use-session-git";
import { useGitWithFeedback } from "@/hooks/use-git-with-feedback";
import { useVcsDialogs } from "@/components/vcs/vcs-dialogs";
import { useActiveTaskPR } from "@/hooks/domains/github/use-task-pr";
import type { ReactNode } from "react";
@@ -34,8 +35,10 @@ function determinePrimaryAction(
uncommittedFileCount: number,
aheadCount: number,
behindCount: number,
): "commit" | "pr" | "rebase" {
hasOpenPR: boolean,
): "commit" | "push" | "pr" | "rebase" {
if (uncommittedFileCount > 0) return "commit";
if (aheadCount > 0 && hasOpenPR) return "push";
if (aheadCount > 0) return "pr";
if (behindCount > 0) return "rebase";
return "commit";
@@ -75,6 +78,16 @@ function buildPrConfig(aheadCount: number, openPRDialog: () => void): PrimaryBut
};
}
function buildPushConfig(aheadCount: number, handlePush: () => void): PrimaryButtonConfig {
return {
icon: <IconCloudUpload className="h-4 w-4" />,
label: "Push",
badge: aheadCount > 0 ? aheadCount : null,
tooltip: `Push ${aheadCount} commit${aheadCount !== 1 ? "s" : ""} to remote`,
onClick: handlePush,
};
}
function buildRebaseConfig(
behindCount: number,
baseBranch: string | undefined,
@@ -90,13 +103,14 @@ function buildRebaseConfig(
}
type PrimaryConfigArgs = {
primaryAction: "commit" | "pr" | "rebase";
primaryAction: "commit" | "push" | "pr" | "rebase";
uncommittedFileCount: number;
aheadCount: number;
behindCount: number;
baseBranch: string | undefined;
openCommitDialog: () => void;
openPRDialog: () => void;
handlePush: () => void;
handleRebase: () => void;
};
@@ -108,8 +122,10 @@ function buildPrimaryButtonConfig({
baseBranch,
openCommitDialog,
openPRDialog,
handlePush,
handleRebase,
}: PrimaryConfigArgs): PrimaryButtonConfig {
if (primaryAction === "push") return buildPushConfig(aheadCount, handlePush);
if (primaryAction === "pr") return buildPrConfig(aheadCount, openPRDialog);
if (primaryAction === "rebase") return buildRebaseConfig(behindCount, baseBranch, handleRebase);
return buildCommitConfig(uncommittedFileCount, openCommitDialog);
@@ -205,24 +221,8 @@ type VcsSplitButtonProps = {
baseBranch?: string;
};
const VcsSplitButton = memo(function VcsSplitButton({
sessionId,
baseBranch,
}: VcsSplitButtonProps) {
function useGitActions(git: ReturnType<typeof useSessionGit>, baseBranch?: string) {
const gitWithFeedback = useGitWithFeedback();
const git = useSessionGit(sessionId);
const { openCommitDialog, openPRDialog } = useVcsDialogs();
const currentBranch = git.branch;
const remoteBranch = git.remoteBranch;
const hasMatchingUpstream =
remoteBranch && currentBranch && remoteBranch === `origin/${currentBranch}`;
const uncommittedFileCount = git.allFiles.length;
const aheadCount = git.ahead;
const behindCount = git.behind;
const isDisabled = git.isLoading || !sessionId;
const isGitLoading = git.isLoading;
const handlePull = useCallback(() => {
gitWithFeedback(() => git.pull(), "Pull");
@@ -245,7 +245,35 @@ const VcsSplitButton = memo(function VcsSplitButton({
gitWithFeedback(() => git.merge(targetBranch), "Merge");
}, [gitWithFeedback, git, baseBranch]);
const primaryAction = determinePrimaryAction(uncommittedFileCount, aheadCount, behindCount);
return { handlePull, handlePush, handleRebase, handleMerge };
}
const VcsSplitButton = memo(function VcsSplitButton({
sessionId,
baseBranch,
}: VcsSplitButtonProps) {
const git = useSessionGit(sessionId);
const { openCommitDialog, openPRDialog } = useVcsDialogs();
const activePR = useActiveTaskPR();
const hasOpenPR = activePR?.state === "open";
const { handlePull, handlePush, handleRebase, handleMerge } = useGitActions(git, baseBranch);
const currentBranch = git.branch;
const remoteBranch = git.remoteBranch;
const hasMatchingUpstream =
remoteBranch && currentBranch && remoteBranch === `origin/${currentBranch}`;
const uncommittedFileCount = git.allFiles.length;
const aheadCount = git.ahead;
const behindCount = git.behind;
const isDisabled = git.isLoading || !sessionId;
const isGitLoading = git.isLoading;
const primaryAction = determinePrimaryAction(
uncommittedFileCount,
aheadCount,
behindCount,
hasOpenPR,
);
const primaryButtonConfig = buildPrimaryButtonConfig({
primaryAction,
uncommittedFileCount,
@@ -254,6 +282,7 @@ const VcsSplitButton = memo(function VcsSplitButton({
baseBranch,
openCommitDialog,
openPRDialog,
handlePush: () => handlePush(false),
handleRebase,
});
@@ -267,6 +296,7 @@ const VcsSplitButton = memo(function VcsSplitButton({
className="rounded-none border-0 cursor-pointer"
onClick={primaryButtonConfig.onClick}
disabled={isDisabled}
data-testid={`vcs-primary-${primaryAction}`}
>
{primaryButtonConfig.icon}
{primaryButtonConfig.label}