mirror of
https://github.com/sourcebot-dev/sourcebot.git
synced 2025-12-12 12:25:22 +00:00
more touchups
This commit is contained in:
parent
39bcb09778
commit
cd54eb0b7b
3 changed files with 120 additions and 26 deletions
|
|
@ -1,18 +1,21 @@
|
||||||
import { Suspense } from "react"
|
import { sew } from "@/actions"
|
||||||
import { notFound } from "next/navigation"
|
|
||||||
import Link from "next/link"
|
|
||||||
import { ChevronLeft, ExternalLink } from "lucide-react"
|
|
||||||
import { Button } from "@/components/ui/button"
|
|
||||||
import { Badge } from "@/components/ui/badge"
|
import { Badge } from "@/components/ui/badge"
|
||||||
|
import { Button } from "@/components/ui/button"
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||||||
import { Skeleton } from "@/components/ui/skeleton"
|
import { Skeleton } from "@/components/ui/skeleton"
|
||||||
import { RepoJobsTable } from "../components/repoJobsTable"
|
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"
|
||||||
import { SINGLE_TENANT_ORG_DOMAIN } from "@/lib/constants"
|
import { SINGLE_TENANT_ORG_DOMAIN } from "@/lib/constants"
|
||||||
import { sew } from "@/actions"
|
|
||||||
import { withOptionalAuthV2 } from "@/withAuthV2"
|
|
||||||
import { ServiceErrorException } from "@/lib/serviceError"
|
import { ServiceErrorException } from "@/lib/serviceError"
|
||||||
import { cn, getCodeHostInfoForRepo, isServiceError } from "@/lib/utils"
|
import { cn, getCodeHostInfoForRepo, isServiceError } from "@/lib/utils"
|
||||||
|
import { withOptionalAuthV2 } from "@/withAuthV2"
|
||||||
|
import { ChevronLeft, ExternalLink, Info } from "lucide-react"
|
||||||
import Image from "next/image"
|
import Image from "next/image"
|
||||||
|
import Link from "next/link"
|
||||||
|
import { notFound } from "next/navigation"
|
||||||
|
import { Suspense } from "react"
|
||||||
|
import { RepoJobsTable } from "../components/repoJobsTable"
|
||||||
|
import { getConfigSettings } from "@sourcebot/shared"
|
||||||
|
import { env } from "@/env.mjs"
|
||||||
|
|
||||||
function formatDate(date: Date | null) {
|
function formatDate(date: Date | null) {
|
||||||
if (!date) return "Never"
|
if (!date) return "Never"
|
||||||
|
|
@ -39,6 +42,21 @@ export default async function RepoDetailPage({ params }: { params: Promise<{ id:
|
||||||
webUrl: repo.webUrl ?? undefined,
|
webUrl: repo.webUrl ?? undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const configSettings = await getConfigSettings(env.CONFIG_PATH);
|
||||||
|
|
||||||
|
const nextIndexAttempt = (() => {
|
||||||
|
const latestJob = repo.jobs.length > 0 ? repo.jobs[0] : null;
|
||||||
|
if (!latestJob) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (latestJob.completedAt) {
|
||||||
|
return new Date(latestJob.completedAt.getTime() + configSettings.reindexIntervalMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
})();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container mx-auto">
|
<div className="container mx-auto">
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
|
|
@ -78,16 +96,17 @@ export default async function RepoDetailPage({ params }: { params: Promise<{ id:
|
||||||
<div className="grid gap-4 md:grid-cols-3 mb-8">
|
<div className="grid gap-4 md:grid-cols-3 mb-8">
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader className="pb-3">
|
<CardHeader className="pb-3">
|
||||||
<CardTitle className="text-sm font-medium">Last Indexed</CardTitle>
|
<CardTitle className="text-sm font-medium flex items-center gap-1.5">
|
||||||
</CardHeader>
|
Created
|
||||||
<CardContent>
|
<Tooltip>
|
||||||
<div className="text-2xl font-semibold">{repo.indexedAt ? formatDate(repo.indexedAt) : "Never"}</div>
|
<TooltipTrigger asChild>
|
||||||
</CardContent>
|
<Info className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
|
||||||
</Card>
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
<Card>
|
<p>When this repository was first added to Sourcebot</p>
|
||||||
<CardHeader className="pb-3">
|
</TooltipContent>
|
||||||
<CardTitle className="text-sm font-medium">Created</CardTitle>
|
</Tooltip>
|
||||||
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="text-2xl font-semibold">{formatDate(repo.createdAt)}</div>
|
<div className="text-2xl font-semibold">{formatDate(repo.createdAt)}</div>
|
||||||
|
|
@ -96,10 +115,39 @@ export default async function RepoDetailPage({ params }: { params: Promise<{ id:
|
||||||
|
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader className="pb-3">
|
<CardHeader className="pb-3">
|
||||||
<CardTitle className="text-sm font-medium">Last Updated</CardTitle>
|
<CardTitle className="text-sm font-medium flex items-center gap-1.5">
|
||||||
|
Last indexed
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Info className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
|
<p>The last time this repository was successfully indexed</p>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="text-2xl font-semibold">{formatDate(repo.updatedAt)}</div>
|
<div className="text-2xl font-semibold">{repo.indexedAt ? formatDate(repo.indexedAt) : "Never"}</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="pb-3">
|
||||||
|
<CardTitle className="text-sm font-medium flex items-center gap-1.5">
|
||||||
|
Scheduled
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Info className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
|
<p>When the next indexing job is scheduled to run</p>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-semibold">{nextIndexAttempt ? formatDate(nextIndexAttempt) : "-"}</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -127,8 +175,12 @@ const getRepoWithJobs = async (repoId: number) => sew(() =>
|
||||||
id: repoId,
|
id: repoId,
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
jobs: true,
|
jobs: {
|
||||||
|
orderBy: {
|
||||||
|
createdAt: 'desc'
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!repo) {
|
if (!repo) {
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,13 @@ import {
|
||||||
useReactTable,
|
useReactTable,
|
||||||
} from "@tanstack/react-table"
|
} from "@tanstack/react-table"
|
||||||
import { cva } from "class-variance-authority"
|
import { cva } from "class-variance-authority"
|
||||||
import { AlertCircle, ArrowUpDown } from "lucide-react"
|
import { AlertCircle, ArrowUpDown, RefreshCwIcon } from "lucide-react"
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import { CopyIconButton } from "../../components/copyIconButton"
|
import { CopyIconButton } from "../../components/copyIconButton"
|
||||||
import { useMemo } from "react"
|
import { useMemo } from "react"
|
||||||
|
import { LightweightCodeHighlighter } from "../../components/lightweightCodeHighlighter"
|
||||||
|
import { useRouter } from "next/navigation"
|
||||||
|
import { useToast } from "@/components/hooks/use-toast"
|
||||||
|
|
||||||
// @see: https://v0.app/chat/repo-indexing-status-uhjdDim8OUS
|
// @see: https://v0.app/chat/repo-indexing-status-uhjdDim8OUS
|
||||||
|
|
||||||
|
|
@ -107,8 +110,14 @@ export const columns: ColumnDef<RepoIndexingJob>[] = [
|
||||||
<TooltipTrigger>
|
<TooltipTrigger>
|
||||||
<AlertCircle className="h-4 w-4 text-destructive" />
|
<AlertCircle className="h-4 w-4 text-destructive" />
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent className="max-w-sm">
|
<TooltipContent className="max-w-[750px] max-h-96 overflow-scroll">
|
||||||
<p className="text-sm">{job.errorMessage}</p>
|
<LightweightCodeHighlighter
|
||||||
|
language="text"
|
||||||
|
lineNumbers={true}
|
||||||
|
renderWhitespace={false}
|
||||||
|
>
|
||||||
|
{job.errorMessage}
|
||||||
|
</LightweightCodeHighlighter>
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
|
|
@ -174,6 +183,8 @@ export const RepoJobsTable = ({ data }: { data: RepoIndexingJob[] }) => {
|
||||||
const [sorting, setSorting] = React.useState<SortingState>([{ id: "createdAt", desc: true }])
|
const [sorting, setSorting] = React.useState<SortingState>([{ id: "createdAt", desc: true }])
|
||||||
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([])
|
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([])
|
||||||
const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>({})
|
const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>({})
|
||||||
|
const router = useRouter();
|
||||||
|
const { toast } = useToast();
|
||||||
|
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data,
|
data,
|
||||||
|
|
@ -238,6 +249,20 @@ export const RepoJobsTable = ({ data }: { data: RepoIndexingJob[] }) => {
|
||||||
<SelectItem value="CLEANUP">Cleanup</SelectItem>
|
<SelectItem value="CLEANUP">Cleanup</SelectItem>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
className="ml-auto"
|
||||||
|
onClick={() => {
|
||||||
|
router.refresh();
|
||||||
|
toast({
|
||||||
|
description: "Page refreshed",
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<RefreshCwIcon className="w-3 h-3" />
|
||||||
|
Refresh
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="rounded-md border">
|
<div className="rounded-md border">
|
||||||
|
|
|
||||||
|
|
@ -28,11 +28,13 @@ import {
|
||||||
useReactTable,
|
useReactTable,
|
||||||
} from "@tanstack/react-table"
|
} from "@tanstack/react-table"
|
||||||
import { cva } from "class-variance-authority"
|
import { cva } from "class-variance-authority"
|
||||||
import { ArrowUpDown, ExternalLink, MoreHorizontal } from "lucide-react"
|
import { ArrowUpDown, ExternalLink, MoreHorizontal, RefreshCwIcon } from "lucide-react"
|
||||||
import Image from "next/image"
|
import Image from "next/image"
|
||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import { useMemo, useState } from "react"
|
import { useMemo, useState } from "react"
|
||||||
import { getBrowsePath } from "../../browse/hooks/utils"
|
import { getBrowsePath } from "../../browse/hooks/utils"
|
||||||
|
import { useRouter } from "next/navigation"
|
||||||
|
import { useToast } from "@/components/hooks/use-toast";
|
||||||
|
|
||||||
// @see: https://v0.app/chat/repo-indexing-status-uhjdDim8OUS
|
// @see: https://v0.app/chat/repo-indexing-status-uhjdDim8OUS
|
||||||
|
|
||||||
|
|
@ -193,6 +195,8 @@ export const ReposTable = ({ data }: { data: Repo[] }) => {
|
||||||
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])
|
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])
|
||||||
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({})
|
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({})
|
||||||
const [rowSelection, setRowSelection] = useState({})
|
const [rowSelection, setRowSelection] = useState({})
|
||||||
|
const router = useRouter();
|
||||||
|
const { toast } = useToast();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
numCompleted,
|
numCompleted,
|
||||||
|
|
@ -256,6 +260,19 @@ export const ReposTable = ({ data }: { data: Repo[] }) => {
|
||||||
<SelectItem value="null">No status ({numNoJobs})</SelectItem>
|
<SelectItem value="null">No status ({numNoJobs})</SelectItem>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
className="ml-auto"
|
||||||
|
onClick={() => {
|
||||||
|
router.refresh();
|
||||||
|
toast({
|
||||||
|
description: "Page refreshed",
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<RefreshCwIcon className="w-3 h-3" />
|
||||||
|
Refresh
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<div className="rounded-md border">
|
<div className="rounded-md border">
|
||||||
<Table>
|
<Table>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue