"use client" import { DisplayDate } from "@/app/[domain]/components/DisplayDate" import { NotificationDot } from "@/app/[domain]/components/notificationDot" import { useToast } from "@/components/hooks/use-toast" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table" import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip" import { SINGLE_TENANT_ORG_DOMAIN } from "@/lib/constants" import { getCodeHostIcon } from "@/lib/utils" import { ConnectionType } from "@sourcebot/db" import { type ColumnDef, type ColumnFiltersState, type SortingState, type VisibilityState, flexRender, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable, } from "@tanstack/react-table" import { cva } from "class-variance-authority" import { ArrowUpDown, RefreshCwIcon } from "lucide-react" import Image from "next/image" import Link from "next/link" import { useRouter } from "next/navigation" import { useMemo, useState } from "react" export type Connection = { id: number name: string syncedAt: Date | null connectionType: ConnectionType latestJobStatus: "PENDING" | "IN_PROGRESS" | "COMPLETED" | "FAILED" | null isFirstTimeSync: boolean } const statusBadgeVariants = cva("", { variants: { status: { PENDING: "bg-secondary text-secondary-foreground hover:bg-secondary/80", IN_PROGRESS: "bg-primary text-primary-foreground hover:bg-primary/90", COMPLETED: "bg-green-600 text-white hover:bg-green-700", FAILED: "bg-destructive text-destructive-foreground hover:bg-destructive/90", }, }, }) const getStatusBadge = (status: Connection["latestJobStatus"]) => { if (!status) { return "-"; } const labels = { PENDING: "Pending", IN_PROGRESS: "In Progress", COMPLETED: "Completed", FAILED: "Failed", } return {labels[status]} } export const columns: ColumnDef[] = [ { accessorKey: "name", size: 400, header: ({ column }) => { return ( ) }, cell: ({ row }) => { const connection = row.original; const codeHostIcon = getCodeHostIcon(connection.connectionType); return (
{`${connection.connectionType} {connection.name} {connection.isFirstTimeSync && ( This is the first time Sourcebot is syncing this connection. It may take a few minutes to complete. )}
) }, }, { accessorKey: "latestJobStatus", size: 150, header: "Lastest status", cell: ({ row }) => getStatusBadge(row.getValue("latestJobStatus")), }, { accessorKey: "syncedAt", size: 200, header: ({ column }) => { return ( ) }, cell: ({ row }) => { const syncedAt = row.getValue("syncedAt") as Date | null; if (!syncedAt) { return "-"; } return ( ) } }, ] export const ConnectionsTable = ({ data }: { data: Connection[] }) => { const [sorting, setSorting] = useState([]) const [columnFilters, setColumnFilters] = useState([]) const [columnVisibility, setColumnVisibility] = useState({}) const [rowSelection, setRowSelection] = useState({}) const router = useRouter(); const { toast } = useToast(); const { numCompleted, numInProgress, numPending, numFailed, numNoJobs, } = useMemo(() => { return { numCompleted: data.filter((connection) => connection.latestJobStatus === "COMPLETED").length, numInProgress: data.filter((connection) => connection.latestJobStatus === "IN_PROGRESS").length, numPending: data.filter((connection) => connection.latestJobStatus === "PENDING").length, numFailed: data.filter((connection) => connection.latestJobStatus === "FAILED").length, numNoJobs: data.filter((connection) => connection.latestJobStatus === null).length, } }, [data]); const table = useReactTable({ data, columns, onSortingChange: setSorting, onColumnFiltersChange: setColumnFilters, getCoreRowModel: getCoreRowModel(), getPaginationRowModel: getPaginationRowModel(), getSortedRowModel: getSortedRowModel(), getFilteredRowModel: getFilteredRowModel(), onColumnVisibilityChange: setColumnVisibility, onRowSelectionChange: setRowSelection, columnResizeMode: 'onChange', enableColumnResizing: false, state: { sorting, columnFilters, columnVisibility, rowSelection, }, }) return (
table.getColumn("name")?.setFilterValue(event.target.value)} className="max-w-sm" />
{table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => { return ( {header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())} ) })} ))} {table.getRowModel().rows?.length ? ( table.getRowModel().rows.map((row) => ( {row.getVisibleCells().map((cell) => ( {flexRender(cell.column.columnDef.cell, cell.getContext())} ))} )) ) : ( No results. )}
{table.getFilteredRowModel().rows.length} {data.length > 1 ? 'connections' : 'connection'} total
) }