Repository navigation
feat(bounties): sort by upvotes, link existing repositories, organization select #36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -250,6 +250,54 @@ export function scaffoldRepository(requestId: string, options: ScaffoldOptions) | |
| }); | ||
| } | ||
|
|
||
| export interface LinkedRepo { | ||
| repoUrl: string; | ||
| fullName: string; | ||
| submitUrl: string; | ||
| claimers: LiveRequest['claimers']; | ||
| } | ||
|
|
||
| /** Records a repository the claimer already maintains as the work for their claim. */ | ||
| export function linkRepository(requestId: string, repoUrl: string) { | ||
| return postAction<LinkedRepo>(`/api/requests/${encodeURIComponent(requestId)}/repo`, { | ||
| repoUrl, | ||
| returnTo: window.location.href.split('#')[0], | ||
| }); | ||
| } | ||
|
|
||
| export interface RepoOwner { | ||
| login: string; | ||
| type: 'user' | 'org'; | ||
| } | ||
|
|
||
| /** The visitor's GitHub account first, then their organizations, or null when unavailable. */ | ||
| export async function fetchRepoOwners(): Promise<RepoOwner[] | null> { | ||
| try { | ||
| const res = await fetch(`${TABULARIUM_URL}/api/submit/owners`, {credentials: 'include'}); | ||
| if (!res.ok) return null; | ||
| return ((await res.json()) as {owners: RepoOwner[]}).owners; | ||
| } catch { | ||
| return null; | ||
| } | ||
| } | ||
|
|
||
| export interface MaintainedRepo { | ||
| fullName: string; | ||
| url: string; | ||
| } | ||
|
|
||
| /** Repositories the visitor can maintain on their linked accounts (first page of each), or null on failure. */ | ||
| export async function fetchMaintainedRepos(): Promise<MaintainedRepo[] | null> { | ||
| try { | ||
| const res = await fetch(`${TABULARIUM_URL}/api/submit/repos?page=1`, {credentials: 'include'}); | ||
| if (!res.ok) return null; | ||
| const body = (await res.json()) as {groups: Array<{repos: MaintainedRepo[]}>}; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. SUGGESTION: Fragile API response assumption
|
||
| return body.groups.flatMap((group) => group.repos.map(({fullName, url}) => ({fullName, url}))); | ||
| } catch { | ||
| return null; | ||
| } | ||
| } | ||
|
|
||
| /** Local alternative to the hosted scaffold, for any forge. */ | ||
| export function localScaffoldCommand(slug: string, kind: string | null): string { | ||
| return kind === 'theme' | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SUGGESTION: useEffect caches failed fetches permanently
The effect only runs when
repos === null. If the first fetch fails,reposbecomes[](line 297 in requests.ts) and the effect never runs again when re-entering 'link' mode. User can still paste a URL manually, but suggestions won't refresh.Consider using a separate
reposLoadedboolean flag or allowing retry on mode change.