mirror of
https://github.com/lukaszraczylo/ghtracker.git
synced 2026-10-14 00:58:36 +00:00
feat: refresh a single repository from its own button (#2)
* feat(refresh): refresh a single repository with POST /refresh?repo= The endpoint refreshes one configured repository and returns the full state plus the repo name. Each repository has a 60-second cooldown that is separate from the full-refresh limit. A running full refresh or a refresh of the same repository returns 409. An unknown repository returns 404. Cross-site and disabled-config behaviour stay the same. The collector reuses its fetch path and replaces only that repository. * feat(ui): add a refresh button beside each repository The button appears in the project list and in each attention group header. It stays hidden when the server disables manual refresh. The button shows a spinner while its repository refreshes and reports refusals in the notice line. The store swaps in the returned state, so no extra fetch follows.
This commit is contained in:
+19
-1
@@ -1,4 +1,4 @@
|
||||
import type { TrackerState } from './types'
|
||||
import type { RepoRefreshResult, TrackerState } from './types'
|
||||
|
||||
export async function fetchState(signal?: AbortSignal): Promise<TrackerState> {
|
||||
const res = await fetch('/api/state', { signal, headers: { Accept: 'application/json' } })
|
||||
@@ -14,3 +14,21 @@ export async function requestRefresh(): Promise<void> {
|
||||
if (res.status === 429) throw new RescanLimitedError('Rescan is limited to once every 5 minutes')
|
||||
if (!res.ok) throw new Error(`rescan request failed: HTTP ${res.status}`)
|
||||
}
|
||||
|
||||
/** Thrown when one repository was refreshed too recently or a scan is running. */
|
||||
export class RepoRefreshRefusedError extends Error {}
|
||||
|
||||
const REPO_COOLDOWN_FALLBACK_SECONDS = 60
|
||||
|
||||
/** Refreshes one repository and returns the full state after it, plus the repo name. */
|
||||
export async function requestRepoRefresh(fullName: string): Promise<RepoRefreshResult> {
|
||||
const res = await fetch(`/refresh?repo=${encodeURIComponent(fullName)}`, { method: 'POST' })
|
||||
if (res.status === 429) {
|
||||
const wait = Number(res.headers.get('Retry-After')) || REPO_COOLDOWN_FALLBACK_SECONDS
|
||||
throw new RepoRefreshRefusedError(`${fullName} was refreshed recently. Try again in ${wait}s`)
|
||||
}
|
||||
if (res.status === 409)
|
||||
throw new RepoRefreshRefusedError('A refresh is already running. Try again shortly')
|
||||
if (!res.ok) throw new Error(`refresh of ${fullName} failed: HTTP ${res.status}`)
|
||||
return (await res.json()) as RepoRefreshResult
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user