CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
Blame · Line-by-line history
useRepo.ts
Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.
| c53cf00 | 1 | import { useState, useEffect, useCallback } from 'react'; |
| 2 | import { api, type Repository, type Commit, type TreeEntry, type FileContent, type Branch } from '../api/client'; | |
| 3 | ||
| 4 | export function useUserRepos(username: string | null) { | |
| 5 | const [repos, setRepos] = useState<Repository[]>([]); | |
| 6 | const [loading, setLoading] = useState(false); | |
| 7 | const [error, setError] = useState<string | null>(null); | |
| 8 | ||
| 9 | const fetch = useCallback(async () => { | |
| 10 | if (!username) return; | |
| 11 | setLoading(true); | |
| 12 | setError(null); | |
| 13 | try { | |
| 14 | const data = await api.listUserRepos(username); | |
| 15 | setRepos(data); | |
| 16 | } catch (err) { | |
| 17 | setError(err instanceof Error ? err.message : 'Failed to load repos'); | |
| 18 | } finally { | |
| 19 | setLoading(false); | |
| 20 | } | |
| 21 | }, [username]); | |
| 22 | ||
| 23 | useEffect(() => { | |
| 24 | fetch(); | |
| 25 | }, [fetch]); | |
| 26 | ||
| 27 | return { repos, loading, error, refresh: fetch }; | |
| 28 | } | |
| 29 | ||
| 30 | export function useRepo(owner: string | null, repo: string | null) { | |
| 31 | const [data, setData] = useState<Repository | null>(null); | |
| 32 | const [loading, setLoading] = useState(false); | |
| 33 | const [error, setError] = useState<string | null>(null); | |
| 34 | ||
| 35 | const fetch = useCallback(async () => { | |
| 36 | if (!owner || !repo) return; | |
| 37 | setLoading(true); | |
| 38 | setError(null); | |
| 39 | try { | |
| 40 | const result = await api.getRepo(owner, repo); | |
| 41 | setData(result); | |
| 42 | } catch (err) { | |
| 43 | setError(err instanceof Error ? err.message : 'Failed to load repo'); | |
| 44 | } finally { | |
| 45 | setLoading(false); | |
| 46 | } | |
| 47 | }, [owner, repo]); | |
| 48 | ||
| 49 | useEffect(() => { | |
| 50 | fetch(); | |
| 51 | }, [fetch]); | |
| 52 | ||
| 53 | return { repo: data, loading, error, refresh: fetch }; | |
| 54 | } | |
| 55 | ||
| 56 | export function useCommits(owner: string | null, repoName: string | null, branch?: string) { | |
| 57 | const [commits, setCommits] = useState<Commit[]>([]); | |
| 58 | const [loading, setLoading] = useState(false); | |
| 59 | const [error, setError] = useState<string | null>(null); | |
| 60 | ||
| 61 | const fetch = useCallback(async () => { | |
| 62 | if (!owner || !repoName) return; | |
| 63 | setLoading(true); | |
| 64 | setError(null); | |
| 65 | try { | |
| 66 | const data = await api.listCommits(owner, repoName, branch); | |
| 67 | setCommits(data); | |
| 68 | } catch (err) { | |
| 69 | setError(err instanceof Error ? err.message : 'Failed to load commits'); | |
| 70 | } finally { | |
| 71 | setLoading(false); | |
| 72 | } | |
| 73 | }, [owner, repoName, branch]); | |
| 74 | ||
| 75 | useEffect(() => { | |
| 76 | fetch(); | |
| 77 | }, [fetch]); | |
| 78 | ||
| 79 | return { commits, loading, error, refresh: fetch }; | |
| 80 | } | |
| 81 | ||
| 82 | export function useFileTree(owner: string | null, repoName: string | null, ref: string, path?: string) { | |
| 83 | const [tree, setTree] = useState<TreeEntry[]>([]); | |
| 84 | const [loading, setLoading] = useState(false); | |
| 85 | const [error, setError] = useState<string | null>(null); | |
| 86 | ||
| 87 | const fetch = useCallback(async () => { | |
| 88 | if (!owner || !repoName) return; | |
| 89 | setLoading(true); | |
| 90 | setError(null); | |
| 91 | try { | |
| 92 | const data = await api.getFileTree(owner, repoName, ref, path); | |
| 93 | setTree(data); | |
| 94 | } catch (err) { | |
| 95 | setError(err instanceof Error ? err.message : 'Failed to load file tree'); | |
| 96 | } finally { | |
| 97 | setLoading(false); | |
| 98 | } | |
| 99 | }, [owner, repoName, ref, path]); | |
| 100 | ||
| 101 | useEffect(() => { | |
| 102 | fetch(); | |
| 103 | }, [fetch]); | |
| 104 | ||
| 105 | return { tree, loading, error, refresh: fetch }; | |
| 106 | } | |
| 107 | ||
| 108 | export function useFileContent(owner: string, repoName: string, filePath: string, ref = 'HEAD') { | |
| 109 | const [file, setFile] = useState<FileContent | null>(null); | |
| 110 | const [loading, setLoading] = useState(false); | |
| 111 | const [error, setError] = useState<string | null>(null); | |
| 112 | ||
| 113 | useEffect(() => { | |
| 114 | setLoading(true); | |
| 115 | setError(null); | |
| 116 | api.getFileContent(owner, repoName, filePath, ref) | |
| 117 | .then(setFile) | |
| 118 | .catch((err) => setError(err instanceof Error ? err.message : 'Failed to load file')) | |
| 119 | .finally(() => setLoading(false)); | |
| 120 | }, [owner, repoName, filePath, ref]); | |
| 121 | ||
| 122 | return { file, loading, error }; | |
| 123 | } | |
| 124 | ||
| 125 | export function useBranches(owner: string | null, repoName: string | null) { | |
| 126 | const [branches, setBranches] = useState<Branch[]>([]); | |
| 127 | const [loading, setLoading] = useState(false); | |
| 128 | const [error, setError] = useState<string | null>(null); | |
| 129 | ||
| 130 | useEffect(() => { | |
| 131 | if (!owner || !repoName) return; | |
| 132 | setLoading(true); | |
| 133 | api.listBranches(owner, repoName) | |
| 134 | .then(setBranches) | |
| 135 | .catch((err) => setError(err instanceof Error ? err.message : 'Failed to load branches')) | |
| 136 | .finally(() => setLoading(false)); | |
| 137 | }, [owner, repoName]); | |
| 138 | ||
| 139 | return { branches, loading, error }; | |
| 140 | } |