feat(CC-069): add Dataset Registry page (system + user datasets, links to data sources)
This commit is contained in:
parent
176850458a
commit
418957676c
1 changed files with 124 additions and 0 deletions
124
src/app/dashboard/data/registry/page.tsx
Normal file
124
src/app/dashboard/data/registry/page.tsx
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
'use client';
|
||||
|
||||
import Link from 'next/link';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { apiFetch } from '../../../../lib/api';
|
||||
import { useSession } from '../../../../components/session-provider';
|
||||
|
||||
interface DataSource { id: string; name: string; sourceType: string; description: string | null; status: string; lastSyncAt: string | null; recordCount: number | null; createdAt: string; }
|
||||
|
||||
const TYPE_ICON: Record<string, string> = {
|
||||
manual: '✋', api: '🔌', file: '📄', database: '🗄️', integration: '🔗', clickhouse: '🏢', sheet: '📊',
|
||||
};
|
||||
|
||||
const SYSTEM_DATASETS = [
|
||||
{ name: 'ClickHouse — manual_ingest.people_data', type: 'clickhouse', records: '147M+', status: 'active', desc: 'Date persoane din ingestie manuală (C3 — restricționat)' },
|
||||
{ name: 'ClickHouse — boardmind schema', type: 'clickhouse', records: 'live', status: 'active', desc: 'Toate tabelele PostgreSQL CEO OS (via MCP)' },
|
||||
{ name: 'AnythingLLM — workspace agents', type: 'integration', records: '10 workspace-uri', status: 'active', desc: 'Agenți date peste ClickHouse la supersrv:3010' },
|
||||
];
|
||||
|
||||
export default function DataRegistryPage() {
|
||||
const { activeTenant } = useSession();
|
||||
const tenantId = activeTenant?.tenantId ?? '';
|
||||
|
||||
const { data: userSources = [], isLoading } = useQuery({
|
||||
queryKey: ['data-sources', tenantId],
|
||||
queryFn: () => apiFetch<DataSource[]>('/v1/data-sources', { tenantId }),
|
||||
enabled: Boolean(tenantId), staleTime: 120_000,
|
||||
});
|
||||
|
||||
const totalUserRecords = userSources.reduce((s, ds) => s + (ds.recordCount ?? 0), 0);
|
||||
const activeUser = userSources.filter((ds) => ds.status === 'active').length;
|
||||
|
||||
return (
|
||||
<div className="max-w-4xl space-y-6 p-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="font-display text-2xl font-semibold text-ink">Registru Dataset</h1>
|
||||
<p className="text-sm text-ink-faint mt-1">
|
||||
{isLoading ? 'Se încarcă…' : `${SYSTEM_DATASETS.length} sistem · ${userSources.length} personalizate · ${activeUser} active`}
|
||||
</p>
|
||||
</div>
|
||||
<Link href="/dashboard/data/sources" className="text-xs text-bronze-deep hover:underline">
|
||||
Gestionează surse →
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* System datasets */}
|
||||
<div className="space-y-3">
|
||||
<h2 className="text-xs font-semibold uppercase tracking-wider text-ink-faint">Dataset-uri sistem</h2>
|
||||
<div className="card divide-y divide-border/50">
|
||||
{SYSTEM_DATASETS.map((ds) => (
|
||||
<div key={ds.name} className="flex items-start gap-4 p-4">
|
||||
<span className="text-xl shrink-0 mt-0.5">{TYPE_ICON[ds.type] ?? '❓'}</span>
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-sm font-medium text-ink font-mono truncate">{ds.name}</p>
|
||||
<p className="text-xs text-ink-faint mt-0.5">{ds.desc}</p>
|
||||
</div>
|
||||
<div className="text-right shrink-0">
|
||||
<p className="text-sm font-mono font-bold text-ink">{ds.records}</p>
|
||||
<span className="text-[10px] text-signal-ok">● activ</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* User-registered datasets */}
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-xs font-semibold uppercase tracking-wider text-ink-faint">Dataset-uri personalizate</h2>
|
||||
{totalUserRecords > 0 && (
|
||||
<span className="text-xs text-ink-faint font-mono">{totalUserRecords.toLocaleString('ro-RO')} înregistrări totale</span>
|
||||
)}
|
||||
</div>
|
||||
{isLoading ? (
|
||||
<div className="card p-8 text-center text-sm text-ink-faint">Se încarcă…</div>
|
||||
) : userSources.length === 0 ? (
|
||||
<div className="card p-8 text-center space-y-2">
|
||||
<p className="text-sm text-ink-faint">Niciun dataset personalizat înregistrat.</p>
|
||||
<Link href="/dashboard/data/sources" className="text-xs text-bronze-deep hover:underline">
|
||||
Adaugă prima sursă de date →
|
||||
</Link>
|
||||
</div>
|
||||
) : (
|
||||
<div className="card divide-y divide-border/50">
|
||||
{userSources.map((ds) => (
|
||||
<div key={ds.id} className="flex items-start gap-4 p-4">
|
||||
<span className="text-xl shrink-0 mt-0.5">{TYPE_ICON[ds.sourceType] ?? '❓'}</span>
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-sm font-medium text-ink truncate">{ds.name}</p>
|
||||
{ds.description && <p className="text-xs text-ink-faint mt-0.5">{ds.description}</p>}
|
||||
{ds.lastSyncAt && (
|
||||
<p className="text-[10px] text-ink-faint mt-0.5">
|
||||
Sync: {new Date(ds.lastSyncAt).toLocaleDateString('ro-RO')}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="text-right shrink-0">
|
||||
{ds.recordCount != null ? (
|
||||
<p className="text-sm font-mono font-bold text-ink">{ds.recordCount.toLocaleString('ro-RO')}</p>
|
||||
) : (
|
||||
<p className="text-xs text-ink-faint">—</p>
|
||||
)}
|
||||
<span className={`text-[10px] ${ds.status === 'active' ? 'text-signal-ok' : 'text-ink-faint'}`}>
|
||||
● {ds.status}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Info note */}
|
||||
<div className="rounded-lg border border-border/50 bg-muted/30 p-4">
|
||||
<p className="text-xs text-ink-faint leading-relaxed">
|
||||
<strong className="text-ink">Arhitectură date:</strong> CEO OS funcționează cu date din ClickHouse (147M+ rânduri, procesate prin ingestie),
|
||||
date din PostgreSQL (baza CEO OS), și surse externe configurate manual.
|
||||
Agenții AnythingLLM pot interoga ClickHouse prin MCP direct.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in a new issue