mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-01-11 22:40:26 +01:00
169 lines
5.7 KiB
TypeScript
169 lines
5.7 KiB
TypeScript
import { useQuery } from '@tanstack/react-query';
|
|
import { invoke } from '@tauri-apps/api/core';
|
|
import { createFastMutation } from '@yaakapp/app/hooks/useFastMutation';
|
|
import { queryClient } from '@yaakapp/app/lib/queryClient';
|
|
import { useMemo } from 'react';
|
|
import { GitCommit, GitRemote, GitStatusSummary, PullResult, PushResult } from './bindings/gen_git';
|
|
|
|
export * from './bindings/gen_git';
|
|
|
|
export interface GitCredentials {
|
|
username: string;
|
|
password: string;
|
|
}
|
|
|
|
export interface GitCallbacks {
|
|
addRemote: () => Promise<GitRemote | null>;
|
|
promptCredentials: (
|
|
result: Extract<PushResult, { type: 'needs_credentials' }>,
|
|
) => Promise<GitCredentials | null>;
|
|
}
|
|
|
|
const onSuccess = () => queryClient.invalidateQueries({ queryKey: ['git'] });
|
|
|
|
export function useGit(dir: string, callbacks: GitCallbacks) {
|
|
const mutations = useMemo(() => gitMutations(dir, callbacks), [dir, callbacks]);
|
|
return [
|
|
{
|
|
remotes: useQuery<GitRemote[], string>({
|
|
queryKey: ['git', 'remotes', dir],
|
|
queryFn: () => getRemotes(dir),
|
|
}),
|
|
log: useQuery<GitCommit[], string>({
|
|
queryKey: ['git', 'log', dir],
|
|
queryFn: () => invoke('cmd_git_log', { dir }),
|
|
}),
|
|
status: useQuery<GitStatusSummary, string>({
|
|
refetchOnMount: true,
|
|
queryKey: ['git', 'status', dir],
|
|
queryFn: () => invoke('cmd_git_status', { dir }),
|
|
}),
|
|
},
|
|
mutations,
|
|
] as const;
|
|
}
|
|
|
|
export const gitMutations = (dir: string, callbacks: GitCallbacks) => {
|
|
const push = async () => {
|
|
const remotes = await getRemotes(dir);
|
|
if (remotes.length === 0) {
|
|
const remote = await callbacks.addRemote();
|
|
if (remote == null) throw new Error('No remote found');
|
|
}
|
|
|
|
const result = await invoke<PushResult>('cmd_git_push', { dir });
|
|
if (result.type !== 'needs_credentials') return result;
|
|
|
|
// Needs credentials, prompt for them
|
|
const creds = await callbacks.promptCredentials(result);
|
|
if (creds == null) throw new Error('Canceled');
|
|
|
|
await invoke('cmd_git_add_credential', {
|
|
dir,
|
|
remoteUrl: result.url,
|
|
username: creds.username,
|
|
password: creds.password,
|
|
});
|
|
|
|
// Push again
|
|
return invoke<PushResult>('cmd_git_push', { dir });
|
|
};
|
|
|
|
return {
|
|
init: createFastMutation<void, string, void>({
|
|
mutationKey: ['git', 'init'],
|
|
mutationFn: () => invoke('cmd_git_initialize', { dir }),
|
|
onSuccess,
|
|
}),
|
|
add: createFastMutation<void, string, { relaPaths: string[] }>({
|
|
mutationKey: ['git', 'add', dir],
|
|
mutationFn: (args) => invoke('cmd_git_add', { dir, ...args }),
|
|
onSuccess,
|
|
}),
|
|
addRemote: createFastMutation<GitRemote, string, GitRemote>({
|
|
mutationKey: ['git', 'add-remote'],
|
|
mutationFn: (args) => invoke('cmd_git_add_remote', { dir, ...args }),
|
|
onSuccess,
|
|
}),
|
|
rmRemote: createFastMutation<void, string, { name: string }>({
|
|
mutationKey: ['git', 'rm-remote', dir],
|
|
mutationFn: (args) => invoke('cmd_git_rm_remote', { dir, ...args }),
|
|
onSuccess,
|
|
}),
|
|
branch: createFastMutation<void, string, { branch: string }>({
|
|
mutationKey: ['git', 'branch', dir],
|
|
mutationFn: (args) => invoke('cmd_git_branch', { dir, ...args }),
|
|
onSuccess,
|
|
}),
|
|
mergeBranch: createFastMutation<void, string, { branch: string; force: boolean }>({
|
|
mutationKey: ['git', 'merge', dir],
|
|
mutationFn: (args) => invoke('cmd_git_merge_branch', { dir, ...args }),
|
|
onSuccess,
|
|
}),
|
|
deleteBranch: createFastMutation<void, string, { branch: string }>({
|
|
mutationKey: ['git', 'delete-branch', dir],
|
|
mutationFn: (args) => invoke('cmd_git_delete_branch', { dir, ...args }),
|
|
onSuccess,
|
|
}),
|
|
checkout: createFastMutation<string, string, { branch: string; force: boolean }>({
|
|
mutationKey: ['git', 'checkout', dir],
|
|
mutationFn: (args) => invoke('cmd_git_checkout', { dir, ...args }),
|
|
onSuccess,
|
|
}),
|
|
commit: createFastMutation<void, string, { message: string }>({
|
|
mutationKey: ['git', 'commit', dir],
|
|
mutationFn: (args) => invoke('cmd_git_commit', { dir, ...args }),
|
|
onSuccess,
|
|
}),
|
|
commitAndPush: createFastMutation<PushResult, string, { message: string }>({
|
|
mutationKey: ['git', 'commit_push', dir],
|
|
mutationFn: async (args) => {
|
|
await invoke('cmd_git_commit', { dir, ...args });
|
|
return push();
|
|
},
|
|
onSuccess,
|
|
}),
|
|
fetchAll: createFastMutation<string, string, void>({
|
|
mutationKey: ['git', 'checkout', dir],
|
|
mutationFn: () => invoke('cmd_git_fetch_all', { dir }),
|
|
onSuccess,
|
|
}),
|
|
push: createFastMutation<PushResult, string, void>({
|
|
mutationKey: ['git', 'push', dir],
|
|
mutationFn: push,
|
|
onSuccess,
|
|
}),
|
|
pull: createFastMutation<PullResult, string, void>({
|
|
mutationKey: ['git', 'pull', dir],
|
|
async mutationFn() {
|
|
const result = await invoke<PullResult>('cmd_git_pull', { dir });
|
|
if (result.type !== 'needs_credentials') return result;
|
|
|
|
// Needs credentials, prompt for them
|
|
const creds = await callbacks.promptCredentials(result);
|
|
if (creds == null) throw new Error('Canceled');
|
|
|
|
await invoke('cmd_git_add_credential', {
|
|
dir,
|
|
remoteUrl: result.url,
|
|
username: creds.username,
|
|
password: creds.password,
|
|
});
|
|
|
|
// Pull again
|
|
return invoke<PullResult>('cmd_git_pull', { dir });
|
|
},
|
|
onSuccess,
|
|
}),
|
|
unstage: createFastMutation<void, string, { relaPaths: string[] }>({
|
|
mutationKey: ['git', 'unstage', dir],
|
|
mutationFn: (args) => invoke('cmd_git_unstage', { dir, ...args }),
|
|
onSuccess,
|
|
}),
|
|
} as const;
|
|
};
|
|
|
|
async function getRemotes(dir: string) {
|
|
return invoke<GitRemote[]>('cmd_git_remotes', { dir });
|
|
}
|