Skip to content

Commit 08df01f

Browse files
CyberT17CyberT17brendan-kellam
authored
feat(web): Added Trigger Sync to /repos dropdown menu (#710)
* feat(web): Added Trigger Sync to /repos dropdown menu Co-authored-by: CyberT17 <Kevin.Patel@nisc.coop> Co-authored-by: Brendan Kellam <bshizzle1234@gmail.com>
1 parent fd2d377 commit 08df01f

File tree

3 files changed

+107
-44
lines changed

3 files changed

+107
-44
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
### Changed
1111
- Changed the default `/repos` pagination size to 20. [#706](https://github.com/sourcebot-dev/sourcebot/pull/706)
1212
- Changed pull policy in docker compose file to always. [#716](https://github.com/sourcebot-dev/sourcebot/pull/716)
13+
- Added Trigger Sync to /repos dropdown menu [#710](https://github.com/sourcebot-dev/sourcebot/pull/710)
1314

1415
### Fixed
1516
- Add warning logs when local repo index fails to match pattern. [#712](https://github.com/sourcebot-dev/sourcebot/pull/712)
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
"use client"
2+
3+
import { Button } from "@/components/ui/button"
4+
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"
5+
import { SINGLE_TENANT_ORG_DOMAIN } from "@/lib/constants"
6+
import { getCodeHostInfoForRepo, isServiceError } from "@/lib/utils"
7+
import { ExternalLink, MoreHorizontal } from "lucide-react"
8+
import Link from "next/link"
9+
import { useState } from "react"
10+
import { indexRepo } from "@/features/workerApi/actions"
11+
import { useRouter } from "next/navigation"
12+
import { useToast } from "@/components/hooks/use-toast"
13+
import type { Repo } from "./reposTable"
14+
15+
interface RepoActionsDropdownProps {
16+
repo: Repo
17+
}
18+
19+
export const RepoActionsDropdown = ({ repo }: RepoActionsDropdownProps) => {
20+
const [isSyncing, setIsSyncing] = useState(false)
21+
const router = useRouter()
22+
const { toast } = useToast()
23+
24+
const codeHostInfo = getCodeHostInfoForRepo({
25+
codeHostType: repo.codeHostType,
26+
name: repo.name,
27+
displayName: repo.displayName ?? undefined,
28+
webUrl: repo.webUrl ?? undefined,
29+
})
30+
31+
const handleTriggerSync = async () => {
32+
setIsSyncing(true)
33+
const response = await indexRepo(repo.id)
34+
35+
if (!isServiceError(response)) {
36+
const { jobId } = response
37+
toast({
38+
description: `✅ Repository sync triggered successfully. Job ID: ${jobId}`,
39+
})
40+
router.refresh()
41+
} else {
42+
toast({
43+
description: `❌ Failed to sync repository. ${response.message}`,
44+
})
45+
}
46+
47+
setIsSyncing(false)
48+
}
49+
50+
return (
51+
<DropdownMenu>
52+
<DropdownMenuTrigger asChild>
53+
<Button variant="ghost" className="h-8 w-8 p-0">
54+
<span className="sr-only">Open menu</span>
55+
<MoreHorizontal className="h-4 w-4" />
56+
</Button>
57+
</DropdownMenuTrigger>
58+
<DropdownMenuContent align="end">
59+
<DropdownMenuLabel>Actions</DropdownMenuLabel>
60+
<DropdownMenuItem asChild>
61+
<Link href={`/${SINGLE_TENANT_ORG_DOMAIN}/repos/${repo.id}`}>View details</Link>
62+
</DropdownMenuItem>
63+
<DropdownMenuItem
64+
onClick={handleTriggerSync}
65+
disabled={isSyncing}
66+
>
67+
Trigger sync
68+
</DropdownMenuItem>
69+
{repo.webUrl && (
70+
<>
71+
<DropdownMenuSeparator />
72+
<DropdownMenuItem asChild>
73+
<a href={repo.webUrl} target="_blank" rel="noopener noreferrer" className="flex items-center">
74+
Open in {codeHostInfo.codeHostName}
75+
<ExternalLink className="ml-2 h-3 w-3" />
76+
</a>
77+
</DropdownMenuItem>
78+
</>
79+
)}
80+
</DropdownMenuContent>
81+
</DropdownMenu>
82+
)
83+
}

packages/web/src/app/[domain]/repos/components/reposTable.tsx

Lines changed: 23 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,11 @@
22

33
import { Badge } from "@/components/ui/badge"
44
import { Button } from "@/components/ui/button"
5-
import {
6-
DropdownMenu,
7-
DropdownMenuContent,
8-
DropdownMenuItem,
9-
DropdownMenuLabel,
10-
DropdownMenuSeparator,
11-
DropdownMenuTrigger,
12-
} from "@/components/ui/dropdown-menu"
135
import { InputGroup, InputGroupAddon, InputGroupInput } from "@/components/ui/input-group"
146
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
157
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
168
import { SINGLE_TENANT_ORG_DOMAIN } from "@/lib/constants"
17-
import { cn, getCodeHostCommitUrl, getCodeHostIcon, getCodeHostInfoForRepo, getRepoImageSrc } from "@/lib/utils"
9+
import { cn, getCodeHostCommitUrl, getCodeHostIcon, getRepoImageSrc, isServiceError } from "@/lib/utils"
1810
import {
1911
type ColumnDef,
2012
type VisibilityState,
@@ -23,7 +15,7 @@ import {
2315
useReactTable,
2416
} from "@tanstack/react-table"
2517
import { cva } from "class-variance-authority"
26-
import { ArrowDown, ArrowUp, ArrowUpDown, ExternalLink, Loader2, MoreHorizontal, RefreshCwIcon } from "lucide-react"
18+
import { ArrowDown, ArrowUp, ArrowUpDown, Loader2, RefreshCwIcon } from "lucide-react"
2719
import Image from "next/image"
2820
import Link from "next/link"
2921
import { useEffect, useRef, useState } from "react"
@@ -35,6 +27,8 @@ import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip
3527
import { NotificationDot } from "../../components/notificationDot"
3628
import { CodeHostType } from "@sourcebot/db"
3729
import { useHotkeys } from "react-hotkeys-hook"
30+
import { indexRepo } from "@/features/workerApi/actions"
31+
import { RepoActionsDropdown } from "./repoActionsDropdown"
3832

3933
// @see: https://v0.app/chat/repo-indexing-status-uhjdDim8OUS
4034

@@ -84,6 +78,7 @@ interface ColumnsContext {
8478
onSortChange: (sortBy: string) => void;
8579
currentSortBy?: string;
8680
currentSortOrder: string;
81+
onTriggerSync: (repoId: number) => void;
8782
}
8883

8984
export const getColumns = (context: ColumnsContext): ColumnDef<Repo>[] => [
@@ -253,40 +248,7 @@ export const getColumns = (context: ColumnsContext): ColumnDef<Repo>[] => [
253248
enableHiding: false,
254249
cell: ({ row }) => {
255250
const repo = row.original
256-
const codeHostInfo = getCodeHostInfoForRepo({
257-
codeHostType: repo.codeHostType,
258-
name: repo.name,
259-
displayName: repo.displayName ?? undefined,
260-
webUrl: repo.webUrl ?? undefined,
261-
});
262-
263-
return (
264-
<DropdownMenu>
265-
<DropdownMenuTrigger asChild>
266-
<Button variant="ghost" className="h-8 w-8 p-0">
267-
<span className="sr-only">Open menu</span>
268-
<MoreHorizontal className="h-4 w-4" />
269-
</Button>
270-
</DropdownMenuTrigger>
271-
<DropdownMenuContent align="end">
272-
<DropdownMenuLabel>Actions</DropdownMenuLabel>
273-
<DropdownMenuItem asChild>
274-
<Link href={`/${SINGLE_TENANT_ORG_DOMAIN}/repos/${repo.id}`}>View details</Link>
275-
</DropdownMenuItem>
276-
{repo.webUrl && (
277-
<>
278-
<DropdownMenuSeparator />
279-
<DropdownMenuItem asChild>
280-
<a href={repo.webUrl} target="_blank" rel="noopener noreferrer" className="flex items-center">
281-
Open in {codeHostInfo.codeHostName}
282-
<ExternalLink className="ml-2 h-3 w-3" />
283-
</a>
284-
</DropdownMenuItem>
285-
</>
286-
)}
287-
</DropdownMenuContent>
288-
</DropdownMenu>
289-
)
251+
return <RepoActionsDropdown repo={repo} />
290252
},
291253
},
292254
]
@@ -386,12 +348,29 @@ export const ReposTable = ({
386348
router.replace(`${pathname}?${params.toString()}`);
387349
};
388350

351+
const handleTriggerSync = async (repoId: number) => {
352+
const response = await indexRepo(repoId);
353+
354+
if (!isServiceError(response)) {
355+
const { jobId } = response;
356+
toast({
357+
description: `✅ Repository sync triggered successfully. Job ID: ${jobId}`,
358+
});
359+
router.refresh();
360+
} else {
361+
toast({
362+
description: `❌ Failed to sync repository. ${response.message}`,
363+
});
364+
}
365+
};
366+
389367
const totalPages = Math.ceil(totalCount / pageSize);
390368

391369
const columns = getColumns({
392370
onSortChange: handleSortChange,
393371
currentSortBy: initialSortBy,
394372
currentSortOrder: initialSortOrder,
373+
onTriggerSync: handleTriggerSync
395374
});
396375

397376
const table = useReactTable({

0 commit comments

Comments
 (0)