fix: Fix repo carousel thrashing (#294)

This commit is contained in:
Brendan Kellam 2025-05-06 10:44:14 -07:00 committed by GitHub
parent eb10d599f3
commit b280e2ddbb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 45 additions and 17 deletions

View file

@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
### Fixed
- Fixes bug with repos not being visible in the homepage carousel when re-indexing. [#294](https://github.com/sourcebot-dev/sourcebot/pull/294)
### Added ### Added
- Added special `*` value for `rev:` to allow searching across all branches. [#281](https://github.com/sourcebot-dev/sourcebot/pull/281) - Added special `*` value for `rev:` to allow searching across all branches. [#281](https://github.com/sourcebot-dev/sourcebot/pull/281)

View file

@ -15,14 +15,24 @@ import {
} from "@/components/ui/carousel"; } from "@/components/ui/carousel";
import { RepoIndexingStatus } from "@sourcebot/db"; import { RepoIndexingStatus } from "@sourcebot/db";
import { SymbolIcon } from "@radix-ui/react-icons"; import { SymbolIcon } from "@radix-ui/react-icons";
import { RepositoryQuery } from "@/lib/types";
export function RepositorySnapshot({ authEnabled }: { authEnabled: boolean }) { interface RepositorySnapshotProps {
authEnabled: boolean;
repos: RepositoryQuery[];
}
export function RepositorySnapshot({
authEnabled,
repos: initialRepos,
}: RepositorySnapshotProps) {
const domain = useDomain(); const domain = useDomain();
const { data: repos, isPending, isError } = useQuery({ const { data: repos, isPending, isError } = useQuery({
queryKey: ['repos', domain], queryKey: ['repos', domain],
queryFn: () => unwrapServiceError(getRepos(domain)), queryFn: () => unwrapServiceError(getRepos(domain)),
refetchInterval: env.NEXT_PUBLIC_POLLING_INTERVAL_MS, refetchInterval: env.NEXT_PUBLIC_POLLING_INTERVAL_MS,
placeholderData: initialRepos,
}); });
if (isPending || isError || !repos) { if (isPending || isError || !repos) {
@ -33,22 +43,30 @@ export function RepositorySnapshot({ authEnabled }: { authEnabled: boolean }) {
) )
} }
const numIndexedRepos = repos.filter((repo) => repo.repoIndexingStatus === RepoIndexingStatus.INDEXED).length; // Use `indexedAt` to determine if a repo has __ever__ been indexed.
const numIndexingRepos = repos.filter((repo) => repo.repoIndexingStatus === RepoIndexingStatus.INDEXING || repo.repoIndexingStatus === RepoIndexingStatus.IN_INDEX_QUEUE).length; // The repo indexing status only tells us the repo's current indexing status.
if (numIndexedRepos === 0 && numIndexingRepos > 0) { const indexedRepos = repos.filter((repo) => repo.indexedAt !== undefined);
return (
<div className="flex flex-row items-center gap-3"> // If there are no indexed repos...
<SymbolIcon className="h-4 w-4 animate-spin" /> if (indexedRepos.length === 0) {
<span className="text-sm">indexing in progress...</span>
</div> // ... show a loading state if repos are being indexed now
) if (repos.some((repo) => repo.repoIndexingStatus === RepoIndexingStatus.INDEXING || repo.repoIndexingStatus === RepoIndexingStatus.IN_INDEX_QUEUE)) {
} else if (numIndexedRepos == 0) { return (
return ( <div className="flex flex-row items-center gap-3">
<EmptyRepoState domain={domain} authEnabled={authEnabled} /> <SymbolIcon className="h-4 w-4 animate-spin" />
) <span className="text-sm">indexing in progress...</span>
</div>
)
// ... otherwise, show the empty state.
} else {
return (
<EmptyRepoState domain={domain} authEnabled={authEnabled} />
)
}
} }
const indexedRepos = repos.filter((repo) => repo.repoIndexingStatus === RepoIndexingStatus.INDEXED);
return ( return (
<div className="flex flex-col items-center gap-3"> <div className="flex flex-col items-center gap-3">
<span className="text-sm"> <span className="text-sm">
@ -57,7 +75,7 @@ export function RepositorySnapshot({ authEnabled }: { authEnabled: boolean }) {
href={`${domain}/repos`} href={`${domain}/repos`}
className="text-blue-500" className="text-blue-500"
> >
{repos.length > 1 ? 'repositories' : 'repository'} {indexedRepos.length > 1 ? 'repositories' : 'repository'}
</Link> </Link>
</span> </span>
<RepositoryCarousel repos={indexedRepos} /> <RepositoryCarousel repos={indexedRepos} />

View file

@ -10,6 +10,8 @@ import { SourcebotLogo } from "../components/sourcebotLogo";
import { RepositorySnapshot } from "./components/repositorySnapshot"; import { RepositorySnapshot } from "./components/repositorySnapshot";
import { SyntaxReferenceGuideHint } from "./components/syntaxReferenceGuideHint"; import { SyntaxReferenceGuideHint } from "./components/syntaxReferenceGuideHint";
import { env } from '@/env.mjs'; import { env } from '@/env.mjs';
import { getRepos } from "@/actions";
import { isServiceError } from "@/lib/utils";
export default async function Home({ params: { domain } }: { params: { domain: string } }) { export default async function Home({ params: { domain } }: { params: { domain: string } }) {
const org = await getOrgFromDomain(domain); const org = await getOrgFromDomain(domain);
@ -17,6 +19,8 @@ export default async function Home({ params: { domain } }: { params: { domain: s
return <PageNotFound /> return <PageNotFound />
} }
const repos = await getRepos(domain);
return ( return (
<div className="flex flex-col items-center overflow-hidden min-h-screen"> <div className="flex flex-col items-center overflow-hidden min-h-screen">
<NavigationMenu <NavigationMenu
@ -34,7 +38,10 @@ export default async function Home({ params: { domain } }: { params: { domain: s
className="mt-4 w-full max-w-[800px]" className="mt-4 w-full max-w-[800px]"
/> />
<div className="mt-8"> <div className="mt-8">
<RepositorySnapshot authEnabled={env.SOURCEBOT_AUTH_ENABLED === 'true'} /> <RepositorySnapshot
authEnabled={env.SOURCEBOT_AUTH_ENABLED === 'true'}
repos={isServiceError(repos) ? [] : repos}
/>
</div> </div>
<div className="flex flex-col items-center w-fit gap-6"> <div className="flex flex-col items-center w-fit gap-6">
<Separator className="mt-5" /> <Separator className="mt-5" />