chore(web): Change carousel and repository list links to link to file tree (#528)

This commit is contained in:
Brendan Kellam 2025-09-20 16:52:44 -07:00 committed by GitHub
parent 5073c7db22
commit e1b6239e2c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 41 additions and 40 deletions

View file

@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed ### Changed
- Improved repository query performance by adding db indices. [#526](https://github.com/sourcebot-dev/sourcebot/pull/526) - Improved repository query performance by adding db indices. [#526](https://github.com/sourcebot-dev/sourcebot/pull/526)
- Improved repository query performance by removing JOIN on `Connection` table. [#527](https://github.com/sourcebot-dev/sourcebot/pull/527) - Improved repository query performance by removing JOIN on `Connection` table. [#527](https://github.com/sourcebot-dev/sourcebot/pull/527)
- Changed repo carousel and repo list links to redirect to the file browser. [#528](https://github.com/sourcebot-dev/sourcebot/pull/528)
## [4.7.1] - 2025-09-19 ## [4.7.1] - 2025-09-19

View file

@ -11,6 +11,9 @@ import Image from "next/image";
import { FileIcon } from "@radix-ui/react-icons"; import { FileIcon } from "@radix-ui/react-icons";
import clsx from "clsx"; import clsx from "clsx";
import { RepositoryQuery } from "@/lib/types"; import { RepositoryQuery } from "@/lib/types";
import { getBrowsePath } from "../../browse/hooks/useBrowseNavigation";
import Link from "next/link";
import { useDomain } from "@/hooks/useDomain";
interface RepositoryCarouselProps { interface RepositoryCarouselProps {
repos: RepositoryQuery[]; repos: RepositoryQuery[];
@ -56,7 +59,8 @@ interface RepositoryBadgeProps {
const RepositoryBadge = ({ const RepositoryBadge = ({
repo repo
}: RepositoryBadgeProps) => { }: RepositoryBadgeProps) => {
const { repoIcon, displayName, repoLink } = (() => { const domain = useDomain();
const { repoIcon, displayName } = (() => {
const info = getCodeHostInfoForRepo({ const info = getCodeHostInfoForRepo({
codeHostType: repo.codeHostType, codeHostType: repo.codeHostType,
name: repo.repoName, name: repo.repoName,
@ -72,32 +76,30 @@ const RepositoryBadge = ({
className={`w-4 h-4 ${info.iconClassName}`} className={`w-4 h-4 ${info.iconClassName}`}
/>, />,
displayName: info.displayName, displayName: info.displayName,
repoLink: info.repoLink,
} }
} }
return { return {
repoIcon: <FileIcon className="w-4 h-4" />, repoIcon: <FileIcon className="w-4 h-4" />,
displayName: repo.repoName, displayName: repo.repoName,
repoLink: undefined,
} }
})(); })();
return ( return (
<div <Link
onClick={() => { href={getBrowsePath({
if (repoLink !== undefined) { repoName: repo.repoName,
window.open(repoLink, "_blank"); path: '/',
} pathType: 'tree',
}} domain
className={clsx("flex flex-row items-center gap-2 border rounded-md p-2 text-clip", {
"cursor-pointer": repoLink !== undefined,
})} })}
className={clsx("flex flex-row items-center gap-2 border rounded-md p-2 text-clip")}
> >
{repoIcon} {repoIcon}
<span className="text-sm font-mono"> <span className="text-sm font-mono">
{displayName} {displayName}
</span> </span>
</div> </Link>
) )
} }

View file

@ -2,20 +2,22 @@
import { Button } from "@/components/ui/button" import { Button } from "@/components/ui/button"
import type { ColumnDef } from "@tanstack/react-table" import type { ColumnDef } from "@tanstack/react-table"
import { ArrowUpDown, ExternalLink, Clock, Loader2, CheckCircle2, XCircle, Trash2, Check, ListFilter } from "lucide-react" import { ArrowUpDown, Clock, Loader2, CheckCircle2, XCircle, Trash2, Check, ListFilter } from "lucide-react"
import Image from "next/image" import Image from "next/image"
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip" import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"
import { cn, getRepoImageSrc } from "@/lib/utils" import { cn, getRepoImageSrc } from "@/lib/utils"
import { RepoIndexingStatus } from "@sourcebot/db"; import { RepoIndexingStatus } from "@sourcebot/db";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"
import Link from "next/link"
import { getBrowsePath } from "../browse/hooks/useBrowseNavigation"
export type RepositoryColumnInfo = { export type RepositoryColumnInfo = {
repoId: number repoId: number
name: string repoName: string;
repoDisplayName: string
imageUrl?: string imageUrl?: string
repoIndexingStatus: RepoIndexingStatus repoIndexingStatus: RepoIndexingStatus
lastIndexed: string lastIndexed: string
url: string
} }
const statusLabels = { const statusLabels = {
@ -90,42 +92,38 @@ const StatusIndicator = ({ status }: { status: RepoIndexingStatus }) => {
export const columns = (domain: string): ColumnDef<RepositoryColumnInfo>[] => [ export const columns = (domain: string): ColumnDef<RepositoryColumnInfo>[] => [
{ {
accessorKey: "name", accessorKey: "repoDisplayName",
header: 'Repository', header: 'Repository',
cell: ({ row }) => { cell: ({ row: { original: { repoId, repoName, repoDisplayName, imageUrl } } }) => {
const repo = row.original
const url = repo.url
const isRemoteRepo = url.length > 0
return ( return (
<div className="flex flex-row items-center gap-3 py-2"> <div className="flex flex-row items-center gap-3 py-2">
<div className="relative h-8 w-8 overflow-hidden rounded-md border bg-muted"> <div className="relative h-8 w-8 overflow-hidden rounded-md border bg-muted">
{repo.imageUrl ? ( {imageUrl ? (
<Image <Image
src={getRepoImageSrc(repo.imageUrl, repo.repoId, domain) || "/placeholder.svg"} src={getRepoImageSrc(imageUrl, repoId, domain) || "/placeholder.svg"}
alt={`${repo.name} logo`} alt={`${repoDisplayName} logo`}
width={32} width={32}
height={32} height={32}
className="object-cover" className="object-cover"
/> />
) : ( ) : (
<div className="flex h-full w-full items-center justify-center bg-muted text-xs font-medium uppercase text-muted-foreground"> <div className="flex h-full w-full items-center justify-center bg-muted text-xs font-medium uppercase text-muted-foreground">
{repo.name.charAt(0)} {repoDisplayName.charAt(0)}
</div> </div>
)} )}
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<span <Link
className={isRemoteRepo ? "font-medium text-primary hover:underline cursor-pointer" : "font-medium"} className={"font-medium text-primary hover:underline cursor-pointer"}
onClick={() => { href={getBrowsePath({
if (isRemoteRepo) { repoName: repoName,
window.open(url, "_blank") path: '/',
} pathType: 'tree',
}} domain
})}
> >
{repo.name.length > 40 ? `${repo.name.slice(0, 40)}...` : repo.name} {repoDisplayName.length > 40 ? `${repoDisplayName.slice(0, 40)}...` : repoDisplayName}
</span> </Link>
{isRemoteRepo && <ExternalLink className="h-3.5 w-3.5 text-muted-foreground" />}
</div> </div>
</div> </div>
) )

View file

@ -37,21 +37,21 @@ export const RepositoryTable = ({
const tableRepos = useMemo(() => { const tableRepos = useMemo(() => {
if (reposLoading) return Array(4).fill(null).map(() => ({ if (reposLoading) return Array(4).fill(null).map(() => ({
repoId: 0, repoId: 0,
name: "", repoName: "",
repoDisplayName: "",
repoIndexingStatus: RepoIndexingStatus.NEW, repoIndexingStatus: RepoIndexingStatus.NEW,
lastIndexed: "", lastIndexed: "",
url: "",
imageUrl: "", imageUrl: "",
})); }));
if (!repos) return []; if (!repos) return [];
return repos.map((repo): RepositoryColumnInfo => ({ return repos.map((repo): RepositoryColumnInfo => ({
repoId: repo.repoId, repoId: repo.repoId,
name: repo.repoDisplayName ?? repo.repoName, repoName: repo.repoName,
repoDisplayName: repo.repoDisplayName ?? repo.repoName,
imageUrl: repo.imageUrl, imageUrl: repo.imageUrl,
repoIndexingStatus: repo.repoIndexingStatus as RepoIndexingStatus, repoIndexingStatus: repo.repoIndexingStatus as RepoIndexingStatus,
lastIndexed: repo.indexedAt?.toISOString() ?? "", lastIndexed: repo.indexedAt?.toISOString() ?? "",
url: repo.webUrl ?? repo.repoCloneUrl,
})).sort((a, b) => { })).sort((a, b) => {
const getPriorityFromStatus = (status: RepoIndexingStatus) => { const getPriorityFromStatus = (status: RepoIndexingStatus) => {
switch (status) { switch (status) {
@ -119,7 +119,7 @@ export const RepositoryTable = ({
<DataTable <DataTable
columns={tableColumns} columns={tableColumns}
data={tableRepos} data={tableRepos}
searchKey="name" searchKey="repoDisplayName"
searchPlaceholder="Search repositories..." searchPlaceholder="Search repositories..."
headerActions={isAddReposButtonVisible && ( headerActions={isAddReposButtonVisible && (
<Button <Button