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
8 changes: 6 additions & 2 deletions apps/web/src/components/GitActionsControl.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { type GitStatusResult, type GitStackedAction, type ThreadId } from "@t3tools/contracts";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { useIsMutating, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { useCallback, useEffect, useMemo, useState } from "react";
import { ChevronDownIcon, CloudUploadIcon, GitCommitIcon, InfoIcon } from "lucide-react";
import { GitHubIcon } from "./Icons";
Expand Down Expand Up @@ -33,6 +33,7 @@ import { toastManager } from "~/components/ui/toast";
import {
gitBranchesQueryOptions,
gitInitMutationOptions,
gitMutationKeys,
gitPullMutationOptions,
gitRunStackedActionMutationOptions,
gitStatusQueryOptions,
Expand Down Expand Up @@ -168,7 +169,10 @@ export default function GitActionsControl({ gitCwd, activeThreadId }: GitActions
);
const pullMutation = useMutation(gitPullMutationOptions({ cwd: gitCwd, queryClient }));

const isGitActionRunning = runImmediateGitActionMutation.isPending || pullMutation.isPending;
const isRunStackedActionRunning =
useIsMutating({ mutationKey: gitMutationKeys.runStackedAction(gitCwd) }) > 0;
const isPullRunning = useIsMutating({ mutationKey: gitMutationKeys.pull(gitCwd) }) > 0;
const isGitActionRunning = isRunStackedActionRunning || isPullRunning;
const isDefaultBranch = useMemo(() => {
const branchName = gitStatusForActions?.branch;
if (!branchName) return false;
Expand Down
33 changes: 33 additions & 0 deletions apps/web/src/lib/gitReactQuery.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { QueryClient } from "@tanstack/react-query";
import { describe, expect, it } from "vitest";
import {
gitMutationKeys,
gitPullMutationOptions,
gitRunStackedActionMutationOptions,
} from "./gitReactQuery";

describe("gitMutationKeys", () => {
it("scopes stacked action keys by cwd", () => {
expect(gitMutationKeys.runStackedAction("/repo/a")).not.toEqual(
gitMutationKeys.runStackedAction("/repo/b"),
);
});

it("scopes pull keys by cwd", () => {
expect(gitMutationKeys.pull("/repo/a")).not.toEqual(gitMutationKeys.pull("/repo/b"));
});
});

describe("git mutation options", () => {
const queryClient = new QueryClient();

it("attaches cwd-scoped mutation key for runStackedAction", () => {
const options = gitRunStackedActionMutationOptions({ cwd: "/repo/a", queryClient });
expect(options.mutationKey).toEqual(gitMutationKeys.runStackedAction("/repo/a"));
});

it("attaches cwd-scoped mutation key for pull", () => {
const options = gitPullMutationOptions({ cwd: "/repo/a", queryClient });
expect(options.mutationKey).toEqual(gitMutationKeys.pull("/repo/a"));
});
});
17 changes: 17 additions & 0 deletions apps/web/src/lib/gitReactQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ export const gitQueryKeys = {
branches: (cwd: string | null) => ["git", "branches", cwd] as const,
};

export const gitMutationKeys = {
init: (cwd: string | null) => ["git", "mutation", "init", cwd] as const,
checkout: (cwd: string | null) => ["git", "mutation", "checkout", cwd] as const,
createBranchAndCheckout: (cwd: string | null) =>
["git", "mutation", "create-branch-and-checkout", cwd] as const,
runStackedAction: (cwd: string | null) =>
["git", "mutation", "run-stacked-action", cwd] as const,
pull: (cwd: string | null) => ["git", "mutation", "pull", cwd] as const,
};

export function invalidateGitQueries(queryClient: QueryClient) {
return queryClient.invalidateQueries({ queryKey: gitQueryKeys.all });
}
Expand Down Expand Up @@ -51,6 +61,7 @@ export function gitBranchesQueryOptions(cwd: string | null) {

export function gitInitMutationOptions(input: { cwd: string | null; queryClient: QueryClient }) {
return mutationOptions({
mutationKey: gitMutationKeys.init(input.cwd),
mutationFn: async () => {
const api = ensureNativeApi();
if (!input.cwd) throw new Error("Git init is unavailable.");
Expand All @@ -67,6 +78,7 @@ export function gitCheckoutMutationOptions(input: {
queryClient: QueryClient;
}) {
return mutationOptions({
mutationKey: gitMutationKeys.checkout(input.cwd),
mutationFn: async (branch: string) => {
const api = ensureNativeApi();
if (!input.cwd) throw new Error("Git checkout is unavailable.");
Expand All @@ -83,6 +95,7 @@ export function gitCreateBranchAndCheckoutMutationOptions(input: {
queryClient: QueryClient;
}) {
return mutationOptions({
mutationKey: gitMutationKeys.createBranchAndCheckout(input.cwd),
mutationFn: async (branch: string) => {
const api = ensureNativeApi();
if (!input.cwd) throw new Error("Git branch creation is unavailable.");
Expand All @@ -100,6 +113,7 @@ export function gitRunStackedActionMutationOptions(input: {
queryClient: QueryClient;
}) {
return mutationOptions({
mutationKey: gitMutationKeys.runStackedAction(input.cwd),
mutationFn: async ({
action,
commitMessage,
Expand All @@ -123,6 +137,7 @@ export function gitRunStackedActionMutationOptions(input: {

export function gitPullMutationOptions(input: { cwd: string | null; queryClient: QueryClient }) {
return mutationOptions({
mutationKey: gitMutationKeys.pull(input.cwd),
mutationFn: async () => {
const api = ensureNativeApi();
if (!input.cwd) throw new Error("Git pull is unavailable.");
Expand Down Expand Up @@ -151,6 +166,7 @@ export function gitCreateWorktreeMutationOptions(input: { queryClient: QueryClie
if (!cwd) throw new Error("Git worktree creation is unavailable.");
return api.git.createWorktree({ cwd, branch, newBranch, path: path ?? null });
},
mutationKey: ["git", "mutation", "create-worktree"] as const,
onSettled: async () => {
await invalidateGitQueries(input.queryClient);
},
Expand All @@ -164,6 +180,7 @@ export function gitRemoveWorktreeMutationOptions(input: { queryClient: QueryClie
if (!cwd) throw new Error("Git worktree removal is unavailable.");
return api.git.removeWorktree({ cwd, path, force });
},
mutationKey: ["git", "mutation", "remove-worktree"] as const,
onSettled: async () => {
await invalidateGitQueries(input.queryClient);
},
Expand Down
Loading