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; promptCredentials: ( result: Extract, ) => Promise; } const onSuccess = () => queryClient.invalidateQueries({ queryKey: ['git'] }); export function useGit(dir: string, callbacks: GitCallbacks) { const mutations = useMemo(() => gitMutations(dir, callbacks), [dir, callbacks]); return [ { remotes: useQuery({ queryKey: ['git', 'remotes', dir], queryFn: () => getRemotes(dir), }), log: useQuery({ queryKey: ['git', 'log', dir], queryFn: () => invoke('plugin:yaak-git|log', { dir }), }), status: useQuery({ refetchOnMount: true, queryKey: ['git', 'status', dir], queryFn: () => invoke('plugin:yaak-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('plugin:yaak-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('plugin:yaak-git|add_credential', { dir, remoteUrl: result.url, username: creds.username, password: creds.password, }); // Push again return invoke('plugin:yaak-git|push', { dir }); }; return { init: createFastMutation({ mutationKey: ['git', 'init'], mutationFn: () => invoke('plugin:yaak-git|initialize', { dir }), onSuccess, }), add: createFastMutation({ mutationKey: ['git', 'add', dir], mutationFn: (args) => invoke('plugin:yaak-git|add', { dir, ...args }), onSuccess, }), addRemote: createFastMutation({ mutationKey: ['git', 'add-remote'], mutationFn: (args) => invoke('plugin:yaak-git|add_remote', { dir, ...args }), onSuccess, }), rmRemote: createFastMutation({ mutationKey: ['git', 'rm-remote', dir], mutationFn: (args) => invoke('plugin:yaak-git|rm_remote', { dir, ...args }), onSuccess, }), branch: createFastMutation({ mutationKey: ['git', 'branch', dir], mutationFn: (args) => invoke('plugin:yaak-git|branch', { dir, ...args }), onSuccess, }), mergeBranch: createFastMutation({ mutationKey: ['git', 'merge', dir], mutationFn: (args) => invoke('plugin:yaak-git|merge_branch', { dir, ...args }), onSuccess, }), deleteBranch: createFastMutation({ mutationKey: ['git', 'delete-branch', dir], mutationFn: (args) => invoke('plugin:yaak-git|delete_branch', { dir, ...args }), onSuccess, }), checkout: createFastMutation({ mutationKey: ['git', 'checkout', dir], mutationFn: (args) => invoke('plugin:yaak-git|checkout', { dir, ...args }), onSuccess, }), commit: createFastMutation({ mutationKey: ['git', 'commit', dir], mutationFn: (args) => invoke('plugin:yaak-git|commit', { dir, ...args }), onSuccess, }), commitAndPush: createFastMutation({ mutationKey: ['git', 'commit_push', dir], mutationFn: async (args) => { await invoke('plugin:yaak-git|commit', { dir, ...args }); return push(); }, onSuccess, }), fetchAll: createFastMutation({ mutationKey: ['git', 'checkout', dir], mutationFn: () => invoke('plugin:yaak-git|fetch_all', { dir }), onSuccess, }), push: createFastMutation({ mutationKey: ['git', 'push', dir], mutationFn: push, onSuccess, }), pull: createFastMutation({ mutationKey: ['git', 'pull', dir], async mutationFn() { const result = await invoke('plugin:yaak-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('plugin:yaak-git|add_credential', { dir, remoteUrl: result.url, username: creds.username, password: creds.password, }); // Pull again return invoke('plugin:yaak-git|pull', { dir }); }, onSuccess, }), unstage: createFastMutation({ mutationKey: ['git', 'unstage', dir], mutationFn: (args) => invoke('plugin:yaak-git|unstage', { dir, ...args }), onSuccess, }), } as const; }; async function getRemotes(dir: string) { return invoke('plugin:yaak-git|remotes', { dir }); }