From eca43549d7eb648878fedb9f646241ea837c71ca Mon Sep 17 00:00:00 2001 From: Ben Allfree Date: Wed, 22 Apr 2026 19:48:27 -0700 Subject: [PATCH] feat: implement tag refresh validation and loading state in RepoPage --- src/pages/RepoPage.tsx | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/pages/RepoPage.tsx b/src/pages/RepoPage.tsx index 3e4a32c..0d541f0 100644 --- a/src/pages/RepoPage.tsx +++ b/src/pages/RepoPage.tsx @@ -92,6 +92,8 @@ export default function RepoPage() { const [resolvedSha, setResolvedSha] = useState(null) const [refError, setRefError] = useState(null) + const [pendingTagRefreshValidation, setPendingTagRefreshValidation] = useState(false) + const [isRefreshingTags, setIsRefreshingTags] = useState(false) useEffect(() => { if (!owner || !repo || !effectiveRef) return let cancelled = false @@ -109,6 +111,20 @@ export default function RepoPage() { } }, [owner, repo, effectiveRef, resolveRef]) + useEffect(() => { + if (!pendingTagRefreshValidation || !sourceRef || tagData === undefined) return + setPendingTagRefreshValidation(false) + const tags = tagData.row?.tags ?? [] + const defaultBranch = (tagData.row as { defaultBranch?: string } | null | undefined)?.defaultBranch + const normalizedSourceRef = sourceRef.toLowerCase() + const refStillExists = + tags.some(t => t.name.toLowerCase() === normalizedSourceRef) || + defaultBranch?.toLowerCase() === normalizedSourceRef + if (!refStillExists) { + navigate(`/${ownerParam}/${repoParam}`, { replace: true }) + } + }, [pendingTagRefreshValidation, sourceRef, tagData, navigate, ownerParam, repoParam]) + useEffect(() => { if (!owner || !repo || !effectiveRef || !resolvedSha) return void ensureScan({ owner, repo, ref: effectiveRef, resolvedSourceSha: resolvedSha }).catch(e => @@ -772,10 +788,18 @@ export default function RepoPage() { size="sm" className="w-full border-slate-600 text-slate-300 hover:border-slate-500 hover:bg-slate-800 hover:text-white" title="Refresh tags from GitHub" - onClick={() => void refreshTags({ owner, repo }).catch(e => toast.error(String(e)))} + disabled={isRefreshingTags} + onClick={() => { + if (isRefreshingTags) return + setIsRefreshingTags(true) + void refreshTags({ owner, repo }) + .then(() => setPendingTagRefreshValidation(true)) + .catch(e => toast.error(String(e))) + .finally(() => setIsRefreshingTags(false)) + }} > - - Refresh tags + + {isRefreshingTags ? "Refreshing…" : "Refresh tags"}