From 8884f507656411af3bb9d849eca22411ca73884a Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Sun, 12 Jul 2026 12:30:13 -0700 Subject: [PATCH] FN-7868: add Commit and Push button to Git Manager changes panel Adds a one-click commit-and-push affordance to the Git Manager modal's Changes panel, letting users commit staged changes and immediately push the active branch without a separate step. - Add handleCommitAndPush callback in GitManagerModal that reuses createCommit and pushBranch, refreshes file changes/status on success, and surfaces a distinct toast (with the local commit hash preserved) if the push step fails after a successful commit - Wire commitAndPush through to ChangesPanel and render a new "Commit and Push" button beside the existing Commit button, disabled while committing, when the message is empty, or when there are no staged files - Add test coverage for the commit-and-push flow, including the partial-failure case where commit succeeds but push fails - Add a minor changeset documenting the new Git Manager feature Files changed: .changeset/fn-7868-git-manager-commit-push.md | 7 +++ .../dashboard/app/components/GitManagerModal.tsx | 64 +++++++++++++++++++- .../components/__tests__/GitManagerModal.test.tsx | 68 ++++++++++++++++++++++ 3 files changed, 138 insertions(+), 1 deletion(-) Fusion-Task-Id: FN-7868 Fusion-Task-Lineage: 8b6913db-6f2a-45ab-b99d-a5c11ce53439 Co-authored-by: Fusion (runfusion.ai) --- .changeset/fn-7868-git-manager-commit-push.md | 7 ++ .../app/components/GitManagerModal.tsx | 64 ++++++++++++++++- .../__tests__/GitManagerModal.test.tsx | 68 +++++++++++++++++++ 3 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 .changeset/fn-7868-git-manager-commit-push.md diff --git a/.changeset/fn-7868-git-manager-commit-push.md b/.changeset/fn-7868-git-manager-commit-push.md new file mode 100644 index 0000000000..36b306a413 --- /dev/null +++ b/.changeset/fn-7868-git-manager-commit-push.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": minor +--- + +summary: Add a Commit and Push button to the Git Manager commit form. +category: feature +dev: Adds a GitManagerModal commit-and-push handler that reuses createCommit and pushBranch. diff --git a/packages/dashboard/app/components/GitManagerModal.tsx b/packages/dashboard/app/components/GitManagerModal.tsx index 6ba26484e4..4ecfe502ef 100644 --- a/packages/dashboard/app/components/GitManagerModal.tsx +++ b/packages/dashboard/app/components/GitManagerModal.tsx @@ -560,7 +560,55 @@ export function GitManagerModal({ isOpen, onClose, tasks: _tasks, addToast, proj } finally { setCommitting(false); } - }, [commitMessage, addToast, projectId, t]); + }, [commitMessage, addToast, projectId, gitRepoPath, t]); + + /* + FNXC:GitManager 2026-07-12-00:00: + The Changes commit form needs a one-click path that commits currently staged changes and immediately pushes the active branch using the existing git client APIs, while preserving the commit message when only the push fails so the local commit context remains visible. + */ + const handleCommitAndPush = useCallback(async () => { + const trimmedMessage = commitMessage.trim(); + if (!trimmedMessage) return; + + setCommitting(true); + let commitHash: string | null = null; + try { + const commitResult = await createCommit(trimmedMessage, projectId, gitRepoPath); + commitHash = commitResult.hash; + addToast(t("git.committedHash", "Committed: {{hash}}", { hash: commitResult.hash }), "success"); + + const pushResult = await pushBranch(projectId, gitRepoPath); + setLastRemoteResult(pushResult); + addToast(pushResult.message || t("git.pushCompleted", "Push completed"), "success"); + setCommitMessage(""); + + const [changes, statusData] = await Promise.all([fetchFileChanges(projectId, gitRepoPath), fetchGitStatus(projectId, { extended: true }, gitRepoPath)]); + setFileChanges(changes); + setStatus(statusData); + setSelectedDiffTarget(null); + setChangeDiff(null); + setChangeDiffError(null); + } catch (err) { + if (commitHash) { + const errorMessage = getErrorMessage(err) || t("git.pushFailed", "Push failed"); + addToast(t("git.commitSucceededPushFailed", "Committed locally ({{hash}}), but push failed: {{message}}", { hash: commitHash, message: errorMessage }), "error"); + try { + const [changes, statusData] = await Promise.all([fetchFileChanges(projectId, gitRepoPath), fetchGitStatus(projectId, { extended: true }, gitRepoPath)]); + setFileChanges(changes); + setStatus(statusData); + setSelectedDiffTarget(null); + setChangeDiff(null); + setChangeDiffError(null); + } catch { + // Keep the push failure toast as the actionable user-facing error. + } + } else { + addToast(getErrorMessage(err) || t("git.failedToCommit", "Failed to commit"), "error"); + } + } finally { + setCommitting(false); + } + }, [commitMessage, addToast, projectId, gitRepoPath, t]); const handleStageAllAndCommit = useCallback(async () => { if (!commitMessage.trim()) return; @@ -1194,6 +1242,7 @@ export function GitManagerModal({ isOpen, onClose, tasks: _tasks, addToast, proj commitMessage={commitMessage} setCommitMessage={setCommitMessage} onCommit={handleCommit} + onCommitAndPush={handleCommitAndPush} onStageAllAndCommit={handleStageAllAndCommit} committing={committing} /> @@ -1758,6 +1807,7 @@ function ChangesPanel({ commitMessage, setCommitMessage, onCommit, + onCommitAndPush, onStageAllAndCommit, committing, }: { @@ -1777,6 +1827,7 @@ function ChangesPanel({ commitMessage: string; setCommitMessage: (msg: string) => void; onCommit: (e: React.FormEvent) => void; + onCommitAndPush: () => void; onStageAllAndCommit: () => void; committing: boolean; }) { @@ -2012,6 +2063,17 @@ function ChangesPanel({ {committing ? : } {t("git.commit", "Commit")} + {/* FNXC:GitManager 2026-07-12-00:00: Expose the staged-only commit-then-push affordance beside Commit without making it a second primary action, so the established commit hierarchy stays intact. */} + {unstagedFiles.length > 0 && (