import Link from 'next/link'; import type { ReactNode } from 'react'; import { RunStatusPill, fmtDuration } from '@/components/meta/connectors-table'; import { cn } from '@/lib/cn'; import { fmtAgo, fmtDateTime, fmtInt, num } from '@/lib/format'; import type { ConnectorRun } from './types'; /** Server-safe admin building blocks: page header, stat tiles, error state, byte formatting, runs table. */ export function fmtBytes(v: number | string | null | undefined): string { const n = num(v); if (n === null) return '—'; if (n < 1024) return `${fmtInt(n)} B`; const units = ['KB', 'MB', 'GB', 'TB']; let x = n / 1024; let i = 0; while (x >= 1024 && i < units.length - 1) { x /= 1024; i++; } return `${x >= 100 ? x.toFixed(0) : x.toFixed(1)} ${units[i]}`; } export function AdminHeader({ title, lede, action }: { title: ReactNode; lede?: ReactNode; action?: ReactNode }) { return (

Admin

{title}

{lede &&

{lede}

}
{action}
); } export function AdminError({ message, what = 'Admin API' }: { message: string; what?: string }) { return (

{what} unavailable

{message}

); } export function Tile({ label, value, hint, tone, href }: { label: string; value: ReactNode; hint?: ReactNode; tone?: 'ok' | 'warn' | 'danger'; href?: string }) { const color = tone === 'ok' ? 'text-active' : tone === 'warn' ? 'text-warn' : tone === 'danger' ? 'text-danger' : ''; const body = ( <>

{label}

{value}

{hint &&

{hint}

} ); return href ? ( {body} ) : (
{body}
); } export function SectionTitle({ children, action }: { children: ReactNode; action?: ReactNode }) { return (

{children}

{action}
); } export function RunsTable({ runs, now = Date.now(), showConnector = true, emptyLabel = 'No runs recorded' }: { runs: ConnectorRun[]; now?: number; showConnector?: boolean; emptyLabel?: string }) { if (runs.length === 0) return

{emptyLabel}

; return (
{showConnector && } {runs.map((r) => ( {showConnector && ( )} ))}
ConnectorStarted Status Duration Fetched Created Updated Error
{r.connector_name} {fmtAgo(r.started_at, now)} {fmtDateTime(r.started_at)} {fmtDuration(r.duration_ms)} {fmtInt(r.records_fetched)} {fmtInt(r.records_created)} {fmtInt(r.records_updated)} {r.error ? ( {r.error} ) : ( — )}
); } /** Small mono JSON preview (config, run meta) — scrolls instead of overflowing. */ export function JsonInline({ value, className }: { value: unknown; className?: string }) { if (value === null || value === undefined) return —; return {JSON.stringify(value)}; }