diff --git a/apps/web/src/components/BranchToolbar.tsx b/apps/web/src/components/BranchToolbar.tsx index c39631921..a398cfcc9 100644 --- a/apps/web/src/components/BranchToolbar.tsx +++ b/apps/web/src/components/BranchToolbar.tsx @@ -1,7 +1,9 @@ import type { ThreadId } from "@okcode/contracts"; -import { FolderIcon, GitForkIcon } from "lucide-react"; +import { ArrowDownIcon, FolderIcon, GitForkIcon, LoaderIcon } from "lucide-react"; import { useCallback } from "react"; +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import { gitPullMutationOptions, gitStatusQueryOptions, invalidateGitQueries } from "../lib/gitReactQuery"; import { newCommandId } from "../lib/utils"; import { readNativeApi } from "../nativeApi"; import { useComposerDraftStore } from "../composerDraftStore"; @@ -13,8 +15,10 @@ import { } from "./BranchToolbar.logic"; import { Badge } from "./ui/badge"; import { BranchToolbarBranchSelector } from "./BranchToolbarBranchSelector"; +import { Button } from "./ui/button"; import { Select, SelectItem, SelectPopup, SelectTrigger, SelectValue } from "./ui/select"; import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip"; +import { toastManager } from "./ui/toast"; const envModeItems = [ { value: "local", label: "Local" }, @@ -110,6 +114,39 @@ export default function BranchToolbar({ ], ); + const queryClient = useQueryClient(); + const gitCwd = activeWorktreePath ?? activeProject?.cwd ?? null; + const gitStatus = useQuery(gitStatusQueryOptions(gitCwd)); + const behindCount = gitStatus.data?.behindCount ?? 0; + const isBehindUpstream = behindCount > 0 && !hasServerThread; + const pullMutation = useMutation(gitPullMutationOptions({ cwd: gitCwd, queryClient })); + + const handlePull = useCallback(() => { + if (pullMutation.isPending) return; + const promise = pullMutation.mutateAsync(); + void promise + .then((result) => { + toastManager.add({ + type: "success", + title: result.status === "pulled" ? "Pulled" : "Already up to date", + description: + result.status === "pulled" + ? `Updated ${result.branch} from ${result.upstreamBranch ?? "upstream"}.` + : "Branch is already up to date.", + }); + }) + .catch((error) => { + toastManager.add({ + type: "error", + title: "Pull failed", + description: error instanceof Error ? error.message : "An error occurred.", + }); + }) + .finally(() => { + void invalidateGitQueries(queryClient); + }); + }, [pullMutation, queryClient]); + if (!activeThreadId || !activeProject) return null; return ( @@ -160,17 +197,47 @@ export default function BranchToolbar({ )}