import type { Metadata } from 'next'; import Link from 'next/link'; import { PageHeader, Section, Note } from '@/components/ui/section'; import { EmptyState } from '@/components/ui/empty-state'; import { Badge, StatusBadge } from '@/components/ui/badge'; import { connectorStates, recentIngests } from '@/lib/queries/pulse'; import { fmtDate, fmtDateTime, fmtDuration, fmtInt, humanize, relativeTime } from '@/lib/format'; export const metadata: Metadata = { title: 'Data update log', description: 'Every connector run of the last 60 days with records created, updated and rejected, dataset versions, and the health and last successful import of each source.' }; export const revalidate = 600; /** Stale = an active scheduled connector without a success in the last 14 days (the worker uses 2× its interval; 14 days is the display rule here). */ const STALE_DAYS = 14; export default async function DataUpdatesPage() { const [runs, states] = await Promise.all([recentIngests(60, 400), connectorStates()]); const byDay = new Map(); for (const r of runs) { const d = String(r.started_at).slice(0, 10); byDay.set(d, [...(byDay.get(d) ?? []), r]); } const now = Date.now(); return (
{states.map((s) => { const stale = s.status === 'active' && !!s.schedule && (!s.last_success_at || now - new Date(s.last_success_at).getTime() > STALE_DAYS * 86_400_000); return ( ); })}
Source Category Status Health Last successful import Schedule Dataset version Source records
{s.source_name ?? s.connector_id} {humanize(s.category)} {s.paused ? paused : null} {stale ? ( stale ) : null} {s.last_success_at ? `${fmtDate(s.last_success_at)} (${relativeTime(s.last_success_at)})` : never} {s.schedule ?? '—'} {s.last_dataset_version ?? '—'} {fmtInt(s.record_count)}
{runs.length ? (
{[...byDay.entries()].map(([day, rows]) => (

{fmtDate(day)}

{rows.map((r) => ( ))}
Started Source Mode Status Fetched Created Updated Unchanged Rejected Duration Dataset version Anomaly
{fmtDateTime(r.started_at)} {r.source_name ?? r.connector_id} {r.mode} {fmtInt(r.records_fetched)} {fmtInt(r.records_created)} {fmtInt(r.records_updated)} {fmtInt(r.records_unchanged)} 0 ? 'text-warn' : ''}`}>{fmtInt(r.records_rejected)} {fmtDuration(r.duration_ms)} {r.dataset_version ?? '—'} {r.anomaly ?? ''}
))}
) : ( )}
Run identifiers are `ING-<CONNECTOR>-YYYYMMDD-nnnnnn`; operators can open a run on the admin console. Derived layers (counters, intelligence, rankings) are recomputed after every run that changed records, then daily at 06:00, 06:15 and 06:30 UTC.
); }