import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { gitCommitLog, gitBranchList, gitTagList, gitBranchSummary, pullRequestList, gitTreeList, gitCommitGet, gitDiffTreeToTree, gitUpdateRepo, branchProtectionList, branchProtectionCreate, branchProtectionUpdate, branchProtectionDelete, projectRepos, } from "@/client/api"; const REPO_DETAIL_QUERY_KEY = "repoDetail"; const REPO_COMMITS_QUERY_KEY = "repoCommits"; const REPO_BRANCHES_QUERY_KEY = "repoBranches"; const REPO_TAGS_QUERY_KEY = "repoTags"; const REPO_BRANCH_SUMMARY_QUERY_KEY = "repoBranchSummary"; const REPO_PULLS_QUERY_KEY = "repoPulls"; const REPO_TREE_QUERY_KEY = "repoTree"; interface RepoParams { namespace: string; repo: string; } export function useRepoDetailQuery({ namespace, repo }: RepoParams) { return useQuery({ queryKey: [REPO_DETAIL_QUERY_KEY, namespace, repo], queryFn: async () => { return { namespace, repo }; }, enabled: !!namespace && !!repo, }); } interface RepoCommitsParams extends RepoParams { page?: number; perPage?: number; } export function useRepoCommitsQuery({ namespace, repo, page = 1, perPage = 20, }: RepoCommitsParams) { return useQuery({ queryKey: [REPO_COMMITS_QUERY_KEY, namespace, repo, page, perPage], queryFn: async () => { const res = await gitCommitLog(namespace, repo, { page, per_page: perPage }); const body = res.data.data as unknown as { data: unknown[]; total: number; total_pages: number } | undefined; const commits = body?.data ?? []; const total = body?.total ?? commits.length; return { commits, totalCount: total, page, totalPages: body?.total_pages ?? (Math.ceil(total / perPage) || 1), }; }, enabled: !!namespace && !!repo, }); } export function useRepoBranchesQuery({ namespace, repo }: RepoParams) { return useQuery({ queryKey: [REPO_BRANCHES_QUERY_KEY, namespace, repo], queryFn: async () => { const res = await gitBranchList(namespace, repo); return (res.data.data as unknown as // eslint-disable-next-line @typescript-eslint/no-explicit-any any[]) || []; }, enabled: !!namespace && !!repo, }); } export function useRepoTagsQuery({ namespace, repo }: RepoParams) { return useQuery({ queryKey: [REPO_TAGS_QUERY_KEY, namespace, repo], queryFn: async () => { const res = await gitTagList(namespace, repo); return (res.data.data as unknown as // eslint-disable-next-line @typescript-eslint/no-explicit-any any[]) || []; }, enabled: !!namespace && !!repo, }); } export function useRepoBranchSummaryQuery({ namespace, repo }: RepoParams) { return useQuery({ queryKey: [REPO_BRANCH_SUMMARY_QUERY_KEY, namespace, repo], queryFn: async () => { const res = await gitBranchSummary(namespace, repo); return (res.data.data as unknown as // eslint-disable-next-line @typescript-eslint/no-explicit-any any) || {}; }, enabled: !!namespace && !!repo, }); } export function useRepoPullsQuery({ namespace, repo }: RepoParams) { return useQuery({ queryKey: [REPO_PULLS_QUERY_KEY, namespace, repo], queryFn: async () => { const res = await pullRequestList(namespace, repo); return ((res.data.data as unknown as { pull_requests?: unknown[] })?.pull_requests ?? []) as unknown as // eslint-disable-next-line @typescript-eslint/no-explicit-any any[]; }, enabled: !!namespace && !!repo, }); } interface RepoTreeParams extends RepoParams { oid: string; } export function useRepoTreeQuery({ namespace, repo, oid }: RepoTreeParams) { return useQuery({ queryKey: [REPO_TREE_QUERY_KEY, namespace, repo, oid], queryFn: async () => { const res = await gitTreeList(namespace, repo, oid); return (res.data.data as unknown as // eslint-disable-next-line @typescript-eslint/no-explicit-any any[]) || []; }, enabled: !!namespace && !!repo && !!oid, }); } const REPO_COMMIT_DETAIL_QUERY_KEY = "repoCommitDetail"; const REPO_COMMIT_DIFF_QUERY_KEY = "repoCommitDiff"; export function useRepoCommitDetailQuery({ namespace, repo, oid }: RepoTreeParams) { return useQuery({ queryKey: [REPO_COMMIT_DETAIL_QUERY_KEY, namespace, repo, oid], queryFn: async () => { const res = await gitCommitGet(namespace, repo, oid); // eslint-disable-next-line @typescript-eslint/no-explicit-any return res.data.data as any; }, enabled: !!namespace && !!repo && !!oid, }); } export function useRepoCommitDiffQuery({ namespace, repo, oid, baseOid }: RepoTreeParams & { baseOid?: string }) { return useQuery({ queryKey: [REPO_COMMIT_DIFF_QUERY_KEY, namespace, repo, oid, baseOid], queryFn: async () => { const res = await gitDiffTreeToTree(namespace, repo, { old_tree: baseOid || "", new_tree: oid, }); // eslint-disable-next-line @typescript-eslint/no-explicit-any return res.data.data as any; }, enabled: !!namespace && !!repo && !!oid, }); } // Repo Settings Hooks export function useRepoInfoQuery({ namespace, repo }: RepoParams) { return useQuery({ queryKey: ["repoInfo", namespace, repo], queryFn: async () => { const res = await projectRepos(namespace); const items = res.data.data?.items ?? []; return items.find((item) => item.repo_name === repo) ?? null; }, enabled: !!namespace && !!repo, }); } export function useUpdateRepoSettingsMutation(namespace: string, repo: string) { const queryClient = useQueryClient(); return useMutation({ mutationFn: async (params: { name?: string; default_branch?: string; ai_code_review_enabled?: boolean; description?: string; is_private?: boolean; }) => { return gitUpdateRepo(namespace, repo, params); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: [REPO_DETAIL_QUERY_KEY, namespace, repo] }); queryClient.invalidateQueries({ queryKey: ["repoInfo", namespace, repo] }); }, }); } // Branch Protection Hooks const BRANCH_PROTECTION_QUERY_KEY = "branchProtection"; export function useBranchProtectionQuery({ namespace, repo }: RepoParams) { return useQuery({ queryKey: [BRANCH_PROTECTION_QUERY_KEY, namespace, repo], queryFn: async () => { const res = await branchProtectionList(namespace, repo); return (res.data.data as unknown as // eslint-disable-next-line @typescript-eslint/no-explicit-any any[]) || []; }, enabled: !!namespace && !!repo, }); } export function useCreateBranchProtectionMutation(namespace: string, repo: string) { const queryClient = useQueryClient(); return useMutation({ mutationFn: async (params: { branch: string; forbid_push?: boolean; forbid_pull?: boolean; forbid_merge?: boolean; forbid_deletion?: boolean; forbid_force_push?: boolean; forbid_tag_push?: boolean; required_approvals?: number; dismiss_stale_reviews?: boolean; require_linear_history?: boolean; allow_fork_syncing?: boolean; }) => { return branchProtectionCreate(namespace, repo, params); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: [BRANCH_PROTECTION_QUERY_KEY, namespace, repo] }); }, }); } export function useUpdateBranchProtectionMutation(namespace: string, repo: string) { const queryClient = useQueryClient(); return useMutation({ mutationFn: async ({ id, ...params }: { id: number; [key: string]: unknown }) => { return branchProtectionUpdate(namespace, repo, id, params); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: [BRANCH_PROTECTION_QUERY_KEY, namespace, repo] }); }, }); } export function useDeleteBranchProtectionMutation(namespace: string, repo: string) { const queryClient = useQueryClient(); return useMutation({ mutationFn: async (id: number) => { return branchProtectionDelete(namespace, repo, id); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: [BRANCH_PROTECTION_QUERY_KEY, namespace, repo] }); }, }); }