"use client"; import Link from "next/link"; import { useEffect, useMemo, useState } from "react"; import { PAGE_TYPES } from "@dci/core"; import { Badge, EmptyState, RelativeTime, SearchInput, SkeletonRows, Table, TBody, Td, Th, THead, Tr } from "@/components/ui"; import { cn } from "@/components/ui/cn"; import { DASH, fmtInt } from "@/lib/format"; import type { AdminDocument, ConnectorHealthDTO } from "@/lib/admin-api"; import { ErrorNote, fmtBytes, LevelBadge, Pager, RefreshButton, Segmented, Select } from "./primitives"; import { AdminPageHeader } from "./shell"; import { useAdminQuery } from "./use-admin-query"; import { useUrlState } from "./use-url-state"; const STATUS = ["all", "error", "changed", "quarantined"] as const; type Status = (typeof STATUS)[number]; const PER_PAGE = 50; export function DocumentsTable() { const [params, setParams] = useUrlState(); const connector = params.connector ?? ""; const pageType = params.pageType ?? ""; const status = (STATUS.includes(params.status as Status) ? params.status : "all") as Status; const page = Math.max(1, Number(params.page ?? 1) || 1); const [search, setSearch] = useState(params.q ?? ""); useEffect(() => { const t = setTimeout(() => { if ((params.q ?? "") !== search) setParams({ q: search || null, page: null }); }, 350); return () => clearTimeout(t); }, [search, params.q, setParams]); const connectors = useAdminQuery("connectors", { timeoutMs: 30_000 }); const q = useAdminQuery("documents", { query: { connector: connector || undefined, pageType: pageType || undefined, status: status === "all" ? undefined : status, q: params.q || undefined, page, per_page: PER_PAGE }, refreshMs: 60_000 }); const total = Number(q.meta?.total ?? 0); const connectorIds = useMemo(() => (connectors.data ?? []).map((c) => c.id).sort(), [connectors.data]); return (
void q.refresh()} busy={q.refreshing} updatedAt={q.updatedAt} />} /> void q.refresh()} className="mb-3" />
setParams({ status: v === "all" ? null : v, page: null })} options={STATUS.map((s) => ({ value: s, label: s === "all" ? "All" : s[0]!.toUpperCase() + s.slice(1) }))} />
{q.loading && !q.data ? ( ) : !q.data || q.data.length === 0 ? ( ) : (
{q.data.map((d) => ( ))}
URL Connector Page type Lvl HTTP Last fetched Last changed Changes Extract Size
{d.url.replace(/^https?:\/\//, "")}
{d.title ?? d.id} {d.quarantined && ( quarantined )} {d.error && ( {d.error} )}
{d.connectorId} {d.pageType} = 400 && "text-danger")}> {d.statusCode ?? DASH} {fmtInt(d.changeCount)} / {fmtInt(d.fetchCount)} {d.extractOk == null ? ( {DASH} ) : d.extractOk ? ( ok {fmtInt(d.extractCount)} ) : ( failed{d.errorCount ? ×{d.errorCount} : null} )} {fmtBytes(d.sizeBytes)}
setParams({ page: p === 1 ? null : p })} />
)}
); }