History

Extract branch sync logic and limit sync to local mode

- move branch-sync decision into `BranchToolbar.logic.ts` - avoid auto-sync when env mode is `worktree` or thread has worktree path - add unit tests for sync and no-sync cases

Julius Marminge committed 9 months ago

Commit 3756bbf1 parent 73fa2d63 files · +96 −6Browse files

Unified · Split

3 files
  1. apps/web/src/components/BranchToolbar.logic.test.ts +56 −0
  2. apps/web/src/components/BranchToolbar.logic.ts +28 −0
  3. apps/web/src/components/BranchToolbar.tsx +12 −6
apps/web/src/components/BranchToolbar.logic.test.ts+56−0
@@ -0,0 +1,56 @@
1import type { GitBranch } from "@t3tools/contracts";
2import { describe, expect, it } from "vitest";
3import { deriveSyncedLocalBranch } from "./BranchToolbar.logic";
4
5const branches: GitBranch[] = [
6 {
7 name: "main",
8 current: true,
9 isDefault: true,
10 worktreePath: null,
11 },
12 {
13 name: "feature/demo",
14 current: false,
15 isDefault: false,
16 worktreePath: null,
17 },
18];
19
20describe("deriveSyncedLocalBranch", () => {
21 it("syncs to git current branch in local mode", () => {
22 const result = deriveSyncedLocalBranch({
23 activeThreadId: "thread-1",
24 activeWorktreePath: null,
25 envMode: "local",
26 activeThreadBranch: "feature/demo",
27 queryBranches: branches,
28 });
29
30 expect(result).toBe("main");
31 });
32
33 it("does not sync when creating a new worktree", () => {
34 const result = deriveSyncedLocalBranch({
35 activeThreadId: "thread-1",
36 activeWorktreePath: null,
37 envMode: "worktree",
38 activeThreadBranch: "feature/demo",
39 queryBranches: branches,
40 });
41
42 expect(result).toBeNull();
43 });
44
45 it("does not sync when thread already targets a worktree path", () => {
46 const result = deriveSyncedLocalBranch({
47 activeThreadId: "thread-1",
48 activeWorktreePath: "/tmp/repo/worktrees/feature-demo",
49 envMode: "local",
50 activeThreadBranch: "feature/demo",
51 queryBranches: branches,
52 });
53
54 expect(result).toBeNull();
55 });
56});
apps/web/src/components/BranchToolbar.logic.ts+28−0
@@ -0,0 +1,28 @@
1import type { GitBranch } from "@t3tools/contracts";
2
3interface DeriveSyncedLocalBranchInput {
4 activeThreadId: string | undefined;
5 activeWorktreePath: string | null;
6 envMode: "local" | "worktree";
7 activeThreadBranch: string | null;
8 queryBranches: GitBranch[] | undefined;
9}
10
11export function deriveSyncedLocalBranch({
12 activeThreadId,
13 activeWorktreePath,
14 envMode,
15 activeThreadBranch,
16 queryBranches,
17}: DeriveSyncedLocalBranchInput): string | null {
18 if (!activeThreadId || activeWorktreePath || envMode !== "local") {
19 return null;
20 }
21
22 const currentBranch = queryBranches?.find((branch) => branch.current);
23 if (!currentBranch || currentBranch.name === activeThreadBranch) {
24 return null;
25 }
26
27 return currentBranch.name;
28}
apps/web/src/components/BranchToolbar.tsx+12−6
@@ -9,6 +9,7 @@ import { · 8 unmodified lines
9 gitCreateBranchAndCheckoutMutationOptions,9 gitCreateBranchAndCheckoutMutationOptions,
10} from "../lib/gitReactQuery";10} from "../lib/gitReactQuery";
11import { useStore } from "../store";11import { useStore } from "../store";
12import { deriveSyncedLocalBranch } from "./BranchToolbar.logic";
12import { Button } from "./ui/button";13import { Button } from "./ui/button";
13import {14import {
14 Combobox,15 Combobox,
@@ -86,17 +87,22 @@ export default function BranchToolbar({ · 71 unmodified lines
86 // Keep thread branch synced to git current branch for local threads.87 // Keep thread branch synced to git current branch for local threads.
87 const queryBranches = branchesQuery.data?.branches;88 const queryBranches = branchesQuery.data?.branches;
88 useEffect(() => {89 useEffect(() => {
89 if (!activeThreadId || activeWorktreePath) return;90 const syncedBranch = deriveSyncedLocalBranch({
90 const current = queryBranches?.find((branch) => branch.current);91 activeThreadId,
91 if (!current) return;92 activeWorktreePath,
92 if (current.name === activeThreadBranch) return;93 envMode,
94 activeThreadBranch,
95 queryBranches,
96 });
97 if (!syncedBranch) return;
98
93 dispatch({99 dispatch({
94 type: "SET_THREAD_BRANCH",100 type: "SET_THREAD_BRANCH",
95 threadId: activeThreadId,101 threadId: activeThreadId,
96 branch: current.name,102 branch: syncedBranch,
97 worktreePath: null,103 worktreePath: null,
98 });104 });
99 }, [activeThreadId, activeWorktreePath, activeThreadBranch, queryBranches, dispatch]);105 }, [activeThreadId, activeWorktreePath, activeThreadBranch, queryBranches, envMode, dispatch]);
100 106
101 useEffect(() => {107 useEffect(() => {
102 if (isBranchMenuOpen) return;108 if (isBranchMenuOpen) return;